-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbc_client.py
More file actions
219 lines (178 loc) · 7.79 KB
/
bc_client.py
File metadata and controls
219 lines (178 loc) · 7.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
import logging
import grpc
import grpc_utils.blockchain_pb2 as blockchain_pb2
import grpc_utils.blockchain_pb2_grpc as blockchain_pb2_grpc
class bc_Miner:
def __init__(self, minerIndex):
self.port_list = []
self.miner_index = minerIndex
self.localPort = ''
self.latestBlockIndex = 1
self.localBlockIndex = 0
# self.initMiner()
def run(self):
# initialize bc_server
self.initMiner()
# Reload data from DB
self.QueryDB()
local_channel = grpc.insecure_channel('localhost:' + self.localPort)
response = self.sendMessage(local_channel, 'Local index')
self.localBlockIndex = int(response.message)
self.latestBlockIndex = self.localBlockIndex
def initMiner(self):
f = open("portList.txt")
line = f.readline()
while line:
self.port_list.append(line.replace('\n', ''))
line = f.readline()
f.close()
# update server side miner_index
local_port = self.port_list[self.miner_index]
local_channel = grpc.insecure_channel('localhost:' + local_port)
stub = blockchain_pb2_grpc.BlockChainStub(local_channel)
response = stub.getState(blockchain_pb2.getStateRequest(message=self.miner_index))
print(response)
self.localPort = self.port_list[self.miner_index]
def QueryDB(self):
local_channel = grpc.insecure_channel('localhost:' + self.localPort)
stub = blockchain_pb2_grpc.BlockChainStub(local_channel)
response = stub.QueryDB(blockchain_pb2.QueryDBRequest(message='Read blockchain from DB'))
print("Query DB result:", response)
def getLatestBlockIdx(self):
index_list = self.broadcastMsg("Highest Index")
# print("Live miner's latest block index", index_list)
for idx in index_list:
if int(idx.message) <= self.latestBlockIndex:
continue
else:
self.latestBlockIndex = int(idx.message)
print("The highest index is:", idx.message)
def broadcastMsg(self, message):
channel_list = self.getAliveChannel(self.port_list)
response_list = []
for c in channel_list:
try:
response = self.sendMessage(c, message)
response_list.append(response)
except Exception as e:
print("broadcastMsg err", e)
return response_list
def mining(self):
# main procedure of block mining
nonce = 0
while 1 == 1:
if self.isMining():
# check whether the miner should mine or synchronize
print("Start mining")
self.mineBlock(nonce)
nonce += 1
else:
print(f"Getting block {self.localBlockIndex}")
self.getBlock(self.localBlockIndex)
self.getLatestBlockIdx()
def isMining(self):
# check whether the mining should start mining
local_channel = grpc.insecure_channel('localhost:' + self.localPort)
response = self.sendMessage(local_channel, 'Local index')
self.localBlockIndex = int(response.message)
self.getLatestBlockIdx()
print("Local latest block index:", self.localBlockIndex)
print("Network latest block index:", self.latestBlockIndex)
if self.localBlockIndex < self.latestBlockIndex:
# query next block
return False
else:
# start mining
return True
def mineBlock(self, nonce):
local_channel = grpc.insecure_channel('localhost:' + self.localPort)
stub = blockchain_pb2_grpc.BlockChainStub(local_channel)
# initialize coinbase tx
initTX = stub.initTxList(blockchain_pb2.InitTxListRequest(message="init transaction"))
# print(initTX.message)
tran_msg = f"This block was added by client {self.miner_index}."
response = stub.addNewBlock(blockchain_pb2.AddBlockRequest(transaction=tran_msg, nonce=nonce))
# print("trying nonce:", nonce)
if response.hash == "Restart":
nonce = 0
elif response.hash != 'False':
print("Add the block successfully. The nonce is " + str(nonce))
print("New block address: " + response.hash)
initTX = stub.initTxList(blockchain_pb2.InitTxListRequest(message="init transaction"))
print(initTX.message)
self.broadcastBlock(response.newBlock)
# if mined a block, reset nonce
nonce = 0
def sendMessage(self, channel, message):
stub = blockchain_pb2_grpc.BlockChainStub(channel)
response = stub.receiveMessage(blockchain_pb2.receiveMessageRequest(message=message))
return response
def broadcastBlock(self, block):
channel_list = self.getAliveChannel(self.port_list)
for c in channel_list:
try:
self.sendBlock(c, block)
except Exception as e:
print("broadcastBlock err: ", e)
def sendBlock(self, channel, block):
stub = blockchain_pb2_grpc.BlockChainStub(channel)
tran_msg = f"{self.miner_index} find a new Block!"
response = stub.receiveBlock(blockchain_pb2.ReceiveBlockRequest(message=tran_msg, newBlock=block))
print(response)
def getAliveChannel(self, port_list):
channel_list = []
alive_miner = []
for i, p in enumerate(port_list):
if i == self.miner_index:
continue
channel = grpc.insecure_channel('localhost:' + p)
try:
grpc.channel_ready_future(channel).result(timeout=0.1)
except:
result = f"channel:{p} connect timeout"
else:
result = f"channel:{p} connect success"
channel_list.append(channel)
alive_miner.append(i)
print(f"Miner {alive_miner} are alive")
return channel_list
def getUTXOs(self):
local_channel = grpc.insecure_channel('localhost:' + self.localPort)
stub = blockchain_pb2_grpc.BlockChainStub(local_channel)
response = stub.getUTXOs(blockchain_pb2.getUTXOsRequest(message="get UTXOs"))
return response
def broadcastNewTransaction(self, transaction, receiver_port):
channel = grpc.insecure_channel('localhost:' + receiver_port)
localChannel = grpc.insecure_channel('localhost:' + self.localPort)
localStub = blockchain_pb2_grpc.BlockChainStub(localChannel)
channel_list = [channel]
successAdd = 0
for c in channel_list:
stub = blockchain_pb2_grpc.BlockChainStub(c)
if stub.addNewTransaction(
blockchain_pb2.addNewTransactionRequest(addnew=transaction)) == 'add NewTransaction success!':
successAdd += 1
if successAdd > 0:
localStub.addNewTransaction(blockchain_pb2.addNewTransactionRequest(addnew=transaction))
def getBlock(self, block_index):
# get block message from other miner
msg = f"Get Block:{block_index}"
response_list = self.broadcastMsg(msg)
# print("block response list", response_list)
required_block = response_list[0].newBlock
# add block into local blockchain
local_channel = grpc.insecure_channel('localhost:' + self.localPort)
try:
self.sendBlock(local_channel, required_block)
except:
print("Error get block")
def getBlockInfo(self, block_index):
msg = f"Get Block:{block_index}"
local_channel = grpc.insecure_channel('localhost:' + self.localPort)
response = self.sendMessage(local_channel, msg)
return response
if __name__ == '__main__':
logging.basicConfig()
miner = bc_Miner(0)
miner.initMiner()
miner.mining()