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_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 = TransactionVersioner() version, type_ = tv.get_version(question) ts = TransactionSerializer.new(version, type_, tv) 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)
class TestTransaction(unittest.TestCase): def setUp(self): test_util.print_testname(self._testMethodName) self.signer = Signer.from_prikey(os.urandom(32)) self.tx_versioner = TransactionVersioner() self.tx_versioner.hash_generator_versions["0x2"] = 0 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) 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 test_transaction_v3(self): tb = TransactionBuilder.new("0x3", None, self.tx_versioner) tb.step_limit = 1000000 tb.value = 100000 tb.signer = self.signer tb.to_address = ExternalAddress(os.urandom(20)) tb.nid = 3 tb.nonce = random.randint(0, 100000) tb.data = "test" tb.data_type = "message" tx = tb.build() tv = TransactionVerifier.new("0x3", tx.type(), self.tx_versioner) tv.verify(tx) ts = TransactionSerializer.new("0x3", tx.type(), self.tx_versioner) tx_raw_data = ts.to_raw_data(tx) self.assertEqual(ts.from_(tx_raw_data), tx) def test_transaction_v2_unsigned(self): signer = Signer.new() tb = TransactionBuilder.new("0x2", None, self.tx_versioner) tb.fee = 1000000 tb.value = 100000 tb.from_address = ExternalAddress.fromhex_address(signer.address) tb.to_address = ExternalAddress(os.urandom(20)) tb.nonce = random.randint(0, 100000) tx = tb.build(is_signing=False) tv = TransactionVerifier.new("0x2", tx.type(), self.tx_versioner) self.assertRaises(TransactionInvalidSignatureError, lambda: tv.verify(tx)) self.assertRaises(TransactionInvalidSignatureError, lambda: tv.pre_verify(tx)) tb.signer = signer signed_tx = tb.sign_transaction(tx) tv.verify(signed_tx) tv.pre_verify(signed_tx) def test_transaction_v3_unsigned(self): signer = Signer.new() tb = TransactionBuilder.new("0x3", None, self.tx_versioner) tb.step_limit = 1000000 tb.value = 100000 tb.from_address = ExternalAddress.fromhex_address(signer.address) tb.to_address = ExternalAddress(os.urandom(20)) tb.nid = 3 tb.nonce = random.randint(0, 100000) tb.data = "test" tb.data_type = "message" tx = tb.build(False) tv = TransactionVerifier.new("0x3", tx.type(), self.tx_versioner) self.assertRaises(TransactionInvalidSignatureError, lambda: tv.verify(tx)) self.assertRaises(TransactionInvalidSignatureError, lambda: tv.pre_verify(tx, nid=3)) tb.signer = signer signed_tx = tb.sign_transaction(tx) tv.verify(signed_tx) tv.pre_verify(signed_tx, nid=3) def test_transaction_v2_invalid_hash0(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['tx_hash'] = os.urandom(32).hex() # invalid hash 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(TransactionInvalidHashError, lambda: tv.verify(tx)) self.assertRaises(TransactionInvalidHashError, lambda: tv.pre_verify(tx)) def test_transaction_v2_invalid_hash1(self): # noinspection PyDictCreation tx_dumped = { 'from': 'hx48cd6eb32339d5c719dcc0af21e9bc3b67d733e6', 'to': 'hx22f72e44141bedd50d1e536455682863d3d8a484', 'value': '0x186a0', 'fee': '0xf4240', 'timestamp': '1558679280067963', 'nonce': '1', 'tx_hash': '34477b3bc76fa73aad0258ba9fd36f28a3c4b26956c1e5eb92ddda7d98df4e32', 'signature': 'W/hW/PAo+ExeSsreD//yJVgNqmnkWKs+m0VUqE11O7Ek82yEINuczLRXtj1k515q8Ep4OLsRPPiPNjDM9vuhsgE=' } tx_dumped['value'] = hex(int(random.randrange(1, 100))) # invalid value 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(TransactionInvalidHashError, lambda: tv.verify(tx)) self.assertRaises(TransactionInvalidHashError, lambda: tv.pre_verify(tx)) 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 test_transaction_v3_invalid_signature(self): # noinspection PyDictCreation tx_dumped = { 'version': '0x3', 'from': 'hx48cd6eb32339d5c719dcc0af21e9bc3b67d733e6', 'to': 'hxe0a231fa5c80e45f51d7df5f7d127954320df829', 'stepLimit': '0xf4240', 'timestamp': '0x5899c717f92f8', 'nid': '0x3', 'value': '0x186a0', 'nonce': '0x64', 'data': 'test', 'dataType': 'message', 'signature': 'J84KdBtQR4w1bcBdBGF8g6aNoCXjsY/5T6vGV4RXeMwEvafj9xVRDVjzF+vN1JVYvXrAzjlYPCiiBXBQe6+tRAE=' } 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, nid=3)) def test_transaction_v3_invalid_nid(self): MockBlockchain = namedtuple("MockBlockchain", "find_nid find_tx_by_key") nids = list(range(0, 1000)) random.shuffle(nids) tb = TransactionBuilder.new("0x3", None, self.tx_versioner) tb.step_limit = 1000000 tb.value = 100000 tb.signer = self.signer tb.to_address = ExternalAddress(os.urandom(20)) tb.nid = nids[0] tb.nonce = random.randint(0, 100000) tb.data = "test" tb.data_type = "message" tx = tb.build() expected_nid = nids[1] mock_blockchain = MockBlockchain(find_nid=lambda: hex(expected_nid), find_tx_by_key=lambda _: False) tv = TransactionVerifier.new(tx.version, tx.type(), self.tx_versioner) self.assertRaises(TransactionInvalidNidError, lambda: tv.verify(tx, mock_blockchain)) self.assertRaises(TransactionInvalidNidError, lambda: tv.pre_verify(tx, nid=expected_nid)) def test_transaction_v2_duplicate_hash(self): MockBlockchain = namedtuple("MockBlockchain", "find_nid find_tx_by_key") 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() mock_blockchain = MockBlockchain(find_nid=lambda: hex(3), find_tx_by_key=lambda _: True) tv = TransactionVerifier.new(tx.version, tx.type(), self.tx_versioner) self.assertRaises(TransactionDuplicatedHashError, lambda: tv.verify(tx, mock_blockchain)) def test_transaction_v3_duplicate_hash(self): MockBlockchain = namedtuple("MockBlockchain", "find_nid find_tx_by_key") tb = TransactionBuilder.new("0x3", None, self.tx_versioner) tb.step_limit = 1000000 tb.value = 100000 tb.signer = self.signer tb.to_address = ExternalAddress(os.urandom(20)) tb.nid = 3 tb.nonce = random.randint(0, 100000) tb.data = "test" tb.data_type = "message" tx = tb.build() mock_blockchain = MockBlockchain(find_nid=lambda: hex(3), find_tx_by_key=lambda _: True) tv = TransactionVerifier.new(tx.version, tx.type(), self.tx_versioner) self.assertRaises(TransactionDuplicatedHashError, lambda: tv.verify(tx, mock_blockchain))