def on_new_block_received(self, block): print('block receiced') block = Block.unpack(block) if self.add_block(block): print('try to stop current miner') self.stop_miner() # stop current miner self.prev_hash = block.hash self.peer.sendall_block(msgtype=MsgType.TYPE_NEW_BLOCK, content=block.b) print('try to start a new miner') self.start_miner() # start a new miner
def make_block(self, nonce) -> Block: trans = self.__get_trans() info = Attachment() info.add_data(b'mined by ' + self.name.encode()) info.ready() block = Block( 0, # todo: get index timestamp=time.time(), blockdata=BlockData(trans, info), previous_hash=self.prev_hash, nonce=nonce) return block
def handle(self): flag = 0 # print(BlockchainMixin.state) while True: header = self.request.recv(LENGTH_HEADER) if len(header) == 0: # self.handler_log.debug('pid {0} Round end: {1}'.format(os.getpid(), time.time())) # print('pid {0} Round end: {1}'.format(os.getpid(), time.time())) break if flag == 0: # self.handler_log.debug('pid {0} Round start: {1}'.format(os.getpid(), time.time())) # print('pid {0} Round start: {1}'.format(os.getpid(), time.time())) flag = 1 typ = header[4:8] len_h = struct.unpack('=i', header[:4])[0] content = bytes() '''Just receive all the content''' l = 0 while l < len_h: piece = self.request.recv(min(PIECE, len_h - l)) content += piece l += len(piece) '''Check whether the block content has been received (hash or keyword IN) if so, continue the loop''' # print('received from: ', self.request.getpeername()) '''PBFT state machine''' if BlockchainMixin.state is StatePBFT.IDLE: if typ == TYPE_TRANS: # keep receiving trans until reach the limitation BlockchainMixin.lock.acquire() BlockchainMixin.trans.append(Transaction.unpack(content)) BlockchainMixin.lock.release() if len(BlockchainMixin.trans ) == BlockchainMixin.trans_limit: # prepare a block at = Attachment() at.add_data(b'') at.ready() bd = BlockData(BlockchainMixin.trans, at) block = Block( BlockchainMixin.chain.chain[-1].index + 1, time.time(), bd, BlockchainMixin.chain.chain[-1].hash) msg = BlockchainMixin.pre_prepare_msg( BlockchainMixin.view, BlockchainMixin.n_request, block.b) BlockchainMixin.n_request += 1 BlockchainMixin.state = StatePBFT.PREPARE BlockchainMixin.temp_block.append(block.b) for ip, port in BlockchainMixin.connection: if (ip, port) == self.request.getpeername(): continue BlockchainMixin.pool.apply_async( self.sends, ((ip, port), msg)) BlockchainMixin.trans.clear() elif typ == TYPE_PRE_PREPARE: # cache the block and response with PREPARE message BlockchainMixin.lock.acquire() # print('content', content) BlockchainMixin.temp_block.append(content) BlockchainMixin.state = StatePBFT.PREPARE BlockchainMixin.lock.release() msg = BlockchainMixin.prepare_msg( BlockchainMixin.view, BlockchainMixin.num_nodes, BlockchainMixin.index, content) for ip, port in BlockchainMixin.connection: BlockchainMixin.pool.apply_async( self.sends, ((ip, port), msg)) elif BlockchainMixin.state is StatePBFT.PREPARE: if typ == TYPE_PREPARE or typ == TYPE_COMMIT: BlockchainMixin.lock.acquire() BlockchainMixin.state = StatePBFT.COMMIT BlockchainMixin.lock.release() msg = BlockchainMixin.commit_msg(BlockchainMixin.view, BlockchainMixin.num_nodes, BlockchainMixin.index, content) for ip, port in BlockchainMixin.connection: BlockchainMixin.pool.apply_async( self.sends, ((ip, port), msg)) elif BlockchainMixin.state is StatePBFT.COMMIT: if typ == TYPE_COMMIT: BlockchainMixin.lock.acquire() BlockchainMixin.state = StatePBFT.REPLY BlockchainMixin.chain.add_block( Block.unpack(BlockchainMixin.temp_block[0])) BlockchainMixin.temp_block.clear() BlockchainMixin.lock.release() msg = BlockchainMixin.commit_msg(BlockchainMixin.view, BlockchainMixin.num_nodes, BlockchainMixin.index, content) for ip, port in BlockchainMixin.connection: BlockchainMixin.pool.apply_async( self.sends, ((ip, port), msg)) mm = '%f' % time.time() print(mm) with open('logs/srv' + str(BlockchainMixin.index) + '.txt', 'w') as logfile: logfile.writelines([mm]) elif BlockchainMixin.state is StatePBFT.REPLY: pass
def test_001_block_write(self): """ use the same case as the test_000_trans_write, but transactions are seperated into different blocks :return: """ # replace the following connection address with the address in the chainbase tinput = [( b'O\x1e,-\xe1\xa0!\x16D\x87\xcc\x923\xf7\xf6\xca\xad\xd1\t\x8eV\xdc\xe8t}N\xfa\x8af\xbe\xe7\xef', 0)] private_key1 = load_pem_private_key( b'-----BEGIN PRIVATE KEY-----\nMIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0w' b'awIBAQQg64DiDBUkuGC5rrTfH6uy\nHt6vhvHrMHj3Gm64SZtdqtKhRANCAATMIea' b'IK4vT0ni00F6GGW40qioinPFgXjsj\n6sZGivW9Ipj+zcDfPc7RxZuFeKFmbtVaUX' b'Z877DM4C8ELZs2DPVQ\n-----END PRIVATE KEY-----\n', None, default_backend()) public_key = b'-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEzCHmiCuL09J4tNBehhluNKoqIpzx' \ b'YF47\nI+rGRor1vSKY/s3A3z3O0cWbhXihZm7VWlF2fO+wzOAvBC2bNgz1UA==\n-----END PUBLIC KEY-----\n' sha = hashlib.sha256() sha.update(public_key) public_key_hash = sha.digest() T1 = TransInput(tinput, public_key_hash) public_key_hash = [] private_keys = [] public_keys = [] for i in range(6): private_key = ec.generate_private_key(ec.SECP256K1, default_backend()) private_keys.append(private_key) public_key = private_key.public_key() public_key = public_key.public_bytes( Encoding.PEM, PublicFormat.SubjectPublicKeyInfo) public_keys.append(public_key) sha = hashlib.sha256() sha.update(public_key) public_key_hash.append(sha.digest()) toutput = [(7, public_key_hash[i]) for i in range(6)] T2 = TransOutput(toutput) T = Transaction(T1, T2) T.ready(private_key1) pri_key = private_keys[0] public_key_hash1 = public_key_hash[0] T8 = TransInput([(T.txid, 0)], public_key_hash1) toutput = [(7, public_key_hash[1])] T9 = TransOutput(toutput) T4 = Transaction(T8, T9) T4.ready(pri_key) at = Attachment() at.add_data(b'') at.ready() bd = BlockData([T, T4], at) t = time.time() block = Block( 1, t, bd, b'G\xfdk\x88\xda5\xff\x8c\x97t\x9f\xcb\xe0\xa8\x07S\x8b9t:.9\x1d\xee\xf4\xb1\xda\xd1r\xaf\xfcu', 33) """ construct a second valid transaction, which pay 7 from random address 1 to random address 2 """ with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM ) as s: # submit the second valid transaction s.connect(self.address) payload = send_handler(MsgType.TYPE_BLOCK_WRITE, block.b) s.sendall(payload) header, length, msgtype, content = recv_parser(s) self.assertEqual(content, b'') self.assertEqual(length, 0) self.assertEqual( msgtype, MsgType.TYPE_RESPONSE_OK) # the chainbase returns OK