From 409a8913d920316c5e3cb84da928ac23b18ef714 Mon Sep 17 00:00:00 2001 From: Niven Date: Tue, 21 Nov 2023 23:57:19 +0800 Subject: [PATCH] RPC: Add single key check for source and destination addresses in transferdomain RPC (#2709) * Add single key flag check in transferdomain RPC, defaults to true * Add invalid single key check test * Fix fmt cpp * Add legacy address support in addressmap * Better refactor, add addressmap tests for legacy addresses * Fix ethlibs test fixture script * Fix typo --------- Co-authored-by: Prasanna Loganathar --- ci/ethlibs_test/main.sh | 2 +- src/dfi/rpc_accounts.cpp | 44 ++- src/wallet/rpcwallet.cpp | 7 +- test/functional/feature_address_map.py | 61 +-- test/functional/feature_evm.py | 13 + .../feature_evm_contract_env_vars.py | 1 + test/functional/feature_evm_contracts.py | 1 + test/functional/feature_evm_dfi_intrinsics.py | 1 + test/functional/feature_evm_dst20.py | 19 + test/functional/feature_evm_eip1559_fees.py | 1 + test/functional/feature_evm_fee.py | 1 + test/functional/feature_evm_gas.py | 1 + test/functional/feature_evm_genesis.py | 1 + test/functional/feature_evm_logs.py | 2 + test/functional/feature_evm_mempool.py | 3 + test/functional/feature_evm_miner.py | 7 + test/functional/feature_evm_proxy.py | 1 + test/functional/feature_evm_rollback.py | 2 + test/functional/feature_evm_rpc.py | 2 + .../functional/feature_evm_rpc_fee_history.py | 1 + test/functional/feature_evm_rpc_filters.py | 1 + .../functional/feature_evm_rpc_transaction.py | 3 + test/functional/feature_evm_smart_contract.py | 2 + .../feature_evm_transaction_replacement.py | 1 + test/functional/feature_evm_transferdomain.py | 352 +++++++++++++++++- test/functional/feature_evm_vmmap_rpc.py | 9 + 26 files changed, 504 insertions(+), 35 deletions(-) diff --git a/ci/ethlibs_test/main.sh b/ci/ethlibs_test/main.sh index c139aab6427..a1dbbaea2c5 100755 --- a/ci/ethlibs_test/main.sh +++ b/ci/ethlibs_test/main.sh @@ -79,7 +79,7 @@ setup_fixtures() { "v0/params/feature/transferdomain": "true"}}' $DEFI_CLI_BIN -regtest generatetoaddress 2 "$OWNERAUTHADDR" - $DEFI_CLI_BIN -regtest transferdomain '[{"src":{"address":"'"$OWNERAUTHADDR"'", "amount":"200@DFI", "domain":2}, "dst":{"address":"'"$ALICE"'", "amount":"200@DFI", "domain":3}}]' + $DEFI_CLI_BIN -regtest transferdomain '[{"src":{"address":"'"$OWNERAUTHADDR"'", "amount":"200@DFI", "domain":2}, "dst":{"address":"'"$ALICE"'", "amount":"200@DFI", "domain":3}, "singlekeycheck": false}]' $DEFI_CLI_BIN -regtest generatetoaddress 1 "$OWNERAUTHADDR" $DEFI_CLI_BIN -regtest eth_sendTransaction '{"from":"'"$ALICE"'", "data":"'"$CONTRACT_COUNTER"'", "value":"0x00", "gas":"0x7a120", "gasPrice": "0x22ecb25c00"}' diff --git a/src/dfi/rpc_accounts.cpp b/src/dfi/rpc_accounts.cpp index e366613a12a..7d7f8d12bcf 100644 --- a/src/dfi/rpc_accounts.cpp +++ b/src/dfi/rpc_accounts.cpp @@ -2172,10 +2172,19 @@ UniValue transferdomain(const JSONRPCRequest &request) { // {"data", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Optional data"}, }, }, - {"nonce", - RPCArg::Type::NUM, - RPCArg::Optional::OMITTED, - "Optional parameter to specify the transaction nonce"}, + { + "nonce", + RPCArg::Type::NUM, + RPCArg::Optional::OMITTED, + "Optional parameter to specify the transaction nonce", + }, + { + "singlekeycheck", + RPCArg::Type::BOOL, + RPCArg::Optional::OMITTED, + "Optional flag to ensure single key check between the corresponding address types " + "(default = true)", + }, }, }, }, @@ -2210,12 +2219,21 @@ UniValue transferdomain(const JSONRPCRequest &request) { std::vector> nonce_cache; for (unsigned int i = 0; i < srcDstArray.size(); i++) { - const UniValue &elem = srcDstArray[i]; - RPCTypeCheck(elem, {UniValue::VOBJ, UniValue::VOBJ, UniValue::VNUM}, false); + const UniValue &elem = srcDstArray[i].get_obj(); + RPCTypeCheckObj(elem, + { + {"src", UniValueType(UniValue::VOBJ) }, + {"dst", UniValueType(UniValue::VOBJ) }, + {"nonce", UniValueType(UniValue::VNUM) }, + {"singlekeycheck", UniValueType(UniValue::VBOOL)}, + }, + true, + true); const UniValue &srcObj = elem["src"].get_obj(); const UniValue &dstObj = elem["dst"].get_obj(); const UniValue &nonceObj = elem["nonce"]; + const UniValue &singlekeycheckObj = elem["singlekeycheck"]; CTransferDomainItem src, dst; @@ -2290,6 +2308,20 @@ UniValue transferdomain(const JSONRPCRequest &request) { // if (!dstObj["data"].isNull()) // dst.data.assign(dstObj["data"].getValStr().begin(), dstObj["data"].getValStr().end()); + // Single key check + bool singlekeycheck = true; + if (!singlekeycheckObj.isNull()) { + singlekeycheck = singlekeycheckObj.getBool(); + } + if (singlekeycheck) { + auto dstKey = AddrToPubKey(pwallet, ScriptToString(dst.address)); + auto [uncompSrcKey, compSrcKey] = GetBothPubkeyCompressions(srcKey); + auto [uncompDstKey, compDstKey] = GetBothPubkeyCompressions(dstKey); + if (uncompSrcKey != uncompDstKey || compSrcKey != compDstKey) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Dst address does not match source key"); + } + } + // Create signed EVM TX CKey key; if (!pwallet->GetKey(srcKey.GetID(), key)) { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2895b1ddde6..5011fce424b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4330,10 +4330,9 @@ UniValue addressmap(const JSONRPCRequest &request) { throwInvalidAddressFmt(); } CPubKey key = AddrToPubKey(pwallet, input); - if (!key.IsCompressed()) { - key.Compress(); - } - format.pushKV("bech32", EncodeDestination(WitnessV0KeyHash(key))); + auto [uncomp, comp] = GetBothPubkeyCompressions(key); + format.pushKV("bech32", EncodeDestination(WitnessV0KeyHash(comp))); + format.pushKV("legacy", EncodeDestination(PKHash(uncomp))); break; } default: diff --git a/test/functional/feature_address_map.py b/test/functional/feature_address_map.py index 45fb0a85e06..49abe79d514 100755 --- a/test/functional/feature_address_map.py +++ b/test/functional/feature_address_map.py @@ -127,14 +127,17 @@ def addressmap_address_basics_manual_import(self): ] addr_maps = [ [ + "n32jT7A5sv6t9Hm2NAYK6juuwsCdsWe1SF", "bcrt1qmhpq9hxgdglwja6uruc92yne8ekxljgykrfta5", "0xfD0766e7aBe123A25c73c95f6dc3eDe26D0b7263", ], [ + "n4VvfBJBTQpDf8ooyjgehiq9mTjeKhcwEc", "bcrt1qtqggfdte5jp8duffzmt54aqtqwlv3l8xsjdrhf", "0x4d07A76Db2a281a348d5A5a1833F4322D77799d5", ], [ + "n1HUChzN3RR89jhtehNBNboLUnt4QNAJ8E", "bcrt1qdw7fqrq9n2d530uh05vdm2yvpag2ydm0z67yc5", "0x816a4DDbC26B80602767B13Fb17B2e1785125BE7", ], @@ -151,44 +154,58 @@ def addressmap_address_basics_manual_import(self): # # self.nodes[0].importprivkey(wif) self.nodes[0].importprivkey(rawkey) - for [dfi_addr, eth_addr] in addr_maps: + for [legacy_address, bech32_address, erc55_address] in addr_maps: # dvm -> evm res = self.nodes[0].addressmap( - dfi_addr, AddressConversionType.DVMToEVMAddress + legacy_address, AddressConversionType.DVMToEVMAddress ) - assert_equal(res["input"], dfi_addr) + assert_equal(res["input"], legacy_address) assert_equal(res["type"], 1) - assert_equal(res["format"]["erc55"], eth_addr) + assert_equal(res["format"]["erc55"], erc55_address) + + res = self.nodes[0].addressmap( + bech32_address, AddressConversionType.DVMToEVMAddress + ) + assert_equal(res["input"], bech32_address) + assert_equal(res["type"], 1) + assert_equal(res["format"]["erc55"], erc55_address) # evm -> dvm res = self.nodes[0].addressmap( - eth_addr, AddressConversionType.EVMToDVMAddress + erc55_address, AddressConversionType.EVMToDVMAddress ) - assert_equal(res["input"], eth_addr) + assert_equal(res["input"], erc55_address) assert_equal(res["type"], 2) - assert_equal(res["format"]["bech32"], dfi_addr) + assert_equal(res["format"]["legacy"], legacy_address) + assert_equal(res["format"]["bech32"], bech32_address) # auto (dvm -> evm) - res = self.nodes[0].addressmap(dfi_addr, AddressConversionType.Auto) - assert_equal(res["input"], dfi_addr) + res = self.nodes[0].addressmap(legacy_address, AddressConversionType.Auto) + assert_equal(res["input"], legacy_address) + assert_equal(res["type"], 1) + assert_equal(res["format"]["erc55"], erc55_address) + + res = self.nodes[0].addressmap(bech32_address, AddressConversionType.Auto) + assert_equal(res["input"], bech32_address) assert_equal(res["type"], 1) - assert_equal(res["format"]["erc55"], eth_addr) + assert_equal(res["format"]["erc55"], erc55_address) # auto (evm -> dvm) - res = self.nodes[0].addressmap(eth_addr, AddressConversionType.Auto) - assert_equal(res["input"], eth_addr) + res = self.nodes[0].addressmap(erc55_address, AddressConversionType.Auto) + assert_equal(res["input"], erc55_address) assert_equal(res["type"], 2) - assert_equal(res["format"]["bech32"], dfi_addr) + assert_equal(res["format"]["legacy"], legacy_address) + assert_equal(res["format"]["bech32"], bech32_address) def addressmap_valid_address_not_present_should_fail(self): self.rollback_to(self.start_block_height) # Give an address that is not own by the node. THis should fail since we don't have the public key of the address. - eth_address = self.nodes[1].getnewaddress("", "erc55") + erc55_addressess = self.nodes[1].getnewaddress("", "erc55") assert_raises_rpc_error( -5, - "no full public key for address " + eth_address, + "no full public key for address " + erc55_addressess, self.nodes[0].addressmap, - eth_address, + erc55_addressess, AddressConversionType.EVMToDVMAddress, ) @@ -196,7 +213,7 @@ def addressmap_valid_address_invalid_type_should_fail(self): self.rollback_to(self.start_block_height) address = self.nodes[0].getnewaddress("", "legacy") p2sh_address = self.nodes[0].getnewaddress("", "p2sh-segwit") - eth_address = self.nodes[0].getnewaddress("", "erc55") + erc55_addressess = self.nodes[0].getnewaddress("", "erc55") assert_invalid_parameter = lambda *args: assert_raises_rpc_error( -8, "Invalid type parameter", self.nodes[0].addressmap, *args ) @@ -205,7 +222,7 @@ def addressmap_valid_address_invalid_type_should_fail(self): ) assert_invalid_parameter(address, 9) assert_invalid_parameter(address, -1) - assert_invalid_format(eth_address, AddressConversionType.DVMToEVMAddress) + assert_invalid_format(erc55_addressess, AddressConversionType.DVMToEVMAddress) assert_invalid_format(address, AddressConversionType.EVMToDVMAddress) assert_invalid_format(p2sh_address, AddressConversionType.DVMToEVMAddress) assert_invalid_format(p2sh_address, AddressConversionType.DVMToEVMAddress) @@ -213,19 +230,19 @@ def addressmap_valid_address_invalid_type_should_fail(self): def addressmap_invalid_address_should_fail(self): self.rollback_to(self.start_block_height) # Check that addressmap is failing on wrong input - eth_address = "0x0000000000000000000000000000000000000000" + erc55_addressess = "0x0000000000000000000000000000000000000000" assert_raises_rpc_error( -5, - eth_address + " does not refer to a key", + erc55_addressess + " does not refer to a key", self.nodes[0].addressmap, - eth_address, + erc55_addressess, AddressConversionType.EVMToDVMAddress, ) assert_raises_rpc_error( -8, "Invalid address format", self.nodes[0].addressmap, - eth_address, + erc55_addressess, AddressConversionType.DVMToEVMAddress, ) assert_raises_rpc_error( diff --git a/test/functional/feature_evm.py b/test/functional/feature_evm.py index 14c9d52e1b9..dbf6fe8f3e9 100755 --- a/test/functional/feature_evm.py +++ b/test/functional/feature_evm.py @@ -63,6 +63,7 @@ def test_tx_without_chainid(self): "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -361,6 +362,7 @@ def verify_evm_not_enabled(): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -383,6 +385,7 @@ def verify_transferdomain_not_enabled_post_evm_on(): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -418,6 +421,7 @@ def verify_transferdomain_not_enabled_post_evm_on(): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -447,6 +451,7 @@ def verify_transferdomain_not_enabled_post_evm_on(): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -581,6 +586,7 @@ def verify_transferdomain_not_enabled_post_evm_on(): "amount": "100@DFI", "domain": 2, }, + "singlekeycheck": False, } ], ) @@ -610,6 +616,7 @@ def verify_transferdomain_not_enabled_post_evm_on(): "domain": 3, }, "dst": {"address": self.address, "amount": "100@DFI", "domain": 2}, + "singlekeycheck": False, } ], ) @@ -639,6 +646,7 @@ def verify_transferdomain_not_enabled_post_evm_on(): "domain": 3, }, "dst": {"address": self.address, "amount": "100@DFI", "domain": 2}, + "singlekeycheck": False, } ], ) @@ -738,6 +746,7 @@ def setup_accounts(self): "amount": "200@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -1362,6 +1371,7 @@ def encrypt_wallet(self): "amount": "0.1@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -1377,6 +1387,7 @@ def encrypt_wallet(self): "amount": "0.1@DFI", "domain": 2, }, + "singlekeycheck": False, } ] ) @@ -1396,6 +1407,7 @@ def delete_account_from_trie(self): "amount": "2@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -1416,6 +1428,7 @@ def delete_account_from_trie(self): "amount": "20@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_contract_env_vars.py b/test/functional/feature_evm_contract_env_vars.py index 52b7251e123..de23c87fc8c 100755 --- a/test/functional/feature_evm_contract_env_vars.py +++ b/test/functional/feature_evm_contract_env_vars.py @@ -73,6 +73,7 @@ def should_create_contract(self): "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_contracts.py b/test/functional/feature_evm_contracts.py index f4ccaa02c85..99e0248f5ce 100755 --- a/test/functional/feature_evm_contracts.py +++ b/test/functional/feature_evm_contracts.py @@ -75,6 +75,7 @@ def setup(self): "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_dfi_intrinsics.py b/test/functional/feature_evm_dfi_intrinsics.py index 5ba8378ce9e..bd8e4370f7d 100755 --- a/test/functional/feature_evm_dfi_intrinsics.py +++ b/test/functional/feature_evm_dfi_intrinsics.py @@ -147,6 +147,7 @@ def run_test(self): "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_dst20.py b/test/functional/feature_evm_dst20.py index 39b713ffca9..83d586eb0b9 100755 --- a/test/functional/feature_evm_dst20.py +++ b/test/functional/feature_evm_dst20.py @@ -230,6 +230,7 @@ def test_pre_evm_token(self): "amount": "1@USDT", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -253,6 +254,7 @@ def test_pre_evm_token(self): "domain": 3, }, "dst": {"address": self.address, "amount": "1@USDT", "domain": 2}, + "singlekeycheck": False, } ] ) @@ -370,6 +372,7 @@ def test_dst20_dvm_to_evm_bridge(self): "amount": "1@BTC", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -401,6 +404,7 @@ def test_dst20_dvm_to_evm_bridge(self): "amount": "1@BTC", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -429,6 +433,7 @@ def test_dst20_evm_to_dvm_bridge(self): "amount": "1.5@BTC", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -459,6 +464,7 @@ def test_multiple_dvm_evm_bridge(self): "domain": 3, }, "nonce": nonce, + "singlekeycheck": False, } ] ) @@ -472,6 +478,7 @@ def test_multiple_dvm_evm_bridge(self): "domain": 3, }, "nonce": nonce + 1, + "singlekeycheck": False, } ] ) @@ -503,6 +510,7 @@ def test_conflicting_bridge(self): "amount": "1@BTC", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -515,6 +523,7 @@ def test_conflicting_bridge(self): "domain": 3, }, "dst": {"address": self.address, "amount": "1@BTC", "domain": 2}, + "singlekeycheck": False, } ] ) @@ -548,6 +557,7 @@ def test_bridge_when_no_balance(self): "domain": 3, }, "dst": {"address": self.address, "amount": "1@BTC", "domain": 2}, + "singlekeycheck": False, } ] ) @@ -583,6 +593,7 @@ def test_invalid_token(self): "amount": "1@XYZ", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -617,6 +628,7 @@ def test_negative_transfer(self): "amount": "-1@BTC", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -634,6 +646,7 @@ def test_different_tokens(self): "amount": "1@ETH", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -708,6 +721,7 @@ def test_loan_token(self): "amount": "2@TSLA", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -735,6 +749,7 @@ def test_loan_token(self): "domain": 3, }, "dst": {"address": self.address, "amount": "1@TSLA", "domain": 2}, + "singlekeycheck": False, } ] ) @@ -764,6 +779,7 @@ def test_dst20_back_and_forth(self): "amount": "1@BTC", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -801,6 +817,7 @@ def test_dst20_back_and_forth(self): "amount": "1@BTC", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -840,6 +857,7 @@ def test_dst20_back_and_forth(self): "amount": "1@BTC", "domain": 2, }, + "singlekeycheck": False, } ] ) @@ -879,6 +897,7 @@ def test_dst20_back_and_forth(self): "amount": "1@BTC", "domain": 2, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_eip1559_fees.py b/test/functional/feature_evm_eip1559_fees.py index 2de31e39812..b78b94dfa1f 100644 --- a/test/functional/feature_evm_eip1559_fees.py +++ b/test/functional/feature_evm_eip1559_fees.py @@ -77,6 +77,7 @@ def setup(self): "amount": "10@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_fee.py b/test/functional/feature_evm_fee.py index deef1f06a62..6d938ffbb1e 100755 --- a/test/functional/feature_evm_fee.py +++ b/test/functional/feature_evm_fee.py @@ -324,6 +324,7 @@ def run_test(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_gas.py b/test/functional/feature_evm_gas.py index 38fccd532dc..2c3bf370c4f 100644 --- a/test/functional/feature_evm_gas.py +++ b/test/functional/feature_evm_gas.py @@ -96,6 +96,7 @@ def setup(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_genesis.py b/test/functional/feature_evm_genesis.py index 3d6eca1f7ac..947c2c2e07f 100755 --- a/test/functional/feature_evm_genesis.py +++ b/test/functional/feature_evm_genesis.py @@ -99,6 +99,7 @@ def tx_should_not_go_into_genesis_block(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_logs.py b/test/functional/feature_evm_logs.py index 79495d9b16f..373a28197ab 100755 --- a/test/functional/feature_evm_logs.py +++ b/test/functional/feature_evm_logs.py @@ -77,6 +77,7 @@ def should_create_contract(self): "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -153,6 +154,7 @@ def transferdomain_receipt_gas_used(self): "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_mempool.py b/test/functional/feature_evm_mempool.py index 375ebe7828e..67e5750a936 100755 --- a/test/functional/feature_evm_mempool.py +++ b/test/functional/feature_evm_mempool.py @@ -99,6 +99,7 @@ def setup(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -120,6 +121,7 @@ def same_nonce_transferdomain_and_evm_txs(self): "domain": 2, }, "nonce": nonce, + "singlekeycheck": False, } ] ) @@ -420,6 +422,7 @@ def flush_invalid_txs(self): "domain": 2, }, "nonce": nonce, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_miner.py b/test/functional/feature_evm_miner.py index d33bfbffb38..af3e92a7d53 100755 --- a/test/functional/feature_evm_miner.py +++ b/test/functional/feature_evm_miner.py @@ -103,6 +103,7 @@ def setup(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -327,6 +328,7 @@ def block_with_multiple_transfer_domain_dfi_txs(self): "domain": 3, }, "nonce": start_nonce_erc55 + i, + "singlekeycheck": False, } ] ) @@ -440,6 +442,7 @@ def block_with_multiple_transfer_domain_dst20_txs(self): "domain": 3, }, "nonce": start_nonce_erc55 + i, + "singlekeycheck": False, } ] ) @@ -534,6 +537,7 @@ def blocks_size_gas_limit_with_transferdomain_txs(self): "domain": 3, }, "nonce": start_nonce_erc55 + i, + "singlekeycheck": False, } ] ) @@ -1025,6 +1029,7 @@ def multiple_evm_and_transferdomain_txs(self): "domain": 3, }, "nonce": start_nonce_erc55 + i, + "singlekeycheck": False, } ] ) @@ -1051,6 +1056,7 @@ def multiple_transferdomain_txs(self): "domain": 3, }, "nonce": start_nonce_erc55 + i, + "singlekeycheck": False, } ] ) @@ -1076,6 +1082,7 @@ def multiple_transferdomain_txs(self): "domain": 3, }, "nonce": start_nonce_erc55 + i, + "singlekeycheck": False, } ], ) diff --git a/test/functional/feature_evm_proxy.py b/test/functional/feature_evm_proxy.py index 2d615871d5f..fb3d0060824 100755 --- a/test/functional/feature_evm_proxy.py +++ b/test/functional/feature_evm_proxy.py @@ -73,6 +73,7 @@ def should_deploy_implementation_smart_contract(self) -> web3Contract: "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_rollback.py b/test/functional/feature_evm_rollback.py index b5c2f41b397..3577f62ecf4 100755 --- a/test/functional/feature_evm_rollback.py +++ b/test/functional/feature_evm_rollback.py @@ -84,6 +84,7 @@ def setup(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -242,6 +243,7 @@ def test_state_rollback(self): "amount": "10@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_rpc.py b/test/functional/feature_evm_rpc.py index c6dae3c75bf..2d588cfe47d 100755 --- a/test/functional/feature_evm_rpc.py +++ b/test/functional/feature_evm_rpc.py @@ -101,6 +101,7 @@ def setup(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -334,6 +335,7 @@ def test_address_state(self): "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_rpc_fee_history.py b/test/functional/feature_evm_rpc_fee_history.py index 53444fb448b..3bd9f420963 100755 --- a/test/functional/feature_evm_rpc_fee_history.py +++ b/test/functional/feature_evm_rpc_fee_history.py @@ -86,6 +86,7 @@ def setup(self): "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_rpc_filters.py b/test/functional/feature_evm_rpc_filters.py index 91804964f23..e02438c6218 100755 --- a/test/functional/feature_evm_rpc_filters.py +++ b/test/functional/feature_evm_rpc_filters.py @@ -74,6 +74,7 @@ def setup(self): "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_rpc_transaction.py b/test/functional/feature_evm_rpc_transaction.py index 199c92761a2..f73b2e288fa 100755 --- a/test/functional/feature_evm_rpc_transaction.py +++ b/test/functional/feature_evm_rpc_transaction.py @@ -105,6 +105,7 @@ def setup(self): "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -502,6 +503,7 @@ def test_auto_nonce_for_multiple_transaction(self): "domain": 2, }, "nonce": nonce + 2, + "singlekeycheck": False, } ] ) @@ -537,6 +539,7 @@ def test_auto_nonce_for_multiple_transaction(self): "amount": "1@DFI", "domain": 2, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_smart_contract.py b/test/functional/feature_evm_smart_contract.py index 2cbff869cc4..2e7ac9fa948 100755 --- a/test/functional/feature_evm_smart_contract.py +++ b/test/functional/feature_evm_smart_contract.py @@ -124,6 +124,7 @@ def test_smart_contract_address_state_storage(self): "amount": "10@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -162,6 +163,7 @@ def run_test(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_transaction_replacement.py b/test/functional/feature_evm_transaction_replacement.py index 64145d72d74..3d2b731711d 100755 --- a/test/functional/feature_evm_transaction_replacement.py +++ b/test/functional/feature_evm_transaction_replacement.py @@ -100,6 +100,7 @@ def setup(self): "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) diff --git a/test/functional/feature_evm_transferdomain.py b/test/functional/feature_evm_transferdomain.py index 0c34d60dbfc..4bd2a992836 100755 --- a/test/functional/feature_evm_transferdomain.py +++ b/test/functional/feature_evm_transferdomain.py @@ -14,6 +14,8 @@ from test_framework.evm_contract import EVMContract from test_framework.evm_key_pair import EvmKeyPair +import json +import math from decimal import Decimal @@ -27,6 +29,7 @@ def transfer_domain(node, fromAddr, toAddr, amount, fromDomain, toDomain): "amount": amount, "domain": toDomain, }, + "singlekeycheck": False, } ] ) @@ -264,7 +267,7 @@ def invalid_before_fork_and_disabled(self): self.start_height = self.nodes[0].getblockcount() - def check_initial_balance(self): + def setup_after_evm_activation(self): self.rollback_to(self.start_height) # Check initial balances @@ -274,6 +277,43 @@ def check_initial_balance(self): assert_equal(self.eth_balance, int_to_eth_u256(0)) assert_equal(len(self.nodes[0].getaccount(self.eth_address, {}, True)), 0) + self.contract_address_btc = self.nodes[0].w3.to_checksum_address( + "0xff00000000000000000000000000000000000001" + ) + self.btc = self.nodes[0].w3.eth.contract( + address=self.contract_address_btc, abi=self.abi + ) + self.bytecode = json.loads( + open( + get_solc_artifact_path("dst20", "deployed_bytecode.json"), + "r", + encoding="utf8", + ).read() + )["object"] + assert_equal(self.btc.functions.name().call(), "BTC token") + assert_equal(self.btc.functions.symbol().call(), "BTC") + + # check BTC migration + genesis_block = self.nodes[0].eth_getBlockByNumber("0x0") + btc_tx = genesis_block["transactions"][5] + receipt = self.nodes[0].eth_getTransactionReceipt(btc_tx) + tx = self.nodes[0].eth_getTransactionByHash(btc_tx) + assert_equal( + self.nodes[0].w3.to_checksum_address(receipt["contractAddress"]), + self.contract_address_btc, + ) + assert_equal(receipt["from"], tx["from"]) + assert_equal(receipt["gasUsed"], "0x0") + assert_equal(receipt["logs"], []) + assert_equal(receipt["status"], "0x1") + assert_equal(receipt["to"], None) + assert_equal( + self.nodes[0].w3.to_hex( + self.nodes[0].w3.eth.get_code(self.contract_address_btc) + ), + self.bytecode, + ) + def invalid_parameters(self): self.rollback_to(self.start_height) @@ -290,6 +330,7 @@ def invalid_parameters(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -305,6 +346,7 @@ def invalid_parameters(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -320,6 +362,7 @@ def invalid_parameters(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -339,6 +382,7 @@ def invalid_parameters(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -354,6 +398,7 @@ def invalid_parameters(self): "amount": "100@DFI", "domain": "evm", }, + "singlekeycheck": False, } ], ) @@ -369,6 +414,7 @@ def invalid_parameters(self): "amount": "100@DFI", "domain": 2, }, + "singlekeycheck": False, } ], ) @@ -384,6 +430,7 @@ def invalid_parameters(self): "amount": "100@DFI", "domain": 4, }, + "singlekeycheck": False, } ], ) @@ -399,6 +446,7 @@ def invalid_parameters(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -410,6 +458,7 @@ def invalid_parameters(self): { "src": {"address": self.address, "amount": "100@DFI", "domain": 2}, "dst": {"address": "blablabla", "amount": "100@DFI", "domain": 3}, + "singlekeycheck": False, } ], ) @@ -443,6 +492,7 @@ def invalid_values_dvm_evm(self): "amount": "101@DFI", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -539,6 +589,7 @@ def invalid_values_evm_dvm(self): { "src": {"address": self.address, "amount": "100@DFI", "domain": 3}, "dst": {"address": self.address, "amount": "100@DFI", "domain": 2}, + "singlekeycheck": False, } ], ) @@ -558,6 +609,7 @@ def invalid_values_evm_dvm(self): "amount": "100@DFI", "domain": 2, }, + "singlekeycheck": False, } ], ) @@ -573,6 +625,7 @@ def invalid_values_evm_dvm(self): "domain": 3, }, "dst": {"address": self.address, "amount": "100@DFI", "domain": 3}, + "singlekeycheck": False, } ], ) @@ -588,6 +641,7 @@ def invalid_values_evm_dvm(self): "domain": 3, }, "dst": {"address": self.address, "amount": "101@DFI", "domain": 2}, + "singlekeycheck": False, } ], ) @@ -603,6 +657,7 @@ def invalid_values_evm_dvm(self): "domain": 3, }, "dst": {"address": self.address, "amount": "10@DFI", "domain": 2}, + "singlekeycheck": False, }, { "src": { @@ -615,6 +670,7 @@ def invalid_values_evm_dvm(self): "amount": "10@DFI", "domain": 2, }, + "singlekeycheck": False, }, ], ) @@ -634,6 +690,7 @@ def invalid_values_evm_dvm(self): "amount": "1@" + self.symbolUSER, "domain": 2, }, + "singlekeycheck": False, } ], ) @@ -653,6 +710,7 @@ def invalid_values_evm_dvm(self): "amount": "1@" + self.symbolBTCDFI, "domain": 2, }, + "singlekeycheck": False, } ], ) @@ -727,6 +785,286 @@ def valid_transfer_evm_dvm(self): attributes["v0/live/economy/evm/block/fee_priority"], Decimal("0E-8") ) + def valid_single_key_transfer(self): + self.rollback_to(self.start_height) + + # Valid DVM legacy address to EVM address with same key transfer + legacy_address = self.nodes[0].getnewaddress("", "legacy") + self.nodes[0].accounttoaccount(self.address, {legacy_address: "1@DFI"}) + self.nodes[0].accounttoaccount(self.address, {legacy_address: "1@BTC"}) + self.nodes[0].generate(1) + + # Native transfer + legacy_erc55_address = self.nodes[0].addressmap(legacy_address, 1)["format"][ + "erc55" + ] + self.nodes[0].transferdomain( + [ + { + "src": {"address": legacy_address, "amount": "1@DFI", "domain": 2}, + "dst": { + "address": legacy_erc55_address, + "amount": "1@DFI", + "domain": 3, + }, + } + ] + ) + self.nodes[0].generate(1) + balance = self.nodes[0].eth_getBalance(legacy_erc55_address) + assert_equal(balance, int_to_eth_u256(1)) + + # Token transfer + self.nodes[0].transferdomain( + [ + { + "src": {"address": legacy_address, "amount": "1@BTC", "domain": 2}, + "dst": { + "address": legacy_erc55_address, + "amount": "1@BTC", + "domain": 3, + }, + } + ] + ) + self.nodes[0].generate(1) + assert_equal( + self.btc.functions.balanceOf(legacy_erc55_address).call() + / math.pow(10, self.btc.functions.decimals().call()), + Decimal(1), + ) + assert_equal( + self.btc.functions.totalSupply().call() + / math.pow(10, self.btc.functions.decimals().call()), + Decimal(1), + ) + + # Valid DVM bech32 address to EVM address with same key transfer + bech32_address = self.nodes[0].getnewaddress("", "bech32") + self.nodes[0].accounttoaccount(self.address, {bech32_address: "1@DFI"}) + self.nodes[0].accounttoaccount(self.address, {bech32_address: "1@BTC"}) + self.nodes[0].generate(1) + + # Native transfer + bech32_erc55_address = self.nodes[0].addressmap(bech32_address, 1)["format"][ + "erc55" + ] + self.nodes[0].transferdomain( + [ + { + "src": {"address": bech32_address, "amount": "1@DFI", "domain": 2}, + "dst": { + "address": bech32_erc55_address, + "amount": "1@DFI", + "domain": 3, + }, + } + ] + ) + self.nodes[0].generate(1) + balance = self.nodes[0].eth_getBalance(bech32_erc55_address) + assert_equal(balance, int_to_eth_u256(1)) + + # Token transfer + self.nodes[0].transferdomain( + [ + { + "src": {"address": bech32_address, "amount": "1@BTC", "domain": 2}, + "dst": { + "address": bech32_erc55_address, + "amount": "1@BTC", + "domain": 3, + }, + } + ] + ) + self.nodes[0].generate(1) + assert_equal( + self.btc.functions.balanceOf(bech32_erc55_address).call() + / math.pow(10, self.btc.functions.decimals().call()), + Decimal(1), + ) + assert_equal( + self.btc.functions.totalSupply().call() + / math.pow(10, self.btc.functions.decimals().call()), + Decimal(2), + ) + + # Valid ERC55 address to DVM bech32 address with same key transfer + erc55_address = self.nodes[0].getnewaddress("", "erc55") + transfer_domain(self.nodes[0], self.address, erc55_address, "2@DFI", 2, 3) + transfer_domain(self.nodes[0], self.address, erc55_address, "2@BTC", 2, 3) + self.nodes[0].generate(1) + balance = self.nodes[0].eth_getBalance(erc55_address) + assert_equal(balance, int_to_eth_u256(2)) + assert_equal( + self.btc.functions.balanceOf(erc55_address).call() + / math.pow(10, self.btc.functions.decimals().call()), + Decimal(2), + ) + assert_equal( + self.btc.functions.totalSupply().call() + / math.pow(10, self.btc.functions.decimals().call()), + Decimal(4), + ) + + # Native transfer + erc55_bech32_address = self.nodes[0].addressmap(erc55_address, 2)["format"][ + "bech32" + ] + erc55_legacy_address = self.nodes[0].addressmap(erc55_address, 2)["format"][ + "legacy" + ] + self.nodes[0].transferdomain( + [ + { + "src": {"address": erc55_address, "amount": "1@DFI", "domain": 3}, + "dst": { + "address": erc55_bech32_address, + "amount": "1@DFI", + "domain": 2, + }, + } + ] + ) + self.nodes[0].transferdomain( + [ + { + "src": {"address": erc55_address, "amount": "1@DFI", "domain": 3}, + "dst": { + "address": erc55_legacy_address, + "amount": "1@DFI", + "domain": 2, + }, + } + ] + ) + self.nodes[0].generate(1) + balance = self.nodes[0].eth_getBalance(erc55_address) + assert_equal(balance, int_to_eth_u256(0)) + balance = self.nodes[0].getaccount(erc55_bech32_address, {}, True)["0"] + assert_equal(balance, Decimal("1")) + balance = self.nodes[0].getaccount(erc55_legacy_address, {}, True)["0"] + assert_equal(balance, Decimal("1")) + + # Token transfer + self.nodes[0].transferdomain( + [ + { + "src": {"address": erc55_address, "amount": "1@BTC", "domain": 3}, + "dst": { + "address": erc55_bech32_address, + "amount": "1@BTC", + "domain": 2, + }, + } + ] + ) + self.nodes[0].transferdomain( + [ + { + "src": {"address": erc55_address, "amount": "1@BTC", "domain": 3}, + "dst": { + "address": erc55_legacy_address, + "amount": "1@BTC", + "domain": 2, + }, + } + ] + ) + self.nodes[0].generate(1) + assert_equal( + self.btc.functions.balanceOf(erc55_address).call() + / math.pow(10, self.btc.functions.decimals().call()), + Decimal(0), + ) + assert_equal( + self.btc.functions.totalSupply().call() + / math.pow(10, self.btc.functions.decimals().call()), + Decimal(2), + ) + balance = self.nodes[0].getaccount(erc55_bech32_address, {}, True)["1"] + assert_equal(balance, Decimal("1")) + balance = self.nodes[0].getaccount(erc55_legacy_address, {}, True)["1"] + assert_equal(balance, Decimal("1")) + + def invalid_single_key_transfer(self): + self.rollback_to(self.start_height) + + # Invalid DVM legacy address to EVM address with different key transfer + legacy_address = self.nodes[0].getnewaddress("", "legacy") + self.nodes[0].accounttoaccount(self.address, {legacy_address: "1@DFI"}) + self.nodes[0].generate(1) + assert_raises_rpc_error( + -5, + "Dst address does not match source key", + self.nodes[0].transferdomain, + [ + { + "src": { + "address": legacy_address, + "amount": "1@DFI", + "domain": 2, + }, + "dst": { + "address": self.eth_address, + "amount": "1@DFI", + "domain": 3, + }, + } + ], + ) + + # Invalid DVM bech32 address to EVM address with different key transfer + bech32_address = self.nodes[0].getnewaddress("", "bech32") + self.nodes[0].accounttoaccount(self.address, {bech32_address: "1@DFI"}) + self.nodes[0].generate(1) + assert_raises_rpc_error( + -5, + "Dst address does not match source key", + self.nodes[0].transferdomain, + [ + { + "src": { + "address": bech32_address, + "amount": "1@DFI", + "domain": 2, + }, + "dst": { + "address": self.eth_address, + "amount": "1@DFI", + "domain": 3, + }, + } + ], + ) + + # Invalid ERC55 address to DVM bech32 address with different key transfer + erc55_address = self.nodes[0].getnewaddress("", "erc55") + transfer_domain(self.nodes[0], self.address, erc55_address, "1@DFI", 2, 3) + self.nodes[0].generate(1) + balance = self.nodes[0].eth_getBalance(erc55_address) + assert_equal(balance, int_to_eth_u256(1)) + assert_raises_rpc_error( + -5, + "Dst address does not match source key", + self.nodes[0].transferdomain, + [ + { + "src": { + "address": erc55_address, + "amount": "1@DFI", + "domain": 3, + }, + "dst": { + "address": self.address, + "amount": "1@DFI", + "domain": 2, + }, + } + ], + ) + def invalid_transfer_sc(self): self.rollback_to(self.start_height) @@ -740,6 +1078,7 @@ def invalid_transfer_sc(self): "amount": "50@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -784,6 +1123,7 @@ def invalid_transfer_sc(self): "amount": "1@DFI", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -803,6 +1143,7 @@ def invalid_transfer_no_auth(self): "amount": "1@DFI", "domain": 3, }, + "singlekeycheck": False, } ], ) @@ -818,6 +1159,7 @@ def invalid_transfer_no_auth(self): "domain": 3, }, "dst": {"address": self.address, "amount": "1@DFI", "domain": 2}, + "singlekeycheck": False, } ], ) @@ -863,6 +1205,7 @@ def valid_transfer_to_evm_then_move_then_back_to_dvm(self): "amount": "101@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -965,6 +1308,7 @@ def valid_transfer_to_evm_then_move_then_back_to_dvm(self): "domain": 3, }, "dst": {"address": self.address, "amount": "100@DFI", "domain": 2}, + "singlekeycheck": False, } ] ) @@ -1259,7 +1603,7 @@ def run_test(self): self.setup() self.invalid_before_fork_and_disabled() - self.check_initial_balance() + self.setup_after_evm_activation() self.invalid_parameters() # Transfer DVM->EVM @@ -1270,6 +1614,10 @@ def run_test(self): self.invalid_values_evm_dvm() self.valid_transfer_evm_dvm() + # Single key transfer + self.valid_single_key_transfer() + self.invalid_single_key_transfer() + # Transfer to smart contract self.invalid_transfer_sc() diff --git a/test/functional/feature_evm_vmmap_rpc.py b/test/functional/feature_evm_vmmap_rpc.py index 4add8f8d5f0..637fd89b2de 100755 --- a/test/functional/feature_evm_vmmap_rpc.py +++ b/test/functional/feature_evm_vmmap_rpc.py @@ -103,6 +103,7 @@ def vmmap_valid_tx_should_succeed(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -189,6 +190,7 @@ def vmmap_valid_block_should_succeed(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -242,6 +244,7 @@ def vmmap_valid_block_number_should_succeed(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -324,6 +327,7 @@ def vmmap_rollback_should_succeed(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -360,6 +364,7 @@ def logvmmaps_tx_exist(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -415,6 +420,7 @@ def vmmap_transfer_domain(self): "amount": "100@DFI", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -440,6 +446,7 @@ def vmmap_transfer_domain(self): "amount": "100@DFI", "domain": 2, }, + "singlekeycheck": False, } ] ) @@ -488,6 +495,7 @@ def vmmap_transfer_domain_dst20(self): "amount": "1@BTC", "domain": 3, }, + "singlekeycheck": False, } ] ) @@ -509,6 +517,7 @@ def vmmap_transfer_domain_dst20(self): "amount": "1@BTC", "domain": 2, }, + "singlekeycheck": False, } ] )