def add_tx(self, request) -> None: tx_json = request.tx_json tx_versioner = self._blockchain.tx_versioner tx_version, tx_type = tx_versioner.get_version(tx_json) ts = TransactionSerializer.new(tx_version, tx_type, tx_versioner) tx = ts.from_(tx_json) tv = TransactionVerifier.new(tx_version, tx_type, tx_versioner) tv.verify(tx) if tx is not None: self._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()
async def relay_all_txs(self): rs_client = ObjectManager().channel_service.rs_client if not rs_client: return items = list(self.__tx_queue.d.values()) self.__tx_queue.d.clear() for item in items: tx = item.value if not util.is_in_time_boundary(tx.timestamp, conf.TIMESTAMP_BOUNDARY_SECOND, util.get_now_time_stamp()): continue ts = TransactionSerializer.new(tx.version, tx.type(), self.blockchain.tx_versioner) if tx.version == v2.version: rest_method = RestMethod.SendTransaction2 elif tx.version == v3.version: rest_method = RestMethod.SendTransaction3 else: continue raw_data = ts.to_raw_data(tx) raw_data["from_"] = raw_data.pop("from") for i in range(conf.RELAY_RETRY_TIMES): try: await rs_client.call_async( rest_method, rest_method.value.params(**raw_data)) except Exception as e: util.logger.warning(f"Relay failed. Tx({tx}), {e}") else: break
def test_transaction_v2_invalid_signature(self): # noinspection PyDictCreation tx_dumped = { 'from': 'hx48cd6eb32339d5c719dcc0af21e9bc3b67d733e6', 'to': 'hx22f72e44141bedd50d1e536455682863d3d8a484', 'value': '0x186a0', 'fee': '0xf4240', 'timestamp': '1558679280067963', 'nonce': '1', 'tx_hash': '34477b3bc76fa73aad0258ba9fd36f28a3c4b26956c1e5eb92ddda7d98df4e32', # valid hash 'signature': 'W/hW/PAo+ExeSsreD//yJVgNqmnkWKs+m0VUqE11O7Ek82yEINuczLRXtj1k515q8Ep4OLsRPPiPNjDM9vuhsgE=' } tx_dumped['signature'] = Signature(os.urandom( Signature.size)).to_base64str() # invalid signature tx_version, tx_type = self.tx_versioner.get_version(tx_dumped) ts = TransactionSerializer.new(tx_version, tx_type, self.tx_versioner) tx = ts.from_(tx_dumped) tv = TransactionVerifier.new(tx_version, tx_type, self.tx_versioner) self.assertRaises(TransactionInvalidSignatureError, lambda: tv.verify(tx)) self.assertRaises(TransactionInvalidSignatureError, lambda: tv.pre_verify(tx))
def _deserialize_body_data(self, json_data: dict): transactions = OrderedDict() for tx_data in json_data['transactions']: tx_version, tx_type = self._tx_versioner.get_version(tx_data) ts = TransactionSerializer.new(tx_version, tx_type, self._tx_versioner) tx = ts.from_(tx_data) transactions[tx.hash] = tx vote_class = BlockVotes leader_vote_class = LeaderVotes if json_data["prevVotes"]: any_vote = next(vote for vote in json_data["prevVotes"] if vote) if any_vote.get("round") is None: vote_class = v0_1a.BlockVotes leader_vote_class = v0_1a.LeaderVotes leader_votes = leader_vote_class.deserialize_votes( json_data["leaderVotes"]) prev_votes = vote_class.deserialize_votes(json_data["prevVotes"]) return { "transactions": transactions, "leader_votes": leader_votes, "prev_votes": prev_votes }
def _serialize(self, block: 'Block'): header: BlockHeader = block.header body: BlockBody = block.body transactions = [] for tx in body.transactions.values(): ts = TransactionSerializer.new(tx.version, tx.type(), self._tx_versioner) tx_serialized = ts.to_full_data(tx) transactions.append(tx_serialized) return { "version": header.version, "prevHash": header.prev_hash.hex_0x(), "transactionsHash": header.transactions_hash.hex_0x(), "stateHash": header.state_hash.hex_0x(), "receiptsHash": header.receipts_hash.hex_0x(), "repsHash": header.reps_hash.hex_0x(), "nextRepsHash": header.next_reps_hash.hex_0x(), "leaderVotesHash": header.leader_votes_hash.hex_0x(), "prevVotesHash": header.prev_votes_hash.hex_0x(), "logsBloom": header.logs_bloom.hex_0x(), "timestamp": hex(header.timestamp), "transactions": transactions, "leaderVotes": LeaderVotes.serialize_votes(body.leader_votes), "prevVotes": BlockVotes.serialize_votes(body.prev_votes), "hash": header.hash.hex_0x(), "height": hex(header.height), "leader": header.peer_id.hex_hx(), "signature": header.signature.to_base64str(), "nextLeader": header.next_leader.hex_xx(), }
async def add_tx_list(self, request) -> tuple: if self.__nid is None: response_code = message_code.Response.fail message = "Node initialization is not completed." return response_code, message tx_list = [] for tx_item in request.tx_list: tx_json = json.loads(tx_item.tx_json) tx_version, tx_type = self.__tx_versioner.get_version(tx_json) ts = TransactionSerializer.new(tx_version, tx_type, self.__tx_versioner) tx = ts.from_(tx_json) tv = TransactionVerifier.new(tx_version, tx_type, self.__tx_versioner) tv.pre_verify(tx, nid=self.__nid) 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 test_serializer_version_check(self, tx_factory: 'TxFactory'): tx: Transaction = tx_factory(self.tx_version) ts = TransactionSerializer.new(version=tx.version, type_=self.type_, versioner=tx_versioner) assert isinstance(ts, v3_issue.TransactionSerializer)
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 = TransactionVersioner() version, type_ = tv.get_version(question) ts = TransactionSerializer.new(version, type_, tv) tx = ts.from_(question) result = self.hash_generator.generate_salted_origin(ts.to_origin_data(tx)) self.assertEqual(result, answer)
def test_hash_case_v3_null(self): request = r'''{ "jsonrpc": "2.0", "method": "icx_sendTransaction", "id": 1234, "params": { "version": "0x3", "from": "hxbe258ceb872e08851f1f59694dac2558708ece11", "to": "cxb0776ee37f5b45bfaea8cff1d8232fbb6122ec32", "stepLimit": "0x12345", "timestamp": "0x563a6cf330136", "nid": "0x1", "nonce": "0x1", "signature": "VAia7YZ2Ji6igKWzjR2YsGa2m53nKPrfK7uXYW78QLE+ATehAVZPC40szvAiA6NEU5gCYB4c4qaQzqDh2ugcHgA=", "dataType": "call", "data": { "method": "transfer", "params": { "to": "hxab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", "value": "0x1", "array0": [ null, null ], "array1": [ { "hash": null, "value": null }, { "hash": null, "value": "0x78" } ] } } } }''' logging.info(f"request : {request}") request = json.loads(request) logging.info(f"request loaded : {request}") question = request["params"] answer = r"icx_sendTransaction.data.{method.transfer.params." \ r"{array0.[\0.\0].array1.[{hash.\0.value.\0}.{hash.\0.value.0x78}]." \ r"to.hxab2d8215eab14bc6bdd8bfb2c8151257032ecd8b.value.0x1}}." \ r"dataType.call.from.hxbe258ceb872e08851f1f59694dac2558708ece11.nid.0x1.nonce.0x1.stepLimit.0x12345." \ r"timestamp.0x563a6cf330136.to.cxb0776ee37f5b45bfaea8cff1d8232fbb6122ec32.version.0x3" tv = TransactionVersioner() version, type_ = tv.get_version(question) ts = TransactionSerializer.new(version, type_, tv) 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 test_get_hash(self, tx_factory: TxFactory): tx: Transaction = tx_factory(self.tx_version) ts = TransactionSerializer.new(version=tx.version, type_=tx.type(), versioner=tx_versioner) full_data = ts.to_full_data(tx) tx_hash = ts.get_hash(full_data) assert tx.hash == Hash32(tx_hash)
def test_to_full_data_equals_tx_raw_data(self, tx_factory: 'TxFactory'): tx: Transaction = tx_factory(self.tx_version) ts = TransactionSerializer.new(version=tx.version, type_=tx.type(), versioner=tx_versioner) full_data = ts.to_full_data(tx) assert full_data == tx.raw_data
def test_get_hash(self, tx_factory: TxFactory): tx: Transaction = tx_factory(self.tx_version) ts = TransactionSerializer.new(version=tx.version, type_=self.type_, versioner=tx_versioner) full_data = ts.to_full_data(tx) tx_hash = ts.get_hash(full_data) assert tx.hash == Hash32.fromhex(tx_hash, ignore_prefix=True)
def test_to_origin_data_has_valid_form(self, tx_factory: TxFactory): tx: Transaction = tx_factory(self.tx_version) ts = TransactionSerializer.new(version=tx.version, type_=self.type_, versioner=tx_versioner) origin_data = ts.to_origin_data(tx) expected_keys = ["version", "from", "to", "stepLimit", "timestamp", "nid", "value", "nonce", "signature"] assert set(origin_data) == set(expected_keys)
def test_to_db_data_equals_dict_raw_data(self, tx_factory: TxFactory): tx: Transaction = tx_factory(self.tx_version) ts = TransactionSerializer.new(version=tx.version, type_=self.type_, versioner=tx_versioner) db_data = ts.to_db_data(tx) assert db_data == tx.raw_data assert tx.raw_data == dict(tx.raw_data)
def test_to_db_data_equals_full_data(self, tx_factory: TxFactory): tx: Transaction = tx_factory(self.tx_version) ts = TransactionSerializer.new(version=tx.version, type_=tx.type(), versioner=tx_versioner) db_data = ts.to_db_data(tx) full_data = ts.to_full_data(tx) assert db_data == full_data
def test_orig_tx_equals_deserialized_tx(self, tx_factory: TxFactory): tx: Transaction = tx_factory(self.tx_version) ts = TransactionSerializer.new(version=tx.version, type_=tx.type(), versioner=tx_versioner) full_data = ts.to_full_data(tx) tx_restored = ts.from_(full_data) assert tx == tx_restored
async def create_icx_tx(self, kwargs: dict): tx_hash = None relay_target = None if self.__qos_controller.limit(): util.logger.debug(f"Out of TPS limit. tx={kwargs}") return message_code.Response.fail_out_of_tps_limit, tx_hash, relay_target 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, tx_hash, relay_target elif node_type != conf.NodeType.CommunityNode.value: relay_target = self.__properties.get('relay_target', None) return message_code.Response.fail_no_permission, tx_hash, relay_target result_code = None exception = None tx = None try: tx_version, tx_type = self.__tx_versioner.get_version(kwargs) ts = TransactionSerializer.new(tx_version, tx_type, 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, tx_type, 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(), relay_target 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, tx_hash, relay_target
def test_to_full_data_equals_to_db_data_with_tx_hash(self, tx_factory: TxFactory): tx: Transaction = tx_factory(self.tx_version) ts = TransactionSerializer.new(version=tx.version, type_=self.type_, versioner=tx_versioner) full_data = ts.to_full_data(tx) db_data = ts.to_db_data(tx) db_data["txHash"] = tx.hash.hex() assert db_data == full_data
def test_to_full_data_equals_raw_data_with_method(self, tx_factory: TxFactory): tx: Transaction = tx_factory(self.tx_version) ts = TransactionSerializer.new(version=tx.version, type_=tx.type(), versioner=tx_versioner) full_data = ts.to_full_data(tx) raw_data = ts.to_raw_data(tx) raw_data["method"] = tx.method assert full_data == raw_data
def test_to_origin_data_has_valid_form(self, tx_factory: 'TxFactory', tx_version, expected_keys): tx: Transaction = tx_factory(tx_version) ts = TransactionSerializer.new(version=tx.version, type_=tx.type(), versioner=tx_versioner) origin_data = ts.to_origin_data(tx) assert set(origin_data) == set(expected_keys)
def test_orig_tx_equals_deserialized_tx(self, tx_builder_factory: TxBuilderFactory): with freeze_time(): # TODO: origin data contains signature, so it affects tx_hash of deserialized tx. tx: genesis.Transaction = tx_builder_factory(self.tx_version)\ .build(is_signing=False) ts: genesis.TransactionSerializer = TransactionSerializer.new(version=tx.version, type_=tx.type(), versioner=tx_versioner) tx_restored = ts.from_(tx.raw_data) assert tx == tx_restored
def test_orig_tx_equals_deserialized_tx(self, tx_factory: TxFactory): tx: Transaction = tx_factory(self.tx_version) ts = TransactionSerializer.new(version=tx.version, type_=tx.type(), versioner=tx_versioner) tx_restored = ts.from_(tx.raw_data) object.__setattr__(tx, "to_address", "") object.__setattr__(tx_restored, "to_address", "") assert tx == tx_restored
def test_get_hash(self, tx_factory: 'TxFactory'): tx: Transaction = tx_factory(self.tx_version) ts = TransactionSerializer.new(version=tx.version, type_=tx.type(), versioner=tx_versioner) tx_hash = ts.get_hash(tx.raw_data) assert tx.hash == Hash32.fromhex(tx_hash, ignore_prefix=True, allow_malformed=False)
def size(self, versioner: 'TransactionVersioner'): if not hasattr(self, _size_attr_name_): from loopchain.blockchain.transactions import TransactionSerializer ts = TransactionSerializer.new(self.version, self.type(), versioner) tx_serialized = ts.to_full_data(self) tx_serialized = json.dumps(tx_serialized) tx_serialized = tx_serialized.encode('utf-8') object.__setattr__(self, _size_attr_name_, len(tx_serialized)) return getattr(self, _size_attr_name_)
def test_serializer_version_check(self, tx_factory: TxFactory, tx_version): tx: Transaction = tx_factory(tx_version) ts = TransactionSerializer.new(version=tx.version, type_=tx.type(), versioner=tx_versioner) if tx_version == genesis.version: assert isinstance(ts, genesis.TransactionSerializer) elif tx_version == v2.version: assert isinstance(ts, v2.TransactionSerializer) elif tx_version == v3.version: assert isinstance(ts, v3.TransactionSerializer) else: assert False
def _deserialize_body_data(self, json_data: dict): confirm_prev_block = json_data.get("confirm_prev_block") transactions = OrderedDict() for tx_data in json_data['confirmed_transaction_list']: tx_version, tx_type = self._tx_versioner.get_version(tx_data) ts = TransactionSerializer.new(tx_version, tx_type, self._tx_versioner) tx = ts.from_(tx_data) transactions[tx.hash] = tx return { "confirm_prev_block": confirm_prev_block, "transactions": transactions }
def test_transaction_v2(self): tb = TransactionBuilder.new("0x2", None, self.tx_versioner) tb.fee = 1000000 tb.value = 100000 tb.signer = self.signer tb.to_address = ExternalAddress(os.urandom(20)) tb.nonce = random.randint(0, 100000) tx = tb.build() tv = TransactionVerifier.new("0x2", tx.type(), self.tx_versioner) tv.verify(tx) ts = TransactionSerializer.new("0x2", tx.type(), self.tx_versioner) tx_raw_data = ts.to_raw_data(tx) self.assertEqual(ts.from_(tx_raw_data), tx)
def _deserialize_body_data(self, json_data: dict): transactions = OrderedDict() for tx_data in json_data['transactions']: tx_version, tx_type = self._tx_versioner.get_version(tx_data) ts = TransactionSerializer.new(tx_version, tx_type, self._tx_versioner) tx = ts.from_(tx_data) transactions[tx.hash] = tx leader_votes = LeaderVotes.deserialize_votes(json_data["leaderVotes"]) prev_votes = BlockVotes.deserialize_votes(json_data["prevVotes"]) return { "transactions": transactions, "leader_votes": leader_votes, "prev_votes": prev_votes }
def test_transaction_genesis(self): tb = TransactionBuilder.new("genesis", None, self.tx_versioner) tb.accounts = [{ "name": "test0", "address": ExternalAddress(os.urandom(20)).hex_hx(), "balance": "0x12221231" }] tb.message = "Icon Loop" tx = tb.build(False) tv = TransactionVerifier.new("genesis", tx.type(), self.tx_versioner) tv.verify(tx) ts = TransactionSerializer.new("genesis", tx.type(), self.tx_versioner) tx_raw_data = ts.to_raw_data(tx) self.assertEqual(ts.from_(tx_raw_data), tx)
async def get_block_v2(self, block_height, block_hash) -> Tuple[int, str, str]: # This is a temporary function for v2 support of exchanges. block, block_hash, _, fail_response_code = await self.__get_block( block_hash, block_height) if fail_response_code: return fail_response_code, block_hash, json.dumps({}) tx_versioner = self._blockchain.tx_versioner bs = BlockSerializer.new(block.header.version, tx_versioner) 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_without_fail = [] for tx in block.body.transactions.values(): invoke_result = self._block_manager.get_invoke_result(tx.hash) if 'failure' in invoke_result: continue ts = TransactionSerializer.new(tx.version, tx.type(), tx_versioner) full_data = ts.to_full_data(tx) if tx.version == "0x3": step_used, step_price = int(invoke_result["stepUsed"], 16), int( invoke_result["stepPrice"], 16) full_data["fee"] = hex(step_used * step_price) confirmed_tx_list_without_fail.append(full_data) # Replace the existing confirmed_transactions with v2 ver. if block.header.version == "0.1a": block_data_dict[ "confirmed_transaction_list"] = confirmed_tx_list_without_fail else: block_data_dict["transactions"] = 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