From 74ab2085b4ab84928a71df61af28f50ce7a221a0 Mon Sep 17 00:00:00 2001 From: Niven Date: Tue, 15 Aug 2023 11:54:27 +0800 Subject: [PATCH 01/50] Bug fixes to little endianness on dvm --- src/key.h | 10 ++++++++++ src/key_io.cpp | 5 ++--- src/masternodes/mn_checks.cpp | 3 +-- src/masternodes/rpc_accounts.cpp | 6 ++---- src/masternodes/rpc_evm.cpp | 14 +++++--------- test/functional/test_runner.py | 8 ++++---- 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/key.h b/src/key.h index 26699ab05e..41bb99e421 100644 --- a/src/key.h +++ b/src/key.h @@ -140,6 +140,16 @@ class CKey //! Load private key and check that public key matches. bool Load(const CPrivKey& privkey, const CPubKey& vchPubKey, bool fSkipCheck); + + std::array GetByteArray() const + { + // We store bytes in the reverse order. So any expectations of + // an array of bytes should be in same order as the hex string. + // The protected data array is an internal implementation detail. + std::array reversedArray; + std::copy(keydata.rbegin(), keydata.rend(), reversedArray.begin()); + return reversedArray; + } }; struct CExtKey { diff --git a/src/key_io.cpp b/src/key_io.cpp index 2daef35380..092e155938 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -63,9 +63,7 @@ class DestinationEncoder { // Raw addr = ETH_ADDR_PREFIX + HexStr(id); // Produce ERC55 checksum address: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md - // TODO: This should ideally be id.ToString() - // HexStr now is hashing the reversed form. - const auto address = HexStr(id); + const auto address = id.GetHex(); std::vector input(address.begin(), address.end()); std::vector output; sha3(input, output); @@ -95,6 +93,7 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par return CNoDestination(); } data = ParseHex(hex); + std::reverse(data.begin(), data.end()); return WitnessV16EthHash(uint160(data)); } if (DecodeBase58Check(str, data)) { diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 9c881c21ae..fd4ac73c95 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -4018,8 +4018,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { } auto txHash = tx.GetHash(); - auto evmTxHashBytes = std::vector(validateResults.tx_hash.begin(), validateResults.tx_hash.end()); - auto evmTxHash = uint256S(HexStr(evmTxHashBytes)); + auto evmTxHash = uint256::FromByteArray(validateResults.tx_hash); auto res = mnview.SetVMDomainTxEdge(VMDomainEdge::DVMToEVM, txHash, evmTxHash); if (!res) { LogPrintf("Failed to store DVMtoEVM TX hash for DFI TX %s\n", txHash.ToString()); diff --git a/src/masternodes/rpc_accounts.cpp b/src/masternodes/rpc_accounts.cpp index 238d0a4867..3ed0da26e8 100644 --- a/src/masternodes/rpc_accounts.cpp +++ b/src/masternodes/rpc_accounts.cpp @@ -477,8 +477,7 @@ UniValue getaccount(const JSONRPCRequest& request) { CTxDestination dest; if (ExtractDestination(reqOwner, dest) && dest.index() == WitV16KeyEthHashType) { const auto keyID = std::get(dest); - EvmAddressData address{}; - std::copy(keyID.begin(), keyID.end(), address.begin()); + EvmAddressData address = keyID.GetByteArray(); auto r = XResultValue(evm_try_get_balance(result, address)); if (!r) throw JSONRPCError(RPC_MISC_ERROR, r.msg); if (const auto balance = *r) { @@ -606,8 +605,7 @@ UniValue gettokenbalances(const JSONRPCRequest& request) { if (evm_dfi_lookup) { for (const auto keyID : pwallet->GetKeys()) { - EvmAddressData address{}; - std::copy(keyID.begin(), keyID.end(), address.begin()); + EvmAddressData address = keyID.GetByteArray(); auto res = XResultValue(evm_try_get_balance(result, address)); if (res) { auto evmAmount = *res; diff --git a/src/masternodes/rpc_evm.cpp b/src/masternodes/rpc_evm.cpp index 7a82f34022..c4fef25c02 100644 --- a/src/masternodes/rpc_evm.cpp +++ b/src/masternodes/rpc_evm.cpp @@ -76,8 +76,8 @@ UniValue evmtx(const JSONRPCRequest &request) { const auto fromEth = std::get(fromDest); const CKeyID keyId{fromEth}; - CKey key; - if (!pwallet->GetKey(keyId, key)) { + CKey privKey; + if (!pwallet->GetKey(keyId, privKey)) { throw JSONRPCError(RPC_WALLET_ERROR, "Private key for from address not found in wallet"); } @@ -109,7 +109,7 @@ UniValue evmtx(const JSONRPCRequest &request) { } const auto toEth = std::get(toDest); - std::copy(toEth.begin(), toEth.end(), to.begin()); + to = toEth.GetByteArray(); } const arith_uint256 valueParam = AmountFromValue(request.params[5]); @@ -127,9 +127,6 @@ UniValue evmtx(const JSONRPCRequest &request) { std::copy(inputVec.begin(), inputVec.end(), input.begin()); } - std::array privKey{}; - std::copy(key.begin(), key.end(), privKey.begin()); - CrossBoundaryResult result; const auto signedTx = evm_try_create_and_sign_tx(result, CreateTransactionContext{chainID, @@ -139,7 +136,7 @@ UniValue evmtx(const JSONRPCRequest &request) { to, value.GetByteArray(), input, - privKey}); + privKey.GetByteArray()}); if (!result.ok) { throw JSONRPCError(RPC_MISC_ERROR, strprintf("Failed to create and sign TX: %s", result.reason.c_str())); } @@ -313,8 +310,7 @@ UniValue vmmap(const JSONRPCRequest &request) { CrossBoundaryResult result; auto evmHash = evm_try_get_block_hash_by_number(result, height); crossBoundaryOkOrThrow(result); - auto evmBlockHash = std::vector(evmHash.begin(), evmHash.end()); - std::reverse(evmBlockHash.begin(), evmBlockHash.end()); + auto evmBlockHash = std::uint256::FromByteArray(evmHash); ResVal dvm_block = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, uint256(evmBlockHash)); if (!dvm_block) { throwInvalidParam(dvm_block.msg); diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index d4166a95d5..ff070d5066 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -295,19 +295,20 @@ "feature_loan_priceupdate.py", "feature_loan_vaultstate.py", "feature_loan.py", + "feature_dst20.py", "feature_evm_contracts.py", + "feature_evm_dfi_intrinsics.py", "feature_evm_logs.py", "feature_evm_fee.py", "feature_evm_genesis.py", "feature_evm_rollback.py", "feature_evm_rpc_transaction.py", "feature_evm_rpc.py", - "feature_evm_vmmap_rpc.py", "feature_evm_smart_contract.py", + "feature_evm_transaction_replacement.py", "feature_evm_transferdomain.py", + "feature_evm_vmmap_rpc.py", "feature_evm.py", - "feature_dst20.py", - "feature_evm_dfi_intrinsics.py", "feature_loan_low_interest.py", "feature_loan_estimatecollateral.py", "feature_vault_pct_check_factor.py", @@ -339,7 +340,6 @@ "feature_negative_interest.py", "rpc_getstoredinterest.py", "feature_dusd_loans.py", - "feature_evm_transaction_replacement.py", # Don't append tests at the end to avoid merge conflicts # Put them in a random line within the section that fits their approximate run-time ] From 34086b068819b02139e69a1211c3d7789bba8825 Mon Sep 17 00:00:00 2001 From: Niven Date: Tue, 15 Aug 2023 13:19:09 +0800 Subject: [PATCH 02/50] Revert changes on encoding decoding tx dest --- src/key_io.cpp | 3 +-- test/functional/feature_evm_rpc.py | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/key_io.cpp b/src/key_io.cpp index 092e155938..8a3e5a14ca 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -63,7 +63,7 @@ class DestinationEncoder { // Raw addr = ETH_ADDR_PREFIX + HexStr(id); // Produce ERC55 checksum address: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md - const auto address = id.GetHex(); + const auto address = HexStr(id); std::vector input(address.begin(), address.end()); std::vector output; sha3(input, output); @@ -93,7 +93,6 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par return CNoDestination(); } data = ParseHex(hex); - std::reverse(data.begin(), data.end()); return WitnessV16EthHash(uint160(data)); } if (DecodeBase58Check(str, data)) { diff --git a/test/functional/feature_evm_rpc.py b/test/functional/feature_evm_rpc.py index 26a4f7e9f1..4d4353fbc9 100755 --- a/test/functional/feature_evm_rpc.py +++ b/test/functional/feature_evm_rpc.py @@ -5,6 +5,7 @@ # file LICENSE or http://www.opensource.org/licenses/mit-license.php. """Test EVM behaviour""" +from test_framework.evm_key_pair import EvmKeyPair from test_framework.test_framework import DefiTestFramework from test_framework.util import ( assert_equal, @@ -49,6 +50,7 @@ def setup(self): self.nodes[0].importprivkey( "17b8cb134958b3d8422b6c43b0732fcdb8c713b524df2d45de12f0c7e214ba35" ) # toAddress + EvmKeyPair.validate_key(self.nodes[0].dumpprivkey(self.ethAddress), self.ethAddress) # Generate chain self.nodes[0].generate(101) From 0e2e97b6fafd8c5df8ebed26eacb9c7fa95348d1 Mon Sep 17 00:00:00 2001 From: Niven Date: Tue, 15 Aug 2023 13:20:04 +0800 Subject: [PATCH 03/50] Fix lint --- test/functional/feature_evm_rpc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/functional/feature_evm_rpc.py b/test/functional/feature_evm_rpc.py index 4d4353fbc9..0c0fec3f0b 100755 --- a/test/functional/feature_evm_rpc.py +++ b/test/functional/feature_evm_rpc.py @@ -50,7 +50,9 @@ def setup(self): self.nodes[0].importprivkey( "17b8cb134958b3d8422b6c43b0732fcdb8c713b524df2d45de12f0c7e214ba35" ) # toAddress - EvmKeyPair.validate_key(self.nodes[0].dumpprivkey(self.ethAddress), self.ethAddress) + EvmKeyPair.validate_key( + self.nodes[0].dumpprivkey(self.ethAddress), self.ethAddress + ) # Generate chain self.nodes[0].generate(101) From 9afcdfbcba849d8654a2f13d4b53bd2ebf2f82f6 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Tue, 15 Aug 2023 14:22:16 +0800 Subject: [PATCH 04/50] Add more key checks --- test/functional/feature_address_map.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/test/functional/feature_address_map.py b/test/functional/feature_address_map.py index 64613695a8..0386f41efa 100755 --- a/test/functional/feature_address_map.py +++ b/test/functional/feature_address_map.py @@ -60,14 +60,23 @@ def set_test_params(self): def setup(self): self.address = self.nodes[0].get_genesis_keys().ownerAuthAddress - self.ethAddress = "0x9b8a4af42140d8a4c153a822f02571a1dd037e89" - self.toAddress = "0x6c34cbb9219d8caa428835d2073e8ec88ba0a110" - self.nodes[0].importprivkey( - "af990cc3ba17e776f7f57fcc59942a82846d75833fa17d2ba59ce6858d886e23" - ) # ethAddress - self.nodes[0].importprivkey( - "17b8cb134958b3d8422b6c43b0732fcdb8c713b524df2d45de12f0c7e214ba35" - ) # toAddress + addr_keys = [ + [ + "0x9b8a4af42140d8a4c153a822f02571a1dd037e89", + "af990cc3ba17e776f7f57fcc59942a82846d75833fa17d2ba59ce6858d886e23", + ], + [ + "0x6c34cbb9219d8caa428835d2073e8ec88ba0a110", + "17b8cb134958b3d8422b6c43b0732fcdb8c713b524df2d45de12f0c7e214ba35", + ], + ] + + self.ethAddress = addr_keys[0][0] + self.toAddress = addr_keys[1][0] + + for [addr, key] in addr_keys: + self.nodes[0].importprivkey(key) + assert_equal(self.nodes[0].dumpprivkey(addr), key) # Generate chain self.nodes[0].generate(101) From bf08250df86f3160ee7fc6b40c666c19304bd316 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Tue, 15 Aug 2023 13:51:12 +0800 Subject: [PATCH 05/50] Cleanup hashing, add wallet tests --- src/crypto/sha3.cpp | 4 ++-- src/crypto/sha3.h | 4 +++- src/hash.h | 4 ++-- src/key_io.cpp | 2 +- src/pubkey.h | 4 +++- src/script/interpreter.cpp | 2 +- src/script/sign.cpp | 1 - src/script/signingprovider.cpp | 2 +- src/script/signingprovider.h | 4 ++-- src/test/pos_tests.cpp | 2 +- src/test/setup_common.cpp | 18 ++++++++++++++- src/test/setup_common.h | 39 ++++++++++++++++++++++++++++++++ src/test/transaction_tests.cpp | 12 +++++----- src/wallet/test/wallet_tests.cpp | 8 +++---- src/wallet/wallet.cpp | 8 +++---- src/wallet/wallet.h | 2 +- 16 files changed, 87 insertions(+), 29 deletions(-) diff --git a/src/crypto/sha3.cpp b/src/crypto/sha3.cpp index 8116de0d61..fd36a02975 100644 --- a/src/crypto/sha3.cpp +++ b/src/crypto/sha3.cpp @@ -174,9 +174,9 @@ defsha3(256) defsha3(384) defsha3(512) -bool sha3(const std::vector &input, std::vector &output) +bool sha3_256_safe(const std::vector &input, std::vector &output) { - output.resize(32); + output.resize(32); sha3_256(output.data(), 32, input.data(), input.size()); return true; } diff --git a/src/crypto/sha3.h b/src/crypto/sha3.h index 1f6db21edd..10c6761eae 100644 --- a/src/crypto/sha3.h +++ b/src/crypto/sha3.h @@ -3,6 +3,8 @@ #include -bool sha3(const std::vector &input, std::vector &output); +// SH3 256, but safer version, that always resizes the output to 256 bits. +// Otherwise, the internal sha3_256 call can fail. +bool sha3_256_safe(const std::vector &input, std::vector &output); #endif // DEFI_CRYPTO_SHA3_H \ No newline at end of file diff --git a/src/hash.h b/src/hash.h index bfacd6d843..78e1d3e807 100644 --- a/src/hash.h +++ b/src/hash.h @@ -128,9 +128,9 @@ inline uint160 Hash160(const prevector& vch) return Hash160(vch.begin(), vch.end()); } -inline uint160 Sha3(const std::vector& vch) { +inline uint160 EthHash160(const std::vector& vch) { std::vector output; - sha3(vch, output); + sha3_256_safe(vch, output); const size_t ADDRESS_OFFSET{12}; return uint160({output.begin() + ADDRESS_OFFSET, output.end()}); } diff --git a/src/key_io.cpp b/src/key_io.cpp index 2daef35380..60890cb473 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -68,7 +68,7 @@ class DestinationEncoder const auto address = HexStr(id); std::vector input(address.begin(), address.end()); std::vector output; - sha3(input, output); + sha3_256_safe(input, output); const auto hashedAddress = HexStr(output); std::string result; for (size_t i{}; i < address.size(); ++i) { diff --git a/src/pubkey.h b/src/pubkey.h index a07ccec084..883c6cddf7 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -194,7 +194,9 @@ class CPubKey CKeyID GetEthID() const { const size_t HEADER_OFFSET{1}; - return CKeyID(Sha3({vch + HEADER_OFFSET, vch + size()})); + auto begin = vch + HEADER_OFFSET; + auto end = vch + size(); + return CKeyID(EthHash160({begin, end})); } //! Get the 256-bit hash of this public key. diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 7f70619c30..e4f0a759e5 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -897,7 +897,7 @@ bool EvalScript(std::vector >& stack, const CScript& CSHA1().Write(vch.data(), vch.size()).Finalize(vchHash.data()); else if (opcode == OP_KECCAK) { const size_t HEADER_OFFSET{1}; - const auto result = Sha3({vch.begin() + HEADER_OFFSET, vch.end()}); + const auto result = EthHash160({vch.begin() + HEADER_OFFSET, vch.end()}); memcpy(vchHash.data(), result.begin(), 20); } else if (opcode == OP_SHA256) CSHA256().Write(vch.data(), vch.size()).Finalize(vchHash.data()); diff --git a/src/script/sign.cpp b/src/script/sign.cpp index d03499b6be..9f8bca5eb3 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -216,7 +216,6 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE, sigdata) && whichType != TX_SCRIPTHASH; P2SH = true; } - if (solved && whichType == TX_WITNESS_V0_KEYHASH) { CScript witnessscript; diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp index b93c2f7439..54479efac3 100644 --- a/src/script/signingprovider.cpp +++ b/src/script/signingprovider.cpp @@ -108,7 +108,7 @@ bool FillableSigningProvider::GetPubKey(const CKeyID &address, CPubKey &vchPubKe return true; } -bool FillableSigningProvider::AddKeyPubKey(const CKey& key, const CPubKey &pubkey) +bool FillableSigningProvider::AddKeyPair(const CKey& key, const CPubKey &pubkey) { LOCK(cs_KeyStore); diff --git a/src/script/signingprovider.h b/src/script/signingprovider.h index bdfaea873e..927fdceead 100644 --- a/src/script/signingprovider.h +++ b/src/script/signingprovider.h @@ -74,8 +74,8 @@ class FillableSigningProvider : public SigningProvider void ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); public: - virtual bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); - virtual bool AddKey(const CKey &key) { return AddKeyPubKey(key, key.GetPubKey()); } + virtual bool AddKeyPair(const CKey& key, const CPubKey &pubkey); + virtual bool AddKey(const CKey &key) { return AddKeyPair(key, key.GetPubKey()); } virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override; virtual bool HaveKey(const CKeyID &address) const override; virtual std::set GetKeys() const; diff --git a/src/test/pos_tests.cpp b/src/test/pos_tests.cpp index 2339070f91..5e49dcc794 100644 --- a/src/test/pos_tests.cpp +++ b/src/test/pos_tests.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(calc_kernel) // CKey key; // key.MakeNewKey(true); // Need to use compressed keys in segwit or the signing will fail // FillableSigningProvider keystore; -// BOOST_CHECK(keystore.AddKeyPubKey(key, key.GetPubKey())); +// BOOST_CHECK(keystore.AddKeyPair(key, key.GetPubKey())); // CKeyID keyID = key.GetPubKey().GetID(); // // uint256 prevStakeModifier = uint256S("fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321"); diff --git a/src/test/setup_common.cpp b/src/test/setup_common.cpp index a29ad05681..8eeb333f3a 100644 --- a/src/test/setup_common.cpp +++ b/src/test/setup_common.cpp @@ -22,6 +22,7 @@ #include #include