def _get_transaction_data_for_verification(self, domain_id, transaction_id): """Get transaction object and verify it""" txobjs, asts = self.networking.domains[domain_id][ 'data'].search_transaction(transaction_id=transaction_id) if transaction_id not in txobjs: return None txobj = txobjs[transaction_id] if txobj.WITH_WIRE: self.logger.info( "To use cross_reference the transaction object must not be in bson/msgpack format" ) return None txobj_is_valid, valid_assets, invalid_assets = bbclib.validate_transaction_object( txobj, asts) if not txobj_is_valid: msg = { KeyType.command: repair_manager.RepairManager.REQUEST_REPAIR_TRANSACTION, KeyType.transaction_id: transaction_id, } self.networking.domains[domain_id]['repair'].put_message(msg) return None txobj.digest() cross_ref_dat = txobj.cross_ref.pack() sigdata = txobj.signatures[0].pack() return txobj.transaction_base_digest, cross_ref_dat, sigdata
def _receive_transaction_data_from_others(self, dat): """Receive transaction data from other core_nodes and check its validity Args: dat (dict): received message """ #print("_receive_transaction_data_from_others:") if KeyType.transaction_data not in dat or KeyType.transaction_id not in dat or KeyType.nonce not in dat: return if dat[KeyType.nonce] not in self.requesting_list: return asset_files = dict() if KeyType.all_asset_files in dat: asset_files = dat[KeyType.all_asset_files] txobj, fmt_type = bbclib.deserialize(dat[KeyType.transaction_data]) if txobj.transaction_data is None: return txobj_is_valid, valid_assets, invalid_assets = bbclib.validate_transaction_object( txobj, asset_files) if txobj_is_valid: self.stats.update_stats_increment("transaction", "success_repair", 1) for idx in range(len(self.data_handler.db_adaptors)): self.data_handler.restore_transaction_data( db_num=idx, transaction_id=txobj.transaction_id, txobj=txobj) add_info = { "repaired_by": dat[KeyType.source_node_id].hex(), "repaired_at": int(time.time()) } self.requesting_list[dat[KeyType.nonce]].update(add_info) self._output_log(self.requesting_list[dat[KeyType.nonce]]) del self.requesting_list[dat[KeyType.nonce]]
def _send_asset_file(self, dat): """Send the asset file if having valid one Args: dat (dict): received message """ #print("_send_asset_file::") asset_group_id = dat[KeyType.asset_group_id] asset_id = dat[KeyType.asset_id] asset_file = self.data_handler.get_in_storage(asset_group_id, asset_id) if asset_file is None: return result_txobj, result_asset_files = self.data_handler.search_transaction( asset_group_id=asset_group_id, asset_id=asset_id) txobj = next(iter(result_txobj.values())) txobj_is_valid, valid_assets, invalid_assets = bbclib.validate_transaction_object( txobj, result_asset_files) if (asset_group_id, asset_id) in valid_assets: dat[KeyType.command] = RepairManager.RESPONSE_ASSET_FILE dat[KeyType.asset_group_id] = asset_group_id dat[KeyType.asset_id] = asset_id dat[KeyType.asset_file] = asset_file dat[KeyType.destination_node_id] = dat[KeyType.source_node_id] self.network.send_message_in_network(None, domain_id=self.domain_id, msg=dat)
def test_03_transaction_len_custom(self): print("\n-----", sys._getframe().f_code.co_name, "-----") id_length = { "transaction_id": 24, "asset_group_id": 6, "user_id": 8, "asset_id": 16, "nonce": 9 } make_transactions(id_len_conf=id_length) for i in range(0, 20): print("txdata_len: %d" % len(txdata[i])) digest = txdata_deserialized[i].digest() #print("transaction_id_len: %d" % len(txdata_deserialized[i].transaction_id)) #print("asset_group_id_len: %d" % len(txdata_deserialized[i].relations[0].asset_group_id)) #print("user_id_len: %d" % len(txdata_deserialized[i].relations[0].asset.user_id)) #print("asset_id_len: %d" % len(txdata_deserialized[i].relations[0].asset.asset_id)) assert len(txdata_deserialized[i].transaction_id ) == id_length["transaction_id"] assert len(txdata_deserialized[i].relations[0].asset_group_id ) == id_length["asset_group_id"] assert len(txdata_deserialized[i].relations[0].asset.user_id ) == id_length["user_id"] assert len(txdata_deserialized[i].relations[0].asset.asset_id ) == id_length["asset_id"] ret = txdata_deserialized[i].signatures[0].verify( digest, pubkey=keypair1.public_key) assert ret ret, _, _ = validate_transaction_object(txdata_deserialized[i]) assert ret print(txdata_deserialized[19])
def _receive_asset_file_from_others(self, dat): """Receive asset file from other core_nodes and check its validity Args: dat (dict): received message """ #print("_receive_asset_file_from_others:") if KeyType.nonce not in dat or dat[KeyType.nonce] not in self.requesting_list: return if KeyType.asset_group_id not in dat or KeyType.asset_id not in dat or KeyType.asset_file not in dat: return asset_group_id = dat[KeyType.asset_group_id] asset_id = dat[KeyType.asset_id] asset_file = dat[KeyType.asset_file] if asset_file is None: return asset_files = {asset_id: asset_file} result_txobj, result_asset_files = self.data_handler.search_transaction(asset_group_id=asset_group_id, asset_id=asset_id) txobj = next(iter(result_txobj.values())) txobj_is_valid, valid_assets, invalid_assets = bbclib.validate_transaction_object(txobj, asset_files) if (asset_group_id, asset_id) in valid_assets: self.data_handler.store_in_storage(asset_group_id, asset_id, asset_file, do_overwrite=True) add_info = { "repaired_by": dat[KeyType.source_node_id].hex(), "repaired_at": int(time.time()) } self.requesting_list[dat[KeyType.nonce]].update(add_info) self._output_log(self.requesting_list[dat[KeyType.nonce]]) del self.requesting_list[dat[KeyType.nonce]]
def _repair_transaction_data(self, transaction_id): """Repair forged transaction_data or asset_file by getting legitimate one from other nodes Args: transaction_id (bytes): target transaction_id """ #print("_repair_transaction_data:") self.stats.update_stats_increment("transaction", "repair_request", 1) forged_asset_files = set() if len(self.data_handler.db_adaptors) > 1: valid_txobj = None db_nums_with_invalid_data = list() for idx in range(1, len(self.data_handler.db_adaptors)): result_txobj, result_asset_files = self.data_handler.search_transaction(transaction_id=transaction_id, db_num=idx) txobj_is_valid, valid_assets, invalid_assets = bbclib.validate_transaction_object(result_txobj[0], result_asset_files) if txobj_is_valid and valid_txobj is None: valid_txobj = result_txobj[0] if not txobj_is_valid: db_nums_with_invalid_data.append(idx) if len(invalid_assets) > 0: for ent in invalid_assets: forged_asset_files.add(ent) if valid_txobj is None: self.stats.update_stats_increment("transaction", "fail_to_repair_in_local", 1) self.logger.fatal("Failed to repair transaction locally (transaction_id=%s in domain=%s)" % (transaction_id.hex(), self.domain_id.hex())) else: for i in db_nums_with_invalid_data: self.data_handler.restore_transaction_data(db_num=i, transaction_id=transaction_id, txobj=valid_txobj) self.stats.update_stats_increment("transaction", "success_repair", 1) self._output_log({"transaction_id": transaction_id.hex(), "request_at": int(time.time()), "repaired_by": "locally", "repaired_at": int(time.time())}) if len(forged_asset_files) > 0: for asgid, ast in forged_asset_files: self._repair_asset_file(asset_group_id=asgid, asset_id=ast, need_check=False) if self.data_handler.replication_strategy == DataHandler.REPLICATION_EXT: return random_nonce = bbclib.get_random_value(4) while random_nonce in self.requesting_list: random_nonce = bbclib.get_random_value(4) self.requesting_list[random_nonce] = { "transaction_id": transaction_id.hex(), "request_at": int(time.time()) } msg = { KeyType.domain_id: self.domain_id, KeyType.infra_msg_type: InfraMessageCategory.CATEGORY_DATA, KeyType.infra_command: DataHandler.REPAIR_TRANSACTION_DATA, KeyType.command: RepairManager.REQUEST_TO_SEND_TRANSACTION_DATA, KeyType.transaction_id: transaction_id, KeyType.nonce: random_nonce, } self.network.broadcast_message_in_network(domain_id=self.domain_id, payload_type=PayloadType.Type_any, msg=msg) return
def _send_transaction_data(self, dat): """Send transaction data if having valid one""" #print("_send_transaction_data::") transaction_id = dat[KeyType.transaction_id] for idx in range(len(self.data_handler.db_adaptors)): result_txobj, result_asset_files = self.data_handler.search_transaction(transaction_id=transaction_id, db_num=idx) txobj_is_valid, valid_assets, invalid_assets = bbclib.validate_transaction_object(result_txobj[transaction_id]) if txobj_is_valid: dat[KeyType.command] = RepairManager.RESPONSE_TRANSACTION_DATA dat[KeyType.transaction_data] = bbclib.serialize(result_txobj[transaction_id]) dat[KeyType.destination_node_id] = dat[KeyType.source_node_id] self.network.send_message_in_network(None, domain_id=self.domain_id, msg=dat) return
def test_03_transaction_len_12(self): print("\n-----", sys._getframe().f_code.co_name, "-----") make_transactions(idlen=12) for i in range(0, 20): print("txdata_len: %d" % len(txdata[i])) digest = txdata_deserialized[i].digest() #print("transaction_id_len: %d" % len(txdata_deserialized[i].transaction_id)) #print("asset_group_id_len: %d" % len(txdata_deserialized[i].relations[0].asset_group_id)) #print("user_id_len: %d" % len(txdata_deserialized[i].relations[0].asset.user_id)) #print("asset_id_len: %d" % len(txdata_deserialized[i].relations[0].asset.asset_id)) assert len(txdata_deserialized[i].transaction_id) == 12 assert len( txdata_deserialized[i].relations[0].asset_group_id) == 12 assert len(txdata_deserialized[i].relations[0].asset.user_id) == 12 assert len( txdata_deserialized[i].relations[0].asset.asset_id) == 12 ret = txdata_deserialized[i].signatures[0].verify(digest) assert ret ret, _, _ = validate_transaction_object(txdata_deserialized[i]) assert ret