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)
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 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)
def add_tx(self, request) -> None: tx_json = request.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) 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 _makeup_block(self): block_builder = BlockBuilder.new("0.1a") tx_versions = TransactionVersions() while self._txQueue: if len(block_builder) >= conf.MAX_TX_SIZE_IN_BLOCK: logging.debug( f"consensus_base total size({len(block_builder)}) " f"count({len(block_builder.transactions)}) " f"_txQueue size ({len(self._txQueue)})") break tx: 'Transaction' = self._txQueue.get_item_in_status( TransactionStatusInQueue.normal, TransactionStatusInQueue.added_to_block) if tx is None: break tx_hash_version = tx_versions.get_hash_generator_version( tx.version) tv = TransactionVerifier.new(tx.version, tx_hash_version) try: tv.verify(tx, self._blockchain) except Exception as e: logging.warning(f"tx hash invalid. tx: {tx}") else: block_builder.transactions[tx.hash] = tx return block_builder
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 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
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)