class ServerCore: def __init__(self, my_port=50082, core_node_host=None, core_node_port=None): self.server_state = STATE_INIT print('Initializing server...') self.my_ip = self.__get_myip() print('Server IP address is set to ... ', self.my_ip) self.my_port = my_port self.cm = ConnectionManager(self.my_ip, self.my_port) self.core_node_host = core_node_host self.core_node_port = core_node_port def start(self): self.server_state = STATE_STANDBY self.cm.start() def join_network(self): if self.core_node_host is not None: self.server_state = STATE_CONNECTED_TO_NETWORK self.cm.join_network(self.core_node_host, self.core_node_port) else: print('This server is runnning as Genesis Core Node...') def shutdown(self): self.server_state = STATE_SHUTTING_DOWN print('Shutdown server...') self.cm.connection_close() def get_my_current_state(self): return self.server_state def __get_myip(self): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) return s.getsockname()[0]
class ServerCore: def __init__(self, my_port=50082, core_node_host=None, core_node_port=None): self.server_state = STATE_INIT print('Initializeing server...') self.my_ip = self.__get_myip() self.my_port = my_port print('Server IP address is set to ...', self.my_ip) print('Server Port is set to ...', self.my_port) self.cm = ConnectionManager(self.my_ip, self.my_port, self.__handle_message) self.core_node_host = core_node_host self.core_node_port = core_node_port self.mpmh = MyProtocolMessageHandler() self.my_protocol_message_store = [] self.bb = BlockBuilder() my_genesis_block = self.bb.generate_genesis_block() self.bm = BlockchainManager(my_genesis_block.to_dict()) self.prev_block_hash = self.bm.get_hash(my_genesis_block.to_dict()) self.tp = TransactionPool() def start(self): self.server_state = STATE_STANDBY self.cm.start() def join_network(self): if self.core_node_host is not None: self.server_state = STATE_CONNECTED_TO_NETWORK self.cm.join_network(self.core_node_host, self.core_node_port) else: print('This server is runnning as Genesis Nore Node...') def shutdown(self): self.server_state = STATE_SHUTTING_DOWN print('Shutdown server...') self.cm.connection_close() def get_my_current_state(self): return self.server_state def __get_myip(self): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) return s.getsockname()[0] def __handle_message(self, msg, is_core, peer=None): """ ConnectionManagerに引き渡すコールバックの中身 """ print('received message!!!!!!!!!!!!!!!!', msg, peer) if peer is not None: print('peer is not None') pass # TODO: 現状はMSG_REQUEST_FULL_CHAINの場合しかこの処理には入らない # とりあえず口だけ作る else: cmd = msg[2] if cmd == MSG_NEW_TRANSACTION: # 送信されてくるデータはバイナリ化したjson文字列とう前提で実装する new_transaction = json.loads(msg[4]) print('received new_transaction', new_transaction) current_transactions = self.tp.get_stored_transactions() if new_transaction in current_transactions: print('this is already pooled transaction:', t) return self.tp.set_new_transaction(new_transaction) if not is_core: new_message = self.cm.get_message_text(MSG_NEW_BLOCK, json.dumps(new_block.to_dict())) self.cm.send_msg_to_all_peer(new_message) elif cmd == MSG_NEW_BLOCK: # TODO: 新規ブロックを検証する処理を呼び出す pass elif cmd == RSP_FULL_CHAIN: # TODO: ブロックチェーン送信要求に応じて返却されたブロックチェーンを検証する処理を呼び出す pass elif cmd == MSG_ENHANCED: print('received enhanced message', msg[4]) # P2P Networkを単なるトランスポートとして使っているアプリケーションが独自拡張したメッセージを処理する # 重複チェック # ここで同じメッセージを送らないようにしないと永遠と送り続けるループに入ってしまう current_message = self.my_protocol_message_store print('received messages', current_message) has_same = False if not msg[4] in current_message: self.my_protocol_message_store.append(msg[4]) self.mpmh.handle_message(msg[4], self.__core_api) def __core_api(self, request, message): """ MyProtocolMessageHandlerで呼び出すための拡張関数群 """ msg_type = MSG_ENHANCED if request == SEND_TO_ALL_EDGE: print('Sending all edge...') new_message = self.cm.get_message_text(msg_type, message) self.cm.send_msg_to_all_edge(new_message) return 'ok' elif request == SEND_TO_ALL_PEER: new_message = self.cm.get_message_text(msg_type, message) self.cm.send_msg_to_all_peer(new_message) return 'ok' elif request == 'api_type': return 'server_core_api' def __generate_block_with_tp(self): result = self.tp.get_stored_transactions() if len(result) == 0: print('Transaction Pool is empty') new_block = self.bb.generate_new_block(result, self.prev_block_hash) self.bm.set_new_block(new_block.to_dict()) prev_block_hash = self.bm.get_hash(new_block.to_dict()) # ブロック生成に成功したらTransaction Poolはクリアする index = len(result) self.tp.clear_my_transactions(index) print('Current Blockchain is ...', self.bm.chain) print('Current prev_block_hash is ...', self.prev_block_hash) self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start()
class ServerCore: def __init__(self, my_port=50082, core_node_host=None, core_node_port=None, pass_phrase=None): self.server_state = STATE_INIT print('Initializing server...') self.my_ip = self.__get_myip() print('Server IP address is set to ... ', self.my_ip) self.my_port = my_port self.cm = ConnectionManager(self.my_ip, self.my_port, self.__handle_message) self.mpmh = MyProtocolMessageHandler() self.core_node_host = core_node_host self.core_node_port = core_node_port self.bb = BlockBuilder() my_genesis_block = self.bb.generate_genesis_block() self.bm = BlockchainManager(my_genesis_block.to_dict()) self.prev_block_hash = self.bm.get_hash(my_genesis_block.to_dict()) self.tp = TransactionPool() self.is_bb_running = False self.flag_stop_block_build = False self.mpm_store = MessageStore() self.km = KeyManager(None, pass_phrase) self.rsa_util = RSAUtil() self.um = UTXOManager(self.km.my_address()) def start_block_building(self): self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() def stop_block_building(self): print('Thread for __generate_block_with_tp is stopped now') self.bb_timer.cancel() def start(self): self.server_state = STATE_STANDBY self.cm.start() self.start_block_building() def join_network(self): if self.core_node_host != None: self.server_state = STATE_CONNECTED_TO_CENTRAL self.cm.join_network(self.core_node_host, self.core_node_port) else: print('This server is runnning as Genesis Core Node...') def shutdown(self): self.server_state = STATE_SHUTTING_DOWN self.flag_stop_block_build = True print('Shutdown server...') self.cm.connection_close() self.stop_block_building() def get_my_current_state(self): return self.server_state def send_req_full_chain_to_my_peer(self): print('send_req_full_chain_to_my_central called') new_message = self.cm.get_message_text(MSG_REQUEST_FULL_CHAIN) self.cm.send_msg((self.core_node_host, self.core_node_port), new_message) def get_all_chains_for_resolve_conflict(self): print('get_all_chains_for_resolve_conflict called') new_message = self.cm.get_message_text(MSG_REQUEST_FULL_CHAIN) self.cm.send_msg_to_all_peer(new_message) def __generate_block_with_tp(self): print('Thread for generate_block_with_tp started!') while not self.flag_stop_block_build: self.is_bb_running = True prev_hash = copy.copy(self.prev_block_hash) result = self.tp.get_stored_transactions() if len(result) == 0: print('Transaction Pool is empty ...') break new_tp = self.bm.remove_useless_transaction(result) self.tp.renew_my_transactions(new_tp) if len(new_tp) == 0: break # リワードとしてリストの先頭に自分宛のCoinbaseTransactionを追加する total_fee = self.tp.get_total_fee_from_tp() # TODO: インセンティブの値をここに直書きするのはイケてないのであとで対処する total_fee += 30 my_coinbase_t = CoinbaseTransaction(self.km.my_address(), total_fee) transactions_4_block = copy.deepcopy(new_tp) transactions_4_block.insert(0, my_coinbase_t.to_dict()) new_block = self.bb.generate_new_block(transactions_4_block, prev_hash) # タイミングがどうしてもクロスするので念のため保存前に再度確認 if new_block.to_dict()['previous_block'] == self.prev_block_hash: self.bm.set_new_block(new_block.to_dict()) self.prev_block_hash = self.bm.get_hash(new_block.to_dict()) msg_new_block = self.cm.get_message_text( MSG_NEW_BLOCK, json.dumps(new_block.to_dict())) self.cm.send_msg_to_all_peer(msg_new_block) # ブロック生成に成功したらTransaction Poolはクリアする index = len(new_tp) self.tp.clear_my_transactions(index) break else: print('Bad block. It seems someone already win the PoW.') break print('Current Blockchain is ... ', self.bm.chain) print('Current prev_block_hash is ... ', self.prev_block_hash) self.flag_stop_block_build = False self.is_bb_running = False self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() def _check_availability_of_transaction(self, transaction): """ Transactionに含まれているTransactionInputの有効性(二重使用)を検証する """ v_result, used_outputs = self.rsa_util.verify_sbc_transaction_sig( transaction) if v_result is not True: print('signature verification error on new transaction') return False for used_o in used_outputs: print('used_o', used_o) bm_v_result = self.bm.has_this_output_in_my_chain(used_o) tp_v_result = self.tp.has_this_output_in_my_tp(used_o) bm_v_result2 = self.bm.is_valid_output_in_my_chain(used_o) if bm_v_result: print('This TransactionOutput is already used', used_o) return False if tp_v_result: print( 'This TransactionOutput is already stored in the TransactionPool', used_o) return False if bm_v_result2 is not True: print('This TransactionOutput is unknown', used_o) return False return True def _check_availability_of_transaction_in_block(self, transaction): """ Transactionの有効性を検証する(Block用) """ v_result, used_outputs = self.rsa_util.verify_sbc_transaction_sig( transaction) if v_result is not True: print('signature verification error on new transaction') return False print('used_outputs: ', used_outputs) for used_o in used_outputs: print('used_o: ', used_o) bm_v_result = self.bm.has_this_output_in_my_chain(used_o) bm_v_result2 = self.bm.is_valid_output_in_my_chain(used_o) if bm_v_result2 is not True: print('This TransactionOutput is unknown', used_o) return False if bm_v_result: print('This TransactionOutput is already used', used_o) return False return True def get_total_fee_on_block(self, block): """ ブロックに格納されているbasicなTransaction全ての手数料の合計値を算出する """ print('get_total_fee_on_block is called') transactions = block['transactions'] result = 0 for t in transactions: t = json.loads(t) is_sbc_t, t_type = self.um.is_sbc_transaction(t) if t_type == 'basic': total_in = sum( i['transaction']['outputs'][i['output_index']]['value'] for i in t['inputs']) total_out = sum(o['value'] for o in t['outputs']) delta = total_in - total_out result += delta return result def check_transactions_in_new_block(self, block): """ ブロック内のTranactionに不正がないか確認する """ fee_for_block = self.get_total_fee_on_block(block) fee_for_block += 30 print("fee_for_block: ", fee_for_block) transactions = block['transactions'] counter = 0 for t in transactions: t = json.loads(t) # basic, coinbase_transaction以外はスルーチェック is_sbc_t, t_type = self.um.is_sbc_transaction(t) if is_sbc_t: if t_type == 'basic': if self._check_availability_of_transaction_in_block( t) is not True: print('Bad Block. Having invalid Transaction') return False elif t_type == 'coinbase_transaction': if counter != 0: print('Coinbase Transaction is only for BlockBuilder') return False else: insentive = t['outputs'][0]['value'] print('insentive', insentive) if insentive != fee_for_block: print( 'Invalid value in fee for CoinbaseTransaction', insentive) return False else: is_verified = self.rsa_util.verify_general_transaction_sig(t) if is_verified is not True: return False print('ok. this block is acceptable.') return True def __core_api(self, request, message): if request == 'send_message_to_all_peer': new_message = self.cm.get_message_text(MSG_ENHANCED, message) self.cm.send_msg_to_all_peer(new_message) return 'ok' elif request == 'send_message_to_all_edge': new_message = self.cm.get_message_text(MSG_ENHANCED, message) self.cm.send_msg_to_all_edge(new_message) return 'ok' elif request == 'api_type': return 'server_core_api' elif request == 'send_message_to_this_pubkey_address': print('send_message_to_this_pubkey_address', message[0]) msg_type = MSG_ENHANCED msg_txt = self.cm.get_message_text(msg_type, message[1]) check_result, target_host, target_port = self.cm.has_this_edge( message[0]) print('check_result', check_result) if check_result: print('sending cipher direct message to... ', target_host, target_port) self.cm.send_msg((target_host, target_port), msg_txt) return 'ok' else: return None def __handle_message(self, msg, is_core, peer=None): if peer != None: if msg[2] == MSG_REQUEST_FULL_CHAIN: print('Send our latest blockchain for reply to : ', peer) mychain = self.bm.get_my_blockchain() chain_data = pickle.dumps(mychain, 0).decode() new_message = self.cm.get_message_text(RSP_FULL_CHAIN, chain_data) self.cm.send_msg(peer, new_message) else: if msg[2] == MSG_NEW_TRANSACTION: new_transaction = json.loads(msg[4]) print('received new_transaction', new_transaction) is_sbc_t, _ = self.um.is_sbc_transaction(new_transaction) current_transactions = self.tp.get_stored_transactions() if new_transaction in current_transactions: print('this is already pooled transaction: ', new_transaction) return if not is_sbc_t: print('this is not SimpleBitcoin transaction: ', new_transaction) else: # テスト用に最初のブロックだけ未知のCoinbaseTransactionを許すための暫定処置 if self.bm.get_my_chain_length() != 1: checked = self._check_availability_of_transaction( new_transaction) if not checked: print('Transaction Verification Error') return self.tp.set_new_transaction(new_transaction) if not is_core: new_message = self.cm.get_message_text( MSG_NEW_TRANSACTION, json.dumps(new_transaction)) self.cm.send_msg_to_all_peer(new_message) else: if not is_sbc_t: print('this is not SimpleBitcoin transaction: ', new_transaction) else: # テスト用に最初のブロックだけ未知のCoinbaseTransactionを許すための暫定処置 if self.bm.get_my_chain_length() != 1: checked = self._check_availability_of_transaction( new_transaction) if not checked: print('Transaction Verification Error') return self.tp.set_new_transaction(new_transaction) if not is_core: new_message = self.cm.get_message_text( MSG_NEW_TRANSACTION, json.dumps(new_transaction)) self.cm.send_msg_to_all_peer(new_message) elif msg[2] == MSG_NEW_BLOCK: if not is_core: print('block received from unknown') return new_block = json.loads(msg[4]) print('new_block: ', new_block) if self.bm.is_valid_block(self.prev_block_hash, new_block): block_check_result = self.check_transactions_in_new_block( new_block) print('block_check_result : ', block_check_result) if block_check_result is not True: print( 'previous block hash is ok. but still not acceptable.' ) self.get_all_chains_for_resolve_conflict() return # ブロック生成が行われていたら一旦停止してあげる(threadingなのでキレイに止まらない場合あり) if self.is_bb_running: self.flag_stop_block_build = True self.prev_block_hash = self.bm.get_hash(new_block) self.bm.set_new_block(new_block) else: # ブロックとして不正ではないがVerifyにコケる場合は自分がorphanブロックを生成している # 可能性がある self.get_all_chains_for_resolve_conflict() elif msg[2] == RSP_FULL_CHAIN: if not is_core: print('blockchain received from unknown') return # ブロックチェーン送信要求に応じて返却されたブロックチェーンを検証し、有効なものか検証した上で # 自分の持つチェインと比較し優位な方を今後のブロックチェーンとして有効化する new_block_chain = pickle.loads(msg[4].encode('utf8')) result, pool_4_orphan_blocks = self.bm.resolve_conflicts( new_block_chain) print('blockchain received') if result is not None: self.prev_block_hash = result if len(pool_4_orphan_blocks) != 0: # orphanブロック群の中にあった未処理扱いになるTransactionをTransactionPoolに戻す new_transactions = self.bm.get_transactions_from_orphan_blocks( pool_4_orphan_blocks) for t in new_transactions: self.tp.set_new_transaction(t) else: print('Received blockchain is useless...') elif msg[2] == MSG_ENHANCED: # アプリケーションがP2P Network を単なるトランスポートして使うために独自拡張したメッセージはここで処理する。 # SimpleBitcoin としてはこの種別は使わない print('received enhanced message', msg[4]) has_same = self.mpm_store.has_this_msg(msg[4]) if has_same is not True: self.mpm_store.add(msg[4]) self.mpmh.handle_message(msg[4], self.__core_api, is_core) def __get_myip(self): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) return s.getsockname()[0]
class ServerCore(object): def __init__(self, my_port=50082, core_node_host=None, core_node_port=None): self.server_state = STATE_INIT print('Initializing server...') self.my_ip = self.__get_myip() print('Server IP address is set to ... ', self.my_ip) self.my_port = my_port self.cm = ConnectionManager(self.my_ip, self.my_port, self.__handle_message) self.mpmh = MyProtocolMessageHandler() self.core_node_host = core_node_host self.core_node_port = core_node_port self.bb = BlockBuilder() self.flag_stop_block_build = False self.is_bb_running = False my_genesis_block = self.bb.generate_genesis_block() self.bm = BlockchainManager(my_genesis_block.to_dict()) self.prev_block_hash = self.bm.get_hash(my_genesis_block.to_dict()) self.tp = TransactionPool() self.vl = VerifyLocinfo() # 位置情報の偽装を検知するようのカウンタ self.c_cnt = 0 self.bc_cnt = 0 self.false_cnt = 0 def start_block_building(self): self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() def stop_block_building(self): print('Thread for __generate_block_with_tp is stopped now') self.bb_timer.cancel() def start(self): self.server_state = STATE_STANDBY self.cm.start() self.start_block_building() def join_network(self): if self.core_node_host != None: self.server_state = STATE_CONNECTED_TO_NETWORK # 状態:親ノードへ接続中 self.cm.join_network(self.core_node_host, self.core_node_port) else: print('This server is running as Genesis Core Node...') def shutdown(self): self.server_state = STATE_SHUTTING_DOWN # 状態:切断中 print('Shutdown server...') self.cm.connection_close() self.stop_block_building() def get_my_current_state(self): return self.server_state def get_all_chains_for_resolve_conflict(self): print('get_all_chains_for_resolve_conflict called') new_message = self.cm.get_message_text(MSG_REQUEST_FULL_CHAIN) self.cm.send_msg_to_all_peer(new_message) def __generate_block_with_tp(self): print('Thread for generate_block_with_tp started!') while self.flag_stop_block_build is not True: result = self.tp.get_stored_transactions() if result == None: print('Transaction Pool is empty ...') break new_tp = self.bm.remove_useless_transaction(result) self.tp.renew_my_transactions(new_tp) if len(new_tp) == 0: break new_block = self.bb.generate_new_block(new_tp, self.prev_block_hash) self.bm.set_new_block(new_block.to_dict()) self.prev_block_hash = self.bm.get_hash(new_block.to_dict()) message_new_block = self.cm.get_message_text( MSG_NEW_BLOCK, json.dumps(new_block.to_dict())) self.cm.send_msg_to_all_peer(message_new_block) index = len(result) self.tp.clear_my_transactions(index) break print('Current Blockchain is ... ', self.bm.chain) print('Current prev_block_hash is ... ', self.prev_block_hash) self.flag_stop_block_build = False self.is_bb_running = False self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() def __handle_message(self, msg, is_core, peer=None): if peer != None: if msg[2] == MSG_REQUEST_FULL_CHAIN: print('Send our latest blockchain for reply to : ', peer) mychain = self.bm.get_my_blockchain() print(mychain) chain_data = pickle.dumps(mychain, 0).decode() new_message = self.cm.get_message_text(RSP_FULL_CHAIN, chain_data) self.cm.send_msg(peer, new_message) else: if msg[2] == MSG_NEW_TRANSACTION: # 新規transactionを登録する処理を呼び出す new_transaction = json.loads(msg[4]) print("received new_transaction", new_transaction) current_transactions = self.tp.get_stored_transactions() bc_transactions = self.bm.get_stored_transactions_from_bc() if new_transaction in current_transactions: print("this is already pooled transaction:", new_transaction) return else: # 車両から送られてきた位置情報を検知する if len(current_transactions ) > 0 and self.vl.verify_trlocinfo( new_transaction, current_transactions): self.c_cnt += 1 with open( '/home/ryoichi/Templates/BlockchainProjects/result/result_c_cnt.txt', 'a') as f: f.write( str(self.my_port) + "," + str(self.c_cnt) + "\n") print("C_Counter", self.c_cnt) self.tp.set_new_transaction(new_transaction) if not is_core: m_type = MSG_NEW_TRANSACTION new_message = self.cm.get_message_text( m_type, json.dumps(new_transaction)) self.cm.send_msg_to_all_peer(new_message) elif len(bc_transactions) > 0 and self.vl.verify_trlocinfo( new_transaction, bc_transactions): self.bc_cnt += 1 with open( '/home/ryoichi/Templates/BlockchainProjects/result/result_bc_cnt.txt', 'a') as f: f.write( str(self.my_port) + "," + str(self.bc_cnt) + "\n") print("BC_Counter", self.bc_cnt) self.tp.set_new_transaction(new_transaction) if not is_core: m_type = MSG_NEW_TRANSACTION new_message = self.cm.get_message_text( m_type, json.dumps(new_transaction)) self.cm.send_msg_to_all_peer(new_message) else: self.false_cnt += 1 with open( '/home/ryoichi/Templates/BlockchainProjects/result/result_false_cnt.txt', 'a') as f: f.write( str(self.my_port) + "," + str(self.false_cnt) + "\n") print("FALSE_Counter", self.false_cnt) ntr = new_transaction['vehicleinfo'] process_time = time.time( ) - new_transaction['sendtime'] ntr_id = [i['ID'] for i in ntr] ntr_ID = ntr_id[0] if len(ntr_id) else '' ntr_ts = [i['timestamp'] for i in ntr] ntr_timestamp = ntr_ts[0] if len(ntr_ts) else '' ntr_or = [i['TorF'] for i in ntr] ntr_torf = ntr_or[0] if len(ntr_or) else '' with open( '/home/ryoichi/Templates/BlockchainProjects/result/result_new_transaction.txt', 'a') as f: f.write( str(self.my_port) + "," + str(ntr_ID) + "," + str(ntr_timestamp) + "," + str(ntr_torf) + "," + str(process_time) + "\n") print("FALSE_Counter", self.false_cnt) self.tp.set_new_transaction(new_transaction) if not is_core: m_type = MSG_NEW_TRANSACTION new_message = self.cm.get_message_text( m_type, json.dumps(new_transaction)) self.cm.send_msg_to_all_peer(new_message) elif msg[2] == MSG_NEW_BLOCK: if not is_core: print('block received from unknown') return # 新規ブロックを検証し、正当なものであればブロックチェーンに追加する new_block = json.loads(msg[4]) block_processtime = self.vl.extract_newblockprocesstime( new_block) with open( '/home/ryoichi/Templates/BlockchainProjects/result/result_new_block_time.txt', 'a') as f: f.write( str(self.my_port) + "," + str(block_processtime) + "\n") with open( '/home/ryoichi/Templates/BlockchainProjects/result/result_new_block.txt', 'a') as f: f.write(str(self.my_port) + "," + str(new_block) + "\n") print('new_block: ', new_block) if self.bm.is_valid_block(self.prev_block_hash, new_block): # ブロック生成が行われていたら一旦停止してあげる(threadingなのでキレイに止まらない場合あり) if self.is_bb_running: self.flag_stop_block_build = True self.prev_block_hash = self.bm.get_hash(new_block) self.bm.set_new_block(new_block) else: # ブロックとして不正ではないがVerifyにコケる場合は自分がorphanブロックを生成している # 可能性がある self.get_all_chains_for_resolve_conflict() elif msg[2] == RSP_FULL_CHAIN: if not is_core: print('blockchain received from unknown') return # ブロックチェーン送信要求に応じて返却されたブロックチェーンを検証し、有効なものか検証した上で # 自分の持つチェインと比較し優位な方を今後のブロックチェーンとして有効化する new_block_chain = pickle.loads(msg[4].encode('utf8')) print(new_block_chain) result, pool_4_orphan_blocks = self.bm.resolve_conflicts( new_block_chain) print('blockchain received') if result is not None: self.prev_block_hash = result if len(pool_4_orphan_blocks) != 0: # orphanブロック群の中にあった未処理扱いになるTransactionをTransactionPoolに戻す new_transactions = self.bm.get_transactions_from_orphan_blocks( pool_4_orphan_blocks) for t in new_transactions: self.tp.set_new_transaction(t) else: print('Received blockchain is useless...') elif msg[2] == MSG_ENHANCED: # P2P Network を単なるトランスポートして使っているアプリケーションが独自拡張したメッセージはここで処理する。SimpleBitcoin としてはこの種別は使わない self.mpmh.handle_message(msg[4]) def __get_myip(self): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) return s.getsockname()[0] def get_count(self): a = self.c_cnt b = self.bc_cnt c = self.false_cnt return a, b, c
class ServerCore(object): def __init__(self, my_port=50082, core_node_host=None, core_node_port=None): self.server_state = STATE_INIT print('Initializing server...') self.my_ip = self.__get_myip() print('Server IP address is set to ... ', self.my_ip) self.my_port = my_port self.cm = ConnectionManager(self.my_ip, self.my_port, self.__handle_message, self) self.mpmh = MyProtocolMessageHandler() self.core_node_host = core_node_host self.core_node_port = core_node_port self.bb = BlockBuilder() self.flag_stop_block_build = False self.is_bb_running = False my_genesis_block = self.bb.generate_genesis_block() self.bm = BlockchainManager(my_genesis_block.to_dict()) self.prev_block_hash = self.bm.get_hash(my_genesis_block.to_dict()) self.tp = TransactionPool() if core_node_host and core_node_port: self.plz_share_db() def start_block_building(self): self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() def stop_block_building(self): print('Thread for __generate_block_with_tp is stopped now') self.bb_timer.cancel() def start(self): self.server_state = STATE_STANDBY self.cm.start() self.start_block_building() def join_network(self): if self.core_node_host is not None: self.server_state = STATE_CONNECTED_TO_NETWORK # 状態:親ノードへ接続中 self.cm.join_network(self.core_node_host, self.core_node_port) else: print('This server is running as Genesis Core Node...') def shutdown(self): self.server_state = STATE_SHUTTING_DOWN # 状態:切断中 print('Shutdown server...') self.cm.connection_close() self.stop_block_building() def get_my_current_state(self): return self.server_state def plz_share_db(self): print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") print("■■■■■■■■■■■■■■■■■■■■ plz_share_db ■■■■■■■■■■■■■■■■■■■■■■") print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") new_message = self.cm.get_message_text(SHARE_DB3) self.cm.send_msg((self.core_node_host, self.core_node_port), new_message) print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") # TODO 接続時のアレコレ def get_all_chains_for_resolve_conflict(self): print('get_all_chains_for_resolve_conflict called') new_message = self.cm.get_message_text(MSG_REQUEST_FULL_CHAIN) self.cm.send_msg_to_all_peer(new_message) def __generate_block_with_tp(self): if DEBUG: print('Thread for generate_block_with_tp started!') while self.flag_stop_block_build is not True: result = self.tp.get_stored_transactions() if result is None: print('Transaction Pool is empty ...') break new_tp = self.bm.remove_useless_transaction(result) self.tp.renew_my_transactions(new_tp) # if len(new_tp) == 0: # TODO TPが0のとき、終わるように。コメントアウトで切り替え # break new_block = self.bb.generate_new_block(new_tp, self.prev_block_hash) self.bm.set_new_block(new_block.to_dict()) self.prev_block_hash = self.bm.get_hash(new_block.to_dict()) message_new_block = self.cm.get_message_text( MSG_NEW_BLOCK, json.dumps(new_block.to_dict())) self.cm.send_msg_to_all_peer(message_new_block) index = len(result) self.tp.clear_my_transactions(index) break print( "■■■■■■■■■■■■■■■■■■■ Current BC ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■" ) print(self.bm.chain) if len(self.bm.chain) >= 10: main_level.add_db(ldb_p=LDB_P, param_p=PARAM_P, zip_p=ZIP_P, vals=self.bm.chain[:5]) self.bm.chain = self.bm.chain[5:] print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") print("保存しました") print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") # print('Current prev_block_hash is ... ', self.prev_block_hash) self.flag_stop_block_build = False self.is_bb_running = False self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() def __handle_message(self, msg, is_core, peer=None): if peer: if msg[2] == MSG_REQUEST_FULL_CHAIN: if DEBUG: print('Send our latest blockchain for reply to : ', peer) mychain = self.bm.get_my_blockchain() if DEBUG: print(mychain) chain_data = pickle.dumps(mychain, 0).decode() new_message = self.cm.get_message_text(RSP_FULL_CHAIN, chain_data) self.cm.send_msg(peer, new_message) else: if msg[2] == MSG_NEW_TRANSACTION: # 新規transactionを登録する処理を呼び出す new_transaction = json.loads(msg[4]) print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") print("transactions", self.tp.get_stored_transactions()) print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") if DEBUG: print("received new_transaction", new_transaction) current_transactions = self.tp.get_stored_transactions() if new_transaction in current_transactions: if DEBUG: print("this is already pooled transaction:", new_transaction) return if not is_core: self.tp.set_new_transaction(new_transaction) # new_message = self.cm.get_message_text(MSG_NEW_BLOCK, json.dumps(new_block.to_dict())) new_message = self.cm.get_message_text( MSG_NEW_TRANSACTION, json.dumps(new_transaction)) self.cm.send_msg_to_all_peer(new_message) else: self.tp.set_new_transaction(new_transaction) elif msg[2] == MSG_NEW_BLOCK: if not is_core: print('block received from unknown') return # 新規ブロックを検証し、正当なものであればブロックチェーンに追加する # TODO new_block = json.loads(msg[4]) if DEBUG: print('new_block: ', new_block) if self.bm.is_valid_block(self.prev_block_hash, new_block): # ブロック生成が行われていたら一旦停止してあげる(threadingなのでキレイに止まらない場合あり) if self.is_bb_running: self.flag_stop_block_build = True self.prev_block_hash = self.bm.get_hash(new_block) self.bm.set_new_block(new_block) else: # ブロックとして不正ではないがVerifyにコケる場合は自分がorphanブロックを生成している # 可能性がある self.get_all_chains_for_resolve_conflict() elif msg[2] == RSP_FULL_CHAIN: if not is_core: if DEBUG: print('blockchain received from unknown') return # ブロックチェーン送信要求に応じて返却されたブロックチェーンを検証し、有効なものか検証した上で # 自分の持つチェインと比較し優位な方を今後のブロックチェーンとして有効化する new_block_chain = pickle.loads(msg[4].encode('utf8')) print(new_block_chain) result, pool_4_orphan_blocks = self.bm.resolve_conflicts( new_block_chain) if DEBUG: print('blockchain received') if result is not None: self.prev_block_hash = result if len(pool_4_orphan_blocks) != 0: # orphanブロック群の中にあった未処理扱いになるTransactionをTransactionPoolに戻す new_transactions = self.bm.get_transactions_from_orphan_blocks( pool_4_orphan_blocks) for t in new_transactions: self.tp.set_new_transaction(t) else: if DEBUG: print('Received blockchain is useless...') elif msg[2] == MSG_ENHANCED: # P2P Network を単なるトランスポートして使っているアプリケーションが独自拡張したメッセージはここで処理する。SimpleBitcoin としてはこの種別は使わない self.mpmh.handle_message(msg[4]) def __get_myip(self): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) return s.getsockname()[0]
class ServerCore: def __init__(self, my_port=50082, core_node_host=None, core_node_port=None): self.server_state = STATE_INIT print('Initializing server...') self.my_ip = utils.get_host() print('Server IP address is set to ... ', self.my_ip) self.my_port = my_port self.cm = ConnectionManager(self.my_ip, self.my_port, self.__handle_message) self.core_node_host = core_node_host self.core_node_port = core_node_port self.miners_wallet = Wallet() self.blockchain = BlockChain(self.miners_wallet.blockchain_address) self.mining_semaphore = threading.Semaphore(1) self.__print_info() def __print_info(self): print({ 'private_key': self.miners_wallet.private_key, 'public_key': self.miners_wallet.public_key, 'blockchain_address': self.miners_wallet.blockchain_address }) def start(self): """ Coreノードとしての待受を開始 """ self.server_state = STATE_STANDBY self.cm.start() self.start_mining() def join_network(self): """ 事前に取得した情報に従い拠り所となる他のCoreノードに接続 """ if self.core_node_host is not None: self.server_state = STATE_CONNECTED_TO_NETWORK self.cm.join_network(self.core_node_host, self.core_node_port) else: print('This server is runnning as Genesis Core Node...') def shutdown(self): """ 待ち受け状態のServer Socketを閉じて終了 """ self.server_state = STATE_SHUTTING_DOWN print('Shutdown server...') self.cm.connection_close() def start_mining(self): print('start mining') is_acquire = self.mining_semaphore.acquire(blocking=False) if is_acquire: with contextlib.ExitStack() as stack: stack.callback(self.mining_semaphore.release) self.__mining() mining_interval = self.blockchain.mining_speed + random.uniform( 9.8, 10.3) loop = threading.Timer(round(mining_interval), self.start_mining) loop.start() def __mining(self): start = time.time() self.blockchain.add_transaction( sender_blockchain_address=MINING_SENDER, recipient_blockchain_address=self.blockchain.blockchain_address, value=MINING_REWARD) nonce = self.blockchain.proof_of_work() if nonce == -1: return False previous_hash = self.blockchain.hash(self.blockchain.chain[-1]) is_created, block = self.blockchain.create_block(nonce, previous_hash) if not is_created: return False self.delete_transaction_for_all_peer() print({'action': 'mining', 'status': 'success'}) utils.pprint(self.blockchain.chain) self.send_all_chain_for_consensus() elapse = round(time.time() - start, 4) self.blockchain.difficulty_adjustment(elapse) # print('mining speed : ', str(round(self.mining_speed, 3))) # print('difficult : ', str(self.difficulty)) return True def delete_transaction_for_all_peer(self): """ ノードのトランザクションプールをからにするメッセージの送信 """ new_message = self.cm.get_message_text(MSG_DELETE_TRANSACTION) self.cm.send_msg_to_all_peer(new_message) def send_all_chain_for_consensus(self): """ チェーンを全てのノードに送信してコンセンサス """ my_chain = self.blockchain.chain chain_data = json.dumps(my_chain) new_message = self.cm.get_message_text(RSP_FULL_CHAIN, chain_data) self.cm.send_msg_to_all_peer(new_message) def __handle_message(self, msg, is_core, peer=None): """ ConnectionManagerに引き渡すコールバックの中身。 """ print('message_type : ', msg[2]) if peer is not None: if msg[2] == MSG_REQUEST_FULL_CHAIN: # walletのチェーンを同期 print('Send our latest blockchain for reply to : ', peer) my_chain = self.blockchain.chain chain_data = json.dumps(my_chain) new_message = self.cm.get_message_text(RSP_FULL_CHAIN, chain_data) self.cm.send_msg(peer, new_message) elif msg[2] == MSG_REQUEST_KEY_INFO: # walletにminerの鍵情報を渡す key_info = pickle.dumps(self.miners_wallet, 0).decode() m_type = MSG_KEY_INFO message = self.cm.get_message_text(m_type, key_info) self.cm.send_msg(peer, message) elif msg[2] == MSG_DELETE_TRANSACTION: # transaction poolを空に print('DELETE_TRANSACTION is called') self.blockchain.transaction_pool = [] else: if msg[2] == MSG_NEW_TRANSACTION: print('NEW_TRANSACTION command is called') payload = json.loads(msg[4]) new_transaction = utils.sorted_dict_by_key({ 'sender_blockchain_address': payload['sender_blockchain_address'], 'recipient_blockchain_address': payload['recipient_blockchain_address'], 'value': float(payload['value']) }) current_transactions = self.blockchain.transaction_pool.copy() print('new transaction : ', new_transaction) if new_transaction in current_transactions: print('transaction is already in pool') return else: signature = pickle.loads( payload['signature'].encode('utf8')) print('signature', signature) is_transacted = self.blockchain.add_transaction( payload['sender_blockchain_address'], payload['recipient_blockchain_address'], payload['value'], payload['sender_public_key'], signature) if is_transacted: print('new transaction is generated') print('\n\ntransaction_pool', self.blockchain.transaction_pool) if not is_core: # ウォレットからのトランザクションはブロードキャスト print('transaction bloadcasted') m_type = MSG_NEW_TRANSACTION new_message = self.cm.get_message_text(m_type, msg[4]) self.cm.send_msg_to_all_peer(new_message) elif msg[2] == RSP_FULL_CHAIN: print('RSP_FULL_CHAIN command is called') if not is_core: return new_block_chain = json.loads(msg[4]) self.blockchain.resolve_conflicts(new_block_chain)
class ServerCore(object): def __init__(self, my_port=50082, core_node_host=None, core_node_port=None): self.server_state = STATE_INIT print('Initializing server...') self.my_ip = self.__get_myip() print('Server IP address is set to ... ', self.my_ip) self.my_port = my_port self.cm = ConnectionManager(self.my_ip, self.my_port, self.__handle_message) self.mpmh = MyProtocolMessageHandler() self.core_node_host = core_node_host self.core_node_port = core_node_port self.bb = BlockBuilder() my_genesis_block = self.bb.generate_genesis_block() self.bm = BlockchainManager(my_genesis_block.to_dict()) self.prev_block_hash = self.bm.get_hash(my_genesis_block.to_dict()) self.tp = TransactionPool() def start(self): self.server_state = STATE_STANDBY self.cm.start() self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() def join_network(self): if self.core_node_host != None: self.server_state = STATE_CONNECTED_TO_NETWORK # 状態:親ノードへ接続中 self.cm.join_network(self.core_node_host, self.core_node_port) else: print('This server is runnning as Genesis Core Node...') def shutdown(self): self.server_state = STATE_SHUTTING_DOWN # 状態:切断中 print('Shutdown server...') self.cm.connection_close() def get_my_current_state(self): return self.server_state def __generate_block_with_tp(self): result = self.tp.get_stored_transactions() print('generate_block_with_tp called!') if len(result) == 0: print('Transaction Pool is empty ...') new_block = self.bb.generate_new_block(result, self.prev_block_hash) self.bm.set_new_block(new_block.to_dict()) self.prev_block_hash = self.bm.get_hash(new_block.to_dict()) # ブロック生成に成功したらTransaction Poolはクリアする index = len(result) self.tp.clear_my_transactions(index) print('Current Blockchain is ... ', self.bm.chain) print('Current prev_block_hash is ... ', self.prev_block_hash) self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() def __handle_message(self, msg, is_core, peer=None): if peer != None: if msg[2] == MSG_REQUEST_FULL_CHAIN: # TODO: 現状はMSG_REQUEST_FULL_CHAINの時くらいしか想定してないけどとりあえず print('Send our latest blockchain for reply to : ', peer) pass else: if msg[2] == MSG_NEW_TRANSACTION: # 新規transactionを登録する処理を呼び出す new_transaction = json.loads(msg[4]) print("received new_transaction", new_transaction) current_transactions = self.tp.get_stored_transactions() has_same = False if new_transaction in current_transactions: print("this is already pooled transaction:", t) return if not is_core: self.tp.set_new_transaction(new_transaction) new_message = self.cm.get_message_text( MSG_NEW_TRANSACTION, json.dumps(new_transaction)) self.cm.send_msg_to_all_peer(new_message) else: self.tp.set_new_transaction(new_transaction) elif msg[2] == MSG_NEW_BLOCK: # TODO: 新規ブロックを検証する処理を呼び出す pass elif msg[2] == RSP_FULL_CHAIN: # TODO: ブロックチェーン送信要求に応じて返却されたブロックチェーンを検証する処理を呼び出す pass elif msg[2] == MSG_ENHANCED: # P2P Network を単なるトランスポートして使っているアプリケーションが独自拡張したメッセージはここで処理する。SimpleBitcoin としてはこの種別は使わない self.mpmh.handle_message(msg[4]) def __get_myip(self): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) return s.getsockname()[0]
class ServerCore(object): def __init__(self, my_port=50082, core_node_host=None, core_node_port=None): self.server_state = STATE_INIT # self.main_window = GuiTest() print('Initializing server...') self.my_ip = self.__get_myip() print('Server IP address is set to ... ', self.my_ip) self.my_port = my_port self.cm = ConnectionManager( self.my_ip, self.my_port, self.__handle_message, self ) #, self.main_window.set_cnode_list, self.main_window.set_enode_list) self.mpmh = MyProtocolMessageHandler() self.core_node_host = core_node_host self.core_node_port = core_node_port self.bb = BlockBuilder() self.flag_stop_block_build = False self.is_bb_running = False my_genesis_block = self.bb.generate_genesis_block() self.bm = BlockchainManager(my_genesis_block.to_dict()) self.prev_block_hash = self.bm.get_hash(my_genesis_block.to_dict()) self.tp = TransactionPool() if core_node_host and core_node_port: self.plz_share_db() # self.get_all_chains_for_resolve_conflict() # self.main_window.set_port(self.my_port) """ def start_gui(self): try: self.main_window.start() except: time.sleep(5) """ def start_block_building(self): self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() def stop_block_building(self): print('Thread for __generate_block_with_tp is stopped now') self.bb_timer.cancel() def start(self): self.server_state = STATE_STANDBY self.cm.start() self.start_block_building() def join_network(self): if self.core_node_host != None: self.server_state = STATE_CONNECTED_TO_NETWORK # 状態:親ノードへ接続中 self.cm.join_network(self.core_node_host, self.core_node_port) else: print('This server is running as Genesis Core Node...') def shutdown(self): self.server_state = STATE_SHUTTING_DOWN # 状態:切断中 print('Shutdown server...') self.cm.connection_close() self.stop_block_building() def get_my_current_state(self): return self.server_state def plz_share_db(self): print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") print("■■■■■■■■■■■■■ plz_share_db ■■■■■■■■■■■■■■■■■■■■") print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") new_message = self.cm.get_message_text(Sync_DB3) self.cm.send_msg((self.core_node_host, self.core_node_port), new_message) print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") def get_all_chains_for_resolve_conflict(self): print('get_all_chains_for_resolve_conflict called') new_message = self.cm.get_message_text(MSG_REQUEST_FULL_CHAIN) self.cm.send_msg_to_all_peer(new_message) def __generate_block_with_tp(self): print('Thread for generate_block_with_tp started!') if self.flag_stop_block_build is not True: result = self.tp.get_stored_transactions() if result == []: print('Transaction Pool is empty ...') #TODO:Create Empty Block new_block = self.bb.generate_new_block("", self.prev_block_hash) self.bm.set_new_block(new_block.to_dict()) self.prev_block_hash = self.bm.get_hash(new_block.to_dict()) message_new_block = self.cm.get_message_text( MSG_NEW_BLOCK, json.dumps(new_block.to_dict(), sort_keys=True, ensure_ascii=False)) self.cm.send_msg_to_all_peer(message_new_block) index = len(result) self.tp.clear_my_transactions(index) new_tp = self.bm.remove_useless_transaction(result) self.tp.renew_my_transactions(new_tp) if len(new_tp) == 0: pass else: new_block = self.bb.generate_new_block(new_tp, self.prev_block_hash) self.bm.set_new_block(new_block.to_dict()) self.prev_block_hash = self.bm.get_hash(new_block.to_dict()) message_new_block = self.cm.get_message_text( MSG_NEW_BLOCK, json.dumps(new_block.to_dict(), sort_keys=True, ensure_ascii=False)) self.cm.send_msg_to_all_peer(message_new_block) index = len(result) self.tp.clear_my_transactions(index) print('Current Blockchain is ... ', self.bm.chain) # + 省略中") if len(self.bm.chain) >= 10: main_level.add_db(ldb_p=LDB_P, param_p=PARAM_P, zip_p=ZIP_P, vals=self.bm.chain[:5]) self.bm.chain = self.bm.chain[5:] print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") print("保存しました") print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") print('Current prev_block_hash is ... ', self.prev_block_hash) self.flag_stop_block_build = False self.is_bb_running = False self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() def __handle_message(self, msg, is_core, peer=None): if peer != None: if msg[2] == MSG_REQUEST_FULL_CHAIN: print('Send our latest blockchain for reply to : ', peer) mychain = self.bm.get_my_blockchain() print(mychain) chain_data = pickle.dumps(mychain, 0).decode() new_message = self.cm.get_message_text(RSP_FULL_CHAIN, chain_data) self.cm.send_msg(peer, new_message) else: if msg[2] == MSG_NEW_TRANSACTION: #msg[4]の型を確認 if isinstance(msg[4], dict): # dict print("for_client_msg[4]") # d = json.loads(msg[4]) # json.loads を使って dict に変換 b = base64.b64decode( msg[4]['bin'].encode()) # base64 を使ってバイナリから復元 with open( dirname + "ZIP_busdata/accept_busdata/server_busdata.zip", "wb") as f: f.write(b) with zipfile.ZipFile( dirname + "ZIP_busdata/accept_busdata/server_busdata.zip" ) as zf: zf.extractall(dirname + "ZIP_busdata/accept_busdata") with open(dirname + "ZIP_busdata/accept_busdata/msg_pub.txt") as f: readdata = f.read().splitlines() print("read txt") new_transaction = json.loads(readdata[0]) if isinstance(msg[4], str): # str print("for_server_msg[4]") print(type(msg[4])) new_transaction = json.loads(msg[4]) else: print("object has no attribute") pass type(new_transaction) current_transactions = self.tp.get_stored_transactions() if new_transaction in current_transactions: print("this is already pooled transaction:") return if not is_core: #from edge node ds = CheckDigitalSignature(new_transaction) CHECK_SIGNATURE = ds.get_flag( ) #ds.check_signature(new_transaction) if CHECK_SIGNATURE == False: print('---------------------------------------') print('DigitalSignature is False') print('---------------------------------------') return else: print('---------------------------------------') print('DigitalSignature is True') print('---------------------------------------') self.tp.set_new_transaction(new_transaction) new_message = self.cm.get_message_text( MSG_NEW_TRANSACTION, json.dumps(new_transaction, sort_keys=True, ensure_ascii=False)) self.cm.send_msg_to_all_peer(new_message) else: self.tp.set_new_transaction(new_transaction) elif msg[2] == MSG_NEW_BLOCK: if not is_core: print('block received from unknown') return # 新規ブロックを検証し、正当なものであればブロックチェーンに追加する new_block = json.loads(msg[4]) print('new_block: ', new_block) if self.bm.is_valid_block(self.prev_block_hash, new_block): # is new block valid? # ブロック生成が行われていたら一旦停止してあげる(threadingなのでキレイに止まらない場合あり) if self.is_bb_running: self.flag_stop_block_build = True self.prev_block_hash = self.bm.get_hash(new_block) self.bm.set_new_block(new_block) else: # ブロックとして不正ではないがVerifyにコケる場合は自分がorphanブロックを生成している # 可能性がある self.get_all_chains_for_resolve_conflict() elif msg[2] == RSP_FULL_CHAIN: if not is_core: print('blockchain received from unknown') return # ブロックチェーン送信要求に応じて返却されたブロックチェーンを検証し、有効なものか検証した上で # 自分の持つチェインと比較し優位な方を今後のブロックチェーンとして有効化する new_block_chain = pickle.loads(msg[4].encode('utf-8')) print(new_block_chain) result, pool_4_orphan_blocks = self.bm.resolve_conflicts( new_block_chain) print('blockchain received') if result is not None: self.prev_block_hash = result if len(pool_4_orphan_blocks) != 0: # orphanブロック群の中にあった未処理扱いになるTransactionをTransactionPoolに戻す new_transactions = self.bm.get_transactions_from_orphan_blocks( pool_4_orphan_blocks) for t in new_transactions: self.tp.set_new_transaction(t) else: print('Received blockchain is useless...') # self.main_window.set_chain(self.bm.chain) elif msg[2] == MSG_ENHANCED: # P2P Network を単なるトランスポートして使っているアプリケーションが独自拡張したメッセージはここで処理する。SimpleBitcoin としてはこの種別は使わない # self.mpmh.handle_message(msg[4]) print("MSG_ENHANCED") print("") print("保存!!>!>!>!>!>!>!>!>!>!>>>!>!") print(self.bm.chain) print("保存!!>!>!>!>!>!>!>!>!>!>>>!>!") print("") def __get_myip(self): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) return s.getsockname()[0]
class ServerCore: def __init__(self, my_port=50082, core_node_host=None, core_node_port=None): self.server_state = STATE_INIT print('Initializing server...') self.my_ip = self.__get_myip() print('Server IP address is set to ... ', self.my_ip) self.my_port = my_port self.cm = ConnectionManager(self.my_ip, self.my_port, self.__handle_message) self.mpm = MyProtocolMessageHandler() self.core_node_host = core_node_host self.core_node_port = core_node_port self.my_protocol_message_store = [] def start(self): """ Coreノードとしての待受を開始する(上位UI層向け """ self.server_state = STATE_STANDBY self.cm.start() def join_network(self): """ 事前に取得した情報に従い拠り所となる他のCoreノードに接続する(上位UI層向け """ if self.core_node_host is not None: self.server_state = STATE_CONNECTED_TO_NETWORK self.cm.join_network(self.core_node_host, self.core_node_port) else: print('This server is runnning as Genesis Core Node...') def shutdown(self): """ 待ち受け状態のServer Socketを閉じて終了する(上位UI層向け """ self.server_state = STATE_SHUTTING_DOWN print('Shutdown server...') self.cm.connection_close() def get_my_current_state(self): """ 現在のCoreノードの状態を取得する(上位UI層向け。多分使う人いない """ return self.server_state def __core_api(self, request, message): """ MyProtocolMessageHandlerで呼び出すための拡張関数群(現状未整備) params: request : MyProtocolMessageHandlerから呼び出されるコマンドの種別 message : コマンド実行時に利用するために引き渡されるメッセージ """ msg_type = MSG_ENHANCED if request == 'send_message_to_all_peer': new_message = self.cm.get_message_text(msg_type, message) self.cm.send_msg_to_all_peer(new_message) return 'ok' elif request == 'send_message_to_all_edge': new_message = self.cm.get_message_text(msg_type, message) self.cm.send_msg_to_all_edge(new_message) return 'ok' elif request == 'api_type': return 'server_core_api' def __handle_message(self, msg, peer=None): """ ConnectionManagerに引き渡すコールバックの中身。 """ if peer is not None: # TODO: 現状はMSG_REQUEST_FULL_CHAINの時にしかこの処理に入らないけど、 # まだブロックチェーンを作るところまで行ってないのでとりあえず口だけ作っておく print('Send our latest blockchain for reply to : ', peer) else: if msg[2] == MSG_NEW_TRANSACTION: # TODO: 新規transactionを登録する処理を呼び出す pass elif msg[2] == MSG_NEW_BLOCK: # TODO: 新規ブロックを検証する処理を呼び出す pass elif msg[2] == RSP_FULL_CHAIN: # TODO: ブロックチェーン送信要求に応じて返却されたブロックチェーンを検証する処理を呼び出す pass elif msg[2] == MSG_ENHANCED: # P2P Network を単なるトランスポートして使っているアプリケーションが独自拡張したメッセージはここで処理する。 # SimpleBitcoin としてはこの種別は使わない # あらかじめ重複チェック(ポリシーによる。別にこの処理しなくてもいいかも print('received enhanced message', msg[4]) current_messages = self.my_protocol_message_store has_same = False if not msg[4] in current_messages: self.my_protocol_message_store.append(msg[4]) self.mpm.handle_message(msg[4], self.__core_api) def __get_myip(self): """ Google先生から自分のIPアドレスを取得する。内部利用のみを想定 """ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) return s.getsockname()[0]
class ServerCore(object): def __init__(self, my_port=50082, core_node_host=None, core_node_port=None): self.server_state = STATE_INIT print('Initializing server...') self.my_ip = self.__get_myip() print('Server IP address is set to ... ', self.my_ip) self.my_port = my_port self.cm = ConnectionManager(self.my_ip, self.my_port, self.__handle_message, self) self.mpmh = MyProtocolMessageHandler() self.core_node_host = core_node_host self.core_node_port = core_node_port self.bb = BlockBuilder() self.flag_stop_block_build = True self.is_bb_running = False if main_level.get_genesis(LDB_P): self.bm = BlockchainManager() latest_dbd_block = main_level.get_latest_block(LDB_P) self.prev_block_hash = self.bm.get_hash(latest_dbd_block) block_num = level_param.get_block_num(PARAM_P) + len(self.bm.chain) new_block = self.bb.generate_new_block({}, self.prev_block_hash, str(block_num), ADDRESS, {}, self) self.bm.set_reconnect_block(new_block.to_dict()) self.prev_block_hash = self.bm.get_hash(new_block.to_dict()) else: my_genesis_block = self.bb.generate_genesis_block() self.bm = BlockchainManager(my_genesis_block.to_dict()) self.prev_block_hash = self.bm.get_hash(my_genesis_block.to_dict()) self.tp = TransactionPool() if core_node_host and core_node_port: self.plz_share_db() else: self.flag_stop_block_build = False def start_block_building(self): if RAND_INTERVAL: CHECK_INTERVAL = randint(39, 60) else: CHECK_INTERVAL = INTERVAL self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() def stop_block_building(self): print('Thread for __generate_block_with_tp is stopped now') self.bb_timer.cancel() def start(self): self.server_state = STATE_STANDBY self.cm.start() self.start_block_building() def join_network(self): if self.core_node_host is not None: self.server_state = STATE_CONNECTED_TO_NETWORK # 状態:親ノードへ接続中 self.cm.join_network(self.core_node_host, self.core_node_port) else: print('This server is running as Genesis Core Node...') def shutdown(self): self.server_state = STATE_SHUTTING_DOWN # 状態:切断中 print('Shutdown server...') self.cm.connection_close() self.stop_block_building() def get_my_current_state(self): return self.server_state def plz_share_db(self): print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") print("■■■■■■■■■■■■■■■■■■■■ plz_share_db ■■■■■■■■■■■■■■■■■■■■■■") print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") new_message = self.cm.get_message_text(SHARE_DB3) self.cm.send_msg((self.core_node_host, self.core_node_port), new_message) print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") def get_all_chains_for_resolve_conflict(self): print('get_all_chains_for_resolve_conflict called') new_message = self.cm.get_message_text(MSG_REQUEST_FULL_CHAIN) self.cm.send_msg_to_all_peer(new_message) # def save_block_2_db(self): # # if self.is_bb_running: # # self.flag_stop_block_build = True # saved_bc = [] # # if len(self.bm.chain) >= SAVE_BORDER: # saved_bc = self.bm.chain[:SAVE_BORDER_HALF] # self.bm.chain = self.bm.chain[SAVE_BORDER_HALF:] # main_level.add_db(ldb_p=LDB_P, param_p=PARAM_P, zip_p=ZIP_P, vals=saved_bc) # print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") # print("保存しました") # print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") # # # self.flag_stop_block_build = False def __generate_block_with_tp(self): if DEBUG: print('Thread for generate_block_with_tp started!') try: if RAND_INTERVAL: CHECK_INTERVAL = randint(39, 60) else: CHECK_INTERVAL = INTERVAL print( "■■■■■■■■■■■■■■■■■■■ Current BC ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■" ) print(self.bm.chain) # self.save_block_2_db() saved_bcs = self.bm.save_block_2_db() print("txs_hash len:", self.tp.get_txs_hash_len()) print("txs_hash:", self.tp.get_txs_hash()) # txs_hash = self.tp.get_txs_hash().values() # for t in txs_hash: # print(f"addrs:{t} / len:{len(t)}") if saved_bcs: prev_ts = 0.0 ts_list = [] for saved_bc in saved_bcs: # genesis_blockはトランザクションがハッシュ値なのでloadsできない try: self.tp.clear_my_hash_txs( json.loads(saved_bc["transactions"])) except json.decoder.JSONDecodeError: pass if prev_ts == 0.0: prev_ts = saved_bc["timestamp"] else: ts_list.append(saved_bc["timestamp"] - prev_ts) prev_ts = saved_bc["timestamp"] print("■■■■■■■■■■■■■■■■■■■") print("平均ブロック生成時間") print(sum(ts_list) / len(saved_bcs)) print("■■■■■■■■■■■■■■■■■■■") print("txs_hash len:", self.tp.get_txs_hash_len()) # print("txs_hash:", self.tp.get_txs_hash()) # while self.flag_stop_block_build is not True: if self.flag_stop_block_build is not True: # new_tp = self.tp.get_stored_transactions2() # new_tp = deepcopy(self.tp.transactions) new_tp = self.tp.get_stored_transactions3() if DEBUG: print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") print("transactions", new_tp) print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") # if not result: # print('Transaction Pool is empty ...') # new_block = self.bb.generate_new_block("", self.prev_block_hash) # self.bm.set_new_block(new_block.to_dict()) # self.prev_block_hash = self.bm.get_hash(new_block.to_dict()) # # message_new_block = self.cm.get_message_text(MSG_NEW_BLOCK, # # json.dumps(new_block.to_dict(), sort_keys=True, # # ensure_ascii=False)) # message_new_block = self.cm.get_message_text(MSG_NEW_BLOCK, json.dumps(new_block.to_dict())) # self.cm.send_msg_to_all_peer(message_new_block) # index = len(result) # self.tp.clear_my_transactions(index) # new_tp = self.bm.remove_useless_transaction(result) # self.tp.renew_my_transactions(new_tp) # if len(new_tp) == 0: # TODO TPが0のとき、終わるように。コメントアウトで切り替え # break # TODO ここでiteration errorでる。値変わってるせい。 txs_hash = self.tp.get_txs_hash() block_num = level_param.get_block_num(PARAM_P) + len( self.bm.chain) new_block = self.bb.generate_new_block(new_tp, self.prev_block_hash, str(block_num), ADDRESS, txs_hash, self) new_block_dic = new_block.to_dict() if not new_block_dic: print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") print("■■■■■■■■■■■■■■ 負け!w ■■■■■■■■■■■■■■■") print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") self.flag_stop_block_build = False self.is_bb_running = False self.bb_timer = threading.Timer( CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() return elif int(new_block_dic["block_number"]) < int( self.bm.chain[-1]["block_number"]): print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") print("■■■■■■■■■■■■■■ YOU LOSE ■■■■■■■■■■■■■■■") print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") self.flag_stop_block_build = False self.is_bb_running = False self.bb_timer = threading.Timer( CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() return # elif (int(new_block_dic["block_number"]) == int(self.bm.chain[-1]["block_number"])) and ( # new_block_dic["total_majority"] <= self.bm.chain[-1]["total_majority"]): # print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") # print("■■■■■■■■■■■■■■ u r 少数派 ■■■■■■■■■■■■■■") # print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■") # self.flag_stop_block_build = False # self.is_bb_running = False # self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) # self.bb_timer.start() # return print("ブロック生成") print(new_block_dic) if len(self.bm.chain) >= 2: print("ブロック生成時間") print( self.__calculate_gene_time(self.bm.chain[-2], self.bm.chain[-1])) if self.bm.set_new_block(new_block.to_dict(), self.prev_block_hash): self.prev_block_hash = self.bm.get_hash( new_block.to_dict()) # self.save_block_2_db() message_new_block = self.cm.get_message_text( MSG_NEW_BLOCK, json.dumps(new_block.to_dict())) self.cm.send_msg_to_all_peer(message_new_block) # index = len(result) # self.tp.clear_my_transactions(index) # 排除対象になったtxを取り込み済みtxから除く exclusion_txs = new_block.get_exclusion_tx() for ex_tx in exclusion_txs: try: del new_tp[ex_tx] except KeyError: pass self.tp.add_through_count(exclusion_txs) self.tp.clear_my_transactions2(new_tp) with open(f'logs/{ADDRESS}_generate_block.csv', 'a') as f: writer = csv.writer(f) writer.writerow([ datetime.now(), new_block_dic["block_number"], # new_block_dic["total_majority"], new_block_dic["nTx"], # new_block_dic["over_half"], ]) # break # print('Current prev_block_hash is ... ', self.prev_block_hash) self.flag_stop_block_build = False self.is_bb_running = False self.bb_timer = threading.Timer(CHECK_INTERVAL, self.__generate_block_with_tp) self.bb_timer.start() except: with open(f"logs/{ADDRESS}_error.log", "a") as f: print(traceback.print_exc(file=f)) def __handle_message(self, msg, is_core, peer=None): if peer: if msg[2] == MSG_REQUEST_FULL_CHAIN: if DEBUG: print('Send our latest blockchain for reply to : ', peer) mychain = self.bm.get_my_blockchain() if DEBUG: print(mychain) chain_data = pickle.dumps(mychain, 0).decode() new_message = self.cm.get_message_text(RSP_FULL_CHAIN, chain_data) self.cm.send_msg(peer, new_message) else: if msg[2] == MSG_NEW_TRANSACTION: # 新規transactionを登録する処理を呼び出す new_transaction = json.loads(msg[4]) bload_tx = deepcopy(new_transaction) if DEBUG: print("received new_transaction", new_transaction) # current_transactions = self.tp.get_stored_transactions() # if DEBUG: # print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") # print("current_transactions:", current_transactions) # print("current_transactions type:", type(current_transactions)) # if current_transactions: # print("current_transactions [0]:", current_transactions[0]) # print("current_transactions [0] type:", type(current_transactions[0])) # print("new_transaction:", new_transaction) # print("new_transaction type:", type(new_transaction)) # if new_transaction: # print("new_transaction [0]:", new_transaction[0]) # print("new_transaction [0]:", type(new_transaction[0])) # print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") # if new_transaction in current_transactions: # if DEBUG: # print("this is already pooled transaction:", new_transaction) # return # only_new_tx = self.tp.check_duplicates(new_transaction) # if not only_new_tx: # return # if not self.tp.check_duplicates_and_set_tx(new_transaction): # return self.tp.check_duplicates_and_set_tx(new_transaction) # self.tp.set_new_transaction(only_new_tx) if not is_core: new_message = self.cm.get_message_text( MSG_NEW_TRANSACTION, json.dumps(bload_tx)) self.cm.send_msg_to_all_peer(new_message) elif msg[2] == MSG_NEW_BLOCK: if not is_core: print('block received from unknown') return # 新規ブロックを検証し、正当なものであればブロックチェーンに追加する new_block = json.loads(msg[4]) if DEBUG: print('new_block: ', new_block) # if (int(self.bm.chain[-1]["block_number"]) > int(new_block["block_number"])) or ( # self.bm.chain[-1]["total_majority"] >= new_block["total_majority"] and ( # int(self.bm.chain[-1]["block_number"]) == int(new_block["block_number"]))): # return if int(self.bm.chain[-1]["block_number"]) > int( new_block["block_number"]): return try: if self.bm.is_valid_block(self.prev_block_hash, new_block): # ブロック生成が行われていたら一旦停止してあげる(threadingなのでキレイに止まらない場合あり) # if self.is_bb_running: # self.flag_stop_block_build = True # self.prev_block_hash = self.bm.get_hash(new_block) # self.bm.set_new_block(new_block) if self.bm.set_new_block(new_block, self.prev_block_hash): self.prev_block_hash = self.bm.get_hash(new_block) self.tp.clear_my_transactions2( json.loads(new_block["addrs"])) with open(f'logs/{ADDRESS}_most_longest.csv', 'a') as f: writer = csv.writer(f) writer.writerow([ datetime.now(), new_block["block_number"], # new_block["total_majority"], new_block["nTx"], # new_block["over_half"], ]) # elif self.bm.is_valid_block_booby(new_block): # if (self.bm.chain[-1]["total_majority"] < new_block["total_majority"]) and (int( # self.bm.chain[-1]["block_number"]) == int(new_block["block_number"])): # deleted_block = self.bm.replace_latest_block(new_block) # if deleted_block: # self.prev_block_hash = self.bm.get_hash(new_block) # self.tp.increment_tx(deleted_block, new_block) # self.tp.clear_my_transactions2(json.loads(new_block["addrs"])) # with open(f'logs/{ADDRESS}_most_majority.csv', 'a') as f: # writer = csv.writer(f) # writer.writerow([ # datetime.now(), # new_block["block_number"], # new_block["total_majority"], # new_block["nTx"], # new_block["over_half"], # ]) else: # ブロックとして不正ではないがVerifyにコケる場合は自分がorphanブロックを生成している # 可能性がある # if self.is_bb_running: # TODO 試しで追加 # self.flag_stop_block_build = True self.get_all_chains_for_resolve_conflict() except: with open(f"logs/{ADDRESS}_error_1.log", "a") as f: print(traceback.print_exc(file=f)) elif msg[2] == RSP_FULL_CHAIN: try: if not is_core: if DEBUG: print('blockchain received from unknown') return # ブロックチェーン送信要求に応じて返却されたブロックチェーンを検証し、有効なものか検証した上で # 自分の持つチェインと比較し優位な方を今後のブロックチェーンとして有効化する new_block_chain = pickle.loads(msg[4].encode('utf8')) # if ((int(new_block_chain[-1]["block_number"]) > int(self.bm.chain[-1]["block_number"])) or ( # (int(new_block_chain[-1]["block_number"]) == int(self.bm.chain[-1]["block_number"])) and ( # new_block_chain[-1]["total_majority"] > self.bm.chain[-1]["total_majority"]))) and ( # (int(new_block_chain[0]["block_number"]) == int(self.bm.chain[0]["block_number"])) or ( # self.bm.chain[0]["block_number"] == "0") or (len(self.bm.chain) < SAVE_BORDER_HALF)): if (int(new_block_chain[-1]["block_number"]) > int( self.bm.chain[-1]["block_number"])) and ( (int(new_block_chain[0]["block_number"]) == int(self.bm.chain[0]["block_number"])) or (self.bm.chain[0]["block_number"] == "0") or (len(self.bm.chain) < SAVE_BORDER_HALF)): result, pool_4_orphan_blocks = self.bm.resolve_conflicts( new_block_chain) if result and self.cm.sync_flag: try: self.tp.justification_conflict( self.bm.chain[-6:]) except: with open(f"logs/{ADDRESS}_error_2.log", "a") as f: print(traceback.print_exc(file=f)) if DEBUG: print('blockchain received') if result is not None: self.prev_block_hash = result # if len(pool_4_orphan_blocks) != 0: # # orphanブロック群の中にあった未処理扱いになるTransactionをTransactionPoolに戻す # new_transactions = self.bm.get_transactions_from_orphan_blocks(pool_4_orphan_blocks) # for t in new_transactions: # self.tp.set_new_transaction(t) else: if DEBUG: print('Received blockchain is useless...') # self.flag_stop_block_build = False except: with open(f"logs/{ADDRESS}_error_3.log", "a") as f: print(traceback.print_exc(file=f)) elif msg[2] == MSG_ENHANCED: # P2P Network を単なるトランスポートして使っているアプリケーションが独自拡張したメッセージはここで処理する。SimpleBitcoin としてはこの種別は使わない self.mpmh.handle_message(msg[4]) def __get_myip(self): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) return s.getsockname()[0] def __calculate_gene_time(self, prev_block: dict, new_block: dict): prev_ts = prev_block["timestamp"] # prev_ts = 1587105439.753553 new_ts = new_block["timestamp"] # new_ts = 1587105451.5021372 gene_time = new_ts - prev_ts return gene_time def format_bc(self): oldest_memory_block = self.bm.chain[0] self.bm.chain = self.bm.chain[:1] self.bm.set_reconnect_block(oldest_memory_block) self.prev_block_hash = self.bm.get_hash(oldest_memory_block)