class TxItemJson: tx_versions = TransactionVersions() tx_serializers = { "0x2": TransactionSerializer.new( "0x2", tx_versions.get_hash_generator_version("0x2")), "0x3": TransactionSerializer.new( "0x3", tx_versions.get_hash_generator_version("0x3")) } def __init__(self, tx_json: str, channel: str): self.channel = channel self.__tx_json = tx_json self.__len = sys.getsizeof(tx_json) + sys.getsizeof(channel) def __len__(self): return self.__len def get_tx_message(self): message = loopchain_pb2.TxSend(tx_json=self.__tx_json, channel=self.channel) return message @classmethod def create_tx_item(cls, tx: Transaction, channel: str): # util.logger.spam(f"tx_item_helper_icx:create_tx_item create_tx_param({create_tx_param})") tx_serializer = cls.tx_serializers[tx.version] tx_item = TxItemJson(json.dumps(tx_serializer.to_raw_data(tx)), channel) return tx_item
async def get_block_v2(self, block_height, block_hash, block_data_filter, tx_data_filter): # This is a temporary function for v2 support of exchanges. block, block_filter, block_hash, fail_response_code, tx_filter = await self.__get_block( block_data_filter, block_hash, block_height, tx_data_filter) if fail_response_code: return fail_response_code, block_hash, json.dumps({}), "" bs = BlockSerializer.new(block.header.version) block_data_dict = bs.serialize(block) if block.header.height == 0: return message_code.Response.success, block_hash, json.dumps( block_data_dict), [] confirmed_tx_list = block_data_dict["confirmed_transaction_list"] confirmed_tx_list_without_fail = [] tv = TransactionVersions() tss = { "genesis": TransactionSerializer.new( "genesis", tv.get_hash_generator_version("genesis")), "0x2": TransactionSerializer.new("0x2", tv.get_hash_generator_version("0x2")), "0x3": TransactionSerializer.new("0x3", tv.get_hash_generator_version("0x3")) } for tx in confirmed_tx_list: version = tv.get_version(tx) tx_hash = tss[version].get_hash(tx) invoke_result = self._channel_service.block_manager.get_invoke_result( tx_hash) if 'failure' in invoke_result: continue if tv.get_version(tx) == "0x3": step_used, step_price = int(invoke_result["stepUsed"], 16), int( invoke_result["stepPrice"], 16) tx["fee"] = hex(step_used * step_price) confirmed_tx_list_without_fail.append(tx) # Replace the existing confirmed_tx_list with v2 ver. block_data_dict[ "confirmed_transaction_list"] = confirmed_tx_list_without_fail block_data_json = json.dumps(block_data_dict) if fail_response_code: return fail_response_code, block_hash, json.dumps({}), [] return message_code.Response.success, block_hash, block_data_json, []
def test_hash_case_v3_escape(self): request = r'''{ "jsonrpc": "2.0", "method": "icx_sendTransaction", "id": 1234, "params": { "version": "0x3", "from": "hxbe258ceb872e08851f1f59694dac2558708ece11", "to": "cxb0776ee37f5b45bfaea8cff1d8232fbb6122ec32", "stepLimit": "0x12345", "timestamp": "0x563a6cf330136", "nonce": "0x1", "nid": "0x2", "signature": "VAia7YZ2Ji6igKWzjR2YsGa2m53nKPrfK7uXYW78QLE+ATehAVZPC40szvAiA6NEU5gCYB4c4qaQzqDh2ugcHgA=", "dataType": "call", "data": { "method": "transfer", "params": { "to": "hx.ab2d8215eab\\14bc6bdd8bfb2c[8151257]032ec{d8}b", "value": "0x1", "array0": [ "1", "2.21" ], "array1": [ { "hash": "0x12", "value": "0x34" }, { "hash": "0x56", "value": "0x78" } ] } } } }''' logging.info(f"request : {request}") request = json.loads(request) logging.info(f"request loaded : {request}") logging.info(f"to : {request['params']['data']['params']['to']}") question = request['params'] answer = r"icx_sendTransaction.data.{method.transfer.params." \ r"{array0.[1.2\.21].array1.[{hash.0x12.value.0x34}.{hash.0x56.value.0x78}]." \ r"to.hx\.ab2d8215eab\\14bc6bdd8bfb2c\[8151257\]032ec\{d8\}b.value.0x1}}." \ r"dataType.call.from.hxbe258ceb872e08851f1f59694dac2558708ece11.nid.0x2.nonce.0x1.stepLimit.0x12345." \ r"timestamp.0x563a6cf330136.to.cxb0776ee37f5b45bfaea8cff1d8232fbb6122ec32.version.0x3" tv = TransactionVersions() version = tv.get_version(question) ts = TransactionSerializer.new(version, tv.get_hash_generator_version(version)) tx = ts.from_(question) result = self.hash_generator.generate_salted_origin( ts.to_origin_data(tx)) logging.info(f"result : {result}") self.assertEqual(result, answer)
async def create_icx_tx(self, kwargs: dict): result_code = None exception = None try: tv = TransactionVersions() tx_version = tv.get_version(kwargs) tx_hash_version = self._channel_service.get_channel_option()["tx_hash_version"] ts = TransactionSerializer.new(tx_version, tx_hash_version) tx = ts.from_(kwargs) tv = TransactionVerifier.new(tx_version, tx_hash_version) tv.verify(tx) block_manager = self._channel_service.block_manager block_manager.pre_validate(tx) logging.debug(f"create icx input : {kwargs}") self._channel_service.broadcast_scheduler.schedule_job(BroadcastCommand.CREATE_TX, tx) return message_code.Response.success, tx.hash.hex() except TransactionInvalidError as e: result_code = e.message_code exception = e except BaseException as e: result_code = TransactionInvalidError.message_code exception = e finally: if exception: logging.warning(f"create_icx_tx: tx restore fail for kwargs({kwargs}), {exception}") return result_code, None
def add_tx_list(self, request) -> tuple: tx_list = [] for tx_item in request.tx_list: tx_json = json.loads(tx_item.tx_json) tx_version = self.__tx_versioner.get_version(tx_json) ts = TransactionSerializer.new(tx_version, self.__tx_versioner) tx = ts.from_(tx_json) tv = TransactionVerifier.new(tx_version, self.__tx_versioner) tv.verify(tx) tx.size(self.__tx_versioner) tx_list.append(tx) tx_len = len(tx_list) if tx_len == 0: response_code = message_code.Response.fail message = "fail tx validate while AddTxList" else: self.__tx_queue.put(tx_list) response_code = message_code.Response.success message = f"success ({len(tx_list)})/({len(request.tx_list)})" return response_code, message
def add_tx(self, request) -> None: tx_json = request.tx_json tx_versioner = self._channel_service.block_manager.get_blockchain( ).tx_versioner tx_version = tx_versioner.get_version(tx_json) ts = TransactionSerializer.new(tx_version, tx_versioner) tx = ts.from_(tx_json) tv = TransactionVerifier.new(tx_version, tx_versioner) tv.verify(tx) object_has_queue = self._channel_service.get_object_has_queue_by_consensus( ) if tx is not None: object_has_queue.add_tx_obj(tx) util.apm_event( ChannelProperty().peer_id, { 'event_type': 'AddTx', 'peer_id': ChannelProperty().peer_id, 'peer_name': conf.PEER_NAME, 'channel_name': ChannelProperty().name, 'data': { 'tx_hash': tx.tx_hash } })
def add_tx(self, request) -> None: tx_json = request.tx_json tx_versioner = self._channel_service.block_manager.get_blockchain( ).tx_versioner tx_version = tx_versioner.get_version(tx_json) ts = TransactionSerializer.new(tx_version, tx_versioner) tx = ts.from_(tx_json) tv = TransactionVerifier.new(tx_version, tx_versioner) tv.verify(tx) if tx is not None: self._channel_service.block_manager.add_tx_obj(tx) util.apm_event( ChannelProperty().peer_id, { 'event_type': 'AddTx', 'peer_id': ChannelProperty().peer_id, 'peer_name': conf.PEER_NAME, 'channel_name': ChannelProperty().name, 'data': { 'tx_hash': tx.tx_hash } }) if not conf.ALLOW_MAKE_EMPTY_BLOCK: self._channel_service.start_leader_complain_timer_if_tx_exists()
def genesis_invoke(self, block: Block) -> ('Block', dict): method = "icx_sendTransaction" transactions = [] for tx in block.body.transactions.values(): hash_version = conf.CHANNEL_OPTION[ ChannelProperty().name]["genesis_tx_hash_version"] tx_serializer = TransactionSerializer.new(tx.version, hash_version) transaction = { "method": method, "params": { "txHash": tx.hash.hex() }, "genesisData": tx_serializer.to_full_data(tx) } transactions.append(transaction) request = { 'block': { 'blockHeight': block.header.height, 'blockHash': block.header.hash.hex(), 'timestamp': block.header.timestamp }, 'transactions': transactions } request = convert_params(request, ParamType.invoke) stub = StubCollection().icon_score_stubs[ChannelProperty().name] response = stub.sync_task().invoke(request) response_to_json_query(response) block_builder = BlockBuilder.from_new(block) block_builder.commit_state = { ChannelProperty().name: response['stateRootHash'] } new_block = block_builder.build() return new_block, response["txResults"]
def get_tx_info(self, tx_hash): tx = self._channel_service.block_manager.get_tx_queue().get( tx_hash, None) if tx: blockchain = self._channel_service.block_manager.get_blockchain() tx_serializer = TransactionSerializer.new(tx.version, blockchain.tx_versioner) tx_origin = tx_serializer.to_origin_data(tx) logging.info(f"get_tx_info pending : tx_hash({tx_hash})") tx_info = dict() tx_info["transaction"] = tx_origin tx_info["tx_index"] = None tx_info["block_height"] = None tx_info["block_hash"] = None return message_code.Response.success, tx_info else: try: return message_code.Response.success, self._channel_service.block_manager.get_tx_info( tx_hash) except KeyError as e: logging.error( f"get_tx_info error : tx_hash({tx_hash}) not found error({e})" ) response_code = message_code.Response.fail_invalid_key_error return response_code, None
def test_hash_origin_case_v2(self): request = r'''{ "jsonrpc": "2.0", "method": "icx_sendTransaction", "id": 1234, "params": { "from": "hxbe258ceb872e08851f1f59694dac2558708ece11", "to": "hx5bfdb090f43a808005ffc27c25b213145e80b7cd", "value": "0xde0b6b3a7640000", "fee": "0x1000000", "timestamp": "1000000000000", "nonce": "0x1", "tx_hash": "a247a97a23398daccb66e2d61d63788b3c2edb91e1fdbb4f34d86d485eb72915", "signature": "VAia7YZ2Ji6igKWzjR2YsGa2m53nKPrfK7uXYW78QLE+ATehAVZPC40szvAiA6NEU5gCYB4c4qaQzqDh2ugcHgA=" } }''' logging.info(f"request : {request}") request = json.loads(request) logging.info(f"request loaded : {request}") question = request["params"] answer = "icx_sendTransaction.fee.0x1000000.from.hxbe258ceb872e08851f1f59694dac2558708ece11.nonce.0x1." \ "timestamp.1000000000000.to.hx5bfdb090f43a808005ffc27c25b213145e80b7cd." \ "value.0xde0b6b3a7640000" tv = TransactionVersions() version = tv.get_version(question) ts = TransactionSerializer.new(version, tv.get_hash_generator_version(version)) tx = ts.from_(question) result = self.hash_generator.generate_salted_origin( ts.to_origin_data(tx)) self.assertEqual(result, answer)
def score_invoke(self, _block: Block) -> dict or None: method = "icx_sendTransaction" transactions = [] for tx in _block.body.transactions.values(): tx_serializer = TransactionSerializer.new(tx.version, self.block_manager.get_blockchain().tx_versioner) transaction = { "method": method, "params": tx_serializer.to_full_data(tx) } transactions.append(transaction) request = { 'block': { 'blockHeight': _block.header.height, 'blockHash': _block.header.hash.hex(), 'prevBlockHash': _block.header.prev_hash.hex() if _block.header.prev_hash else '', 'timestamp': _block.header.timestamp }, 'transactions': transactions } request = convert_params(request, ParamType.invoke) stub = StubCollection().icon_score_stubs[ChannelProperty().name] response = stub.sync_task().invoke(request) response_to_json_query(response) block_builder = BlockBuilder.from_new(_block, self.__block_manager.get_blockchain().tx_versioner) block_builder.commit_state = { ChannelProperty().name: response['stateRootHash'] } new_block = block_builder.build() return new_block, response["txResults"]
async def create_icx_tx(self, kwargs: dict): if self.__qos_controller.limit(): util.logger.debug(f"Out of TPS limit. tx={kwargs}") return message_code.Response.fail_out_of_tps_limit, None node_type = self.__properties.get('node_type', None) if node_type is None: util.logger.warning("Node type has not been set yet.") return NodeInitializationError.message_code, None elif node_type != conf.NodeType.CommunityNode.value: return message_code.Response.fail_no_permission, None result_code = None exception = None tx = None try: tx_version = self.__tx_versioner.get_version(kwargs) ts = TransactionSerializer.new(tx_version, self.__tx_versioner) tx = ts.from_(kwargs) nid = self.__properties.get('nid', None) if nid is None: util.logger.warning(f"NID has not been set yet.") raise NodeInitializationError(tx.hash.hex()) tv = TransactionVerifier.new(tx_version, self.__tx_versioner) tv.pre_verify(tx, nid=nid) self.__pre_validate(tx) logging.debug(f"create icx input : {kwargs}") self.__broadcast_scheduler.schedule_job(BroadcastCommand.CREATE_TX, (tx, self.__tx_versioner)) return message_code.Response.success, tx.hash.hex() except MessageCodeError as e: result_code = e.message_code exception = e traceback.print_exc() except BaseException as e: result_code = TransactionInvalidError.message_code exception = e traceback.print_exc() finally: if exception: logging.warning(f"create_icx_tx: tx restore fail.\n\n" f"kwargs({kwargs})\n\n" f"tx({tx})\n\n" f"exception({exception})") return result_code, None
def __add_tx_to_block_db(self, block, invoke_results): """block db 에 block_hash - block_object 를 저장할때, tx_hash - block_hash 를 저장한다. get tx by tx_hash 시 해당 block 을 효율적으로 찾기 위해서 :param block: """ # loop all tx in block logging.debug("try add all tx in block to block db, block hash: " + block.header.hash.hex()) block_manager = ObjectManager().channel_service.block_manager tx_queue = block_manager.get_tx_queue() # util.logger.spam(f"blockchain:__add_tx_to_block_db::tx_queue : {tx_queue}") # util.logger.spam( # f"blockchain:__add_tx_to_block_db::confirmed_transaction_list : {block.confirmed_transaction_list}") tx_hash_version = conf.CHANNEL_OPTION[ self.__channel_name]["tx_hash_version"] for index, tx in enumerate(block.body.transactions.values()): tx_hash = tx.hash.hex() invoke_result = invoke_results[tx_hash] tx_serializer = TransactionSerializer.new(tx.version, tx_hash_version) tx_info = { 'block_hash': block.header.hash.hex(), 'block_height': block.header.height, 'tx_index': hex(index), 'transaction': tx_serializer.to_raw_data(tx), 'result': invoke_result } self.__confirmed_block_db.Put( tx_hash.encode(encoding=conf.HASH_KEY_ENCODING), json.dumps(tx_info).encode(encoding=conf.PEER_DATA_ENCODING)) # try: # util.logger.spam( # f"blockchain:__add_tx_to_block_db::{tx_hash}'s status : {tx_queue.get_item_status(tx_hash)}") # except KeyError as e: # util.logger.spam(f"__add_tx_to_block_db :: {e}") tx_queue.pop(tx_hash, None) # util.logger.spam(f"pop tx from queue:{tx_hash}") if block.header.height > 0: self.__save_tx_by_address_strategy(tx) self.__save_invoke_result_block_height(block.header.height)
def genesis_invoke(self, block: Block) -> ('Block', dict): method = "icx_sendTransaction" transactions = [] for tx in block.body.transactions.values(): tx_serializer = TransactionSerializer.new( tx.version, self.block_manager.get_blockchain().tx_versioner) transaction = { "method": method, "params": { "txHash": tx.hash.hex() }, "genesisData": tx_serializer.to_full_data(tx) } transactions.append(transaction) request = { 'block': { 'blockHeight': block.header.height, 'blockHash': block.header.hash.hex(), 'timestamp': block.header.timestamp }, 'transactions': transactions } request = convert_params(request, ParamType.invoke) stub = StubCollection().icon_score_stubs[ChannelProperty().name] response = stub.sync_task().invoke(request) response_to_json_query(response) tx_receipts = response["txResults"] block_builder = BlockBuilder.from_new( block, self.block_manager.get_blockchain().tx_versioner) block_builder.reset_cache() block_builder.peer_id = block.header.peer_id block_builder.signature = block.header.signature block_builder.commit_state = { ChannelProperty().name: response['stateRootHash'] } block_builder.state_hash = Hash32( bytes.fromhex(response['stateRootHash'])) block_builder.receipts = tx_receipts block_builder.reps = self.get_rep_ids() new_block = block_builder.build() return new_block, tx_receipts
def add_tx_list(self, request) -> tuple: tx_validate_count = 0 for tx_item in request.tx_list: tx_json = json.loads(tx_item.tx_json) tv = TransactionVersions() tx_version = tv.get_version(tx_json) tx_hash_version = self._channel_service.get_channel_option( )["tx_hash_version"] ts = TransactionSerializer.new(tx_version, tx_hash_version) tx = ts.from_(tx_json) tv = TransactionVerifier.new(tx_version, tx_hash_version) tv.verify(tx) # util.logger.spam(f"channel_inner_service:add_tx tx({tx.get_data_string()})") object_has_queue = self._channel_service.get_object_has_queue_by_consensus( ) if tx is not None: object_has_queue.add_tx_obj(tx) tx_validate_count += 1 util.apm_event( ChannelProperty().peer_id, { 'event_type': 'AddTx', 'peer_id': ChannelProperty().peer_id, 'peer_name': conf.PEER_NAME, 'channel_name': ChannelProperty().name, 'data': { 'tx_hash': tx.hash.hex() } }) if tx_validate_count == 0: response_code = message_code.Response.fail message = "fail tx validate while AddTxList" else: response_code = message_code.Response.success message = f"success ({tx_validate_count})/({len(request.tx_list)})" return response_code, message
async def create_icx_tx(self, kwargs: dict): result_code = None exception = None tx = None try: tx_versioner = self._channel_service.block_manager.get_blockchain( ).tx_versioner tx_version = tx_versioner.get_version(kwargs) ts = TransactionSerializer.new(tx_version, tx_versioner) tx = ts.from_(kwargs) tv = TransactionVerifier.new(tx_version, tx_versioner) tv.verify(tx) block_manager = self._channel_service.block_manager block_manager.pre_validate(tx) logging.debug(f"create icx input : {kwargs}") self._channel_service.broadcast_scheduler.schedule_job( BroadcastCommand.CREATE_TX, (tx, tx_versioner)) return message_code.Response.success, tx.hash.hex() except TransactionInvalidError as e: result_code = e.message_code exception = e traceback.print_exc() except BaseException as e: result_code = TransactionInvalidError.message_code exception = e traceback.print_exc() finally: if exception: logging.warning(f"create_icx_tx: tx restore fail.\n\n" f"kwargs({kwargs})\n\n" f"tx({tx})\n\n" f"exception({exception})") return result_code, None
def find_tx_by_key(self, tx_hash_key): """find tx by hash :param tx_hash_key: tx hash :return None: There is no tx by hash or transaction object. """ try: tx_info_json = self.find_tx_info(tx_hash_key) except KeyError as e: # This case is not an error. # Client send wrong tx_hash.. # logging.warning(f"[blockchain::find_tx_by_key] Transaction is pending. tx_hash ({tx_hash_key})") return None if tx_info_json is None: logging.warning(f"tx not found. tx_hash ({tx_hash_key})") return None tx_data = tx_info_json["transaction"] tx_version = self.tx_versioner.get_version(tx_data) tx_serializer = TransactionSerializer.new(tx_version, self.tx_versioner) return tx_serializer.from_(tx_data)
def get_serializer(cls, tx: Transaction, tx_versioner: TransactionVersioner): if tx.version not in cls.tx_serializers: cls.tx_serializers[tx.version] = TransactionSerializer.new( tx.version, tx_versioner) return cls.tx_serializers[tx.version]
def test_block_v0_3(self): private_auth = test_util.create_default_peer_auth() tx_versioner = TransactionVersioner() dummy_receipts = {} block_builder = BlockBuilder.new("0.3", tx_versioner) for i in range(1000): tx_builder = TransactionBuilder.new("0x3", tx_versioner) tx_builder.private_key = private_auth.private_key tx_builder.to_address = ExternalAddress.new() tx_builder.step_limit = random.randint(0, 10000) tx_builder.value = random.randint(0, 10000) tx_builder.nid = 2 tx = tx_builder.build() tx_serializer = TransactionSerializer.new(tx.version, tx_versioner) block_builder.transactions[tx.hash] = tx dummy_receipts[tx.hash.hex()] = { "dummy_receipt": "dummy", "tx_dumped": tx_serializer.to_full_data(tx) } block_builder.peer_private_key = private_auth.private_key block_builder.height = 0 block_builder.state_hash = Hash32(bytes(Hash32.size)) block_builder.receipts = dummy_receipts block_builder.reps = [ ExternalAddress.fromhex_address(private_auth.address) ] block_builder.next_leader = ExternalAddress.fromhex( "hx00112233445566778899aabbccddeeff00112233") block = block_builder.build() block_verifier = BlockVerifier.new("0.3", tx_versioner) block_verifier.invoke_func = lambda b: (block, dummy_receipts) block_verifier.verify(block, None, None, block.header.peer_id, reps=block_builder.reps) block_serializer = BlockSerializer.new("0.3", tx_versioner) block_serialized = block_serializer.serialize(block) block_deserialized = block_serializer.deserialize(block_serialized) assert block.header == block_deserialized.header # FIXME : confirm_prev_block not serialized # assert block.body == block_deserialized.body tx_hashes = list(block.body.transactions) tx_index = random.randrange(0, len(tx_hashes)) block_prover = BlockProver.new(block.header.version, tx_hashes, BlockProverType.Transaction) tx_proof = block_prover.get_proof(tx_index) assert block_prover.prove(tx_hashes[tx_index], block.header.transaction_hash, tx_proof) block_prover = BlockProver.new(block.header.version, block_builder.receipts, BlockProverType.Receipt) receipt_proof = block_prover.get_proof(tx_index) receipt_hash = block_prover.to_hash32(block_builder.receipts[tx_index]) assert block_prover.prove(receipt_hash, block.header.receipt_hash, receipt_proof)
def test_hash_case_v2_v3_compatibility(self): # These methods are obsolete. # But this one and new one must have same results for v2 request. def create_origin_for_hash(json_data: dict): def gen_origin_str(json_data: dict): ordered_keys = list(json_data) ordered_keys.sort() for key in ordered_keys: yield key if isinstance(json_data[key], str): yield json_data[key] elif isinstance(json_data[key], dict): yield from gen_origin_str(json_data[key]) elif isinstance(json_data[key], int): yield str(json_data[key]) else: raise TypeError( f"{key} must be one of them(dict, str, int).") origin = ".".join(gen_origin_str(json_data)) return origin def generate_icx_hash(icx_origin_data, tx_hash_key): copy_tx = copy.deepcopy(icx_origin_data) if 'method' in copy_tx: del copy_tx['method'] if 'signature' in copy_tx: del copy_tx['signature'] if tx_hash_key in copy_tx: del copy_tx[tx_hash_key] origin = create_origin_for_hash(copy_tx) origin = f"icx_sendTransaction.{origin}" # gen hash return hashlib.sha3_256(origin.encode()).digest() request = r'''{ "jsonrpc": "2.0", "method": "icx_sendTransaction", "id": 1234, "params": { "version": "0x3", "from": "hxbe258ceb872e08851f1f59694dac2558708ece11", "to": "hx5bfdb090f43a808005ffc27c25b213145e80b7cd", "value": "0xde0b6b3a7640000", "timestamp": "0x563a6cf330136", "nonce": "0x1", "stepLimit": "0x100000", "nid": "0x2", "signature": "VAia7YZ2Ji6igKWzjR2YsGa2m53nKPrfK7uXYW78QLE+ATehAVZPC40szvAiA6NEU5gCYB4c4qaQzqDh2ugcHgA=" } }''' logging.info(f"request : {request}") request = json.loads(request) logging.info(f"request loaded : {request}") question = request["params"] tv = TransactionVersions() version = tv.get_version(question) ts = TransactionSerializer.new(version, tv.get_hash_generator_version(version)) tx = ts.from_(question) result_new_hash = self.hash_generator.generate_hash( ts.to_origin_data(tx)) result_old_hash = generate_icx_hash(question, "tx_hash") self.assertEqual(result_new_hash, result_old_hash) v0_hash_generator = build_hash_generator(0, "icx_sendTransaction") result_old_hash = v0_hash_generator.generate_hash( ts.to_origin_data(tx)) self.assertEquals(result_new_hash, result_old_hash)