From c9fc0ec229d5e07b3256113fb92390b230b9bf1b Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Thu, 17 Aug 2023 07:24:34 +0800 Subject: [PATCH 01/22] Isolate linux specific helpers (#2336) * Isolate linux specific helpers * Add comments --- src/test/setup_common.cpp | 35 ++++++++++++++++++++--------------- src/test/setup_common.h | 4 ++++ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/test/setup_common.cpp b/src/test/setup_common.cpp index 84208649f0..1a66c6c179 100644 --- a/src/test/setup_common.cpp +++ b/src/test/setup_common.cpp @@ -33,6 +33,26 @@ #ifdef __linux__ #include + +// Use addr2line for symbols. Eg: +// addr2line --exe=$(pwd)/build/src/test/test_defi -afCp 0x3ce23a2 + +void print_backtrace() +{ + void* array[10]; + char** strings; + int size, i; + size = backtrace(array, 10); + strings = backtrace_symbols(array, size); + if (strings != NULL) { + std::cout << "Obtained " << size << "stack frames.\n"; + for (i = 0; i < size; i++) { + std::cout << strings[i] << "\n"; + } + } + free(strings); +} + #endif // defined (__linux__) const std::function G_TRANSLATION_FUN = nullptr; @@ -270,18 +290,3 @@ CBlock getBlock13b8a() return block; } -void print_backtrace() -{ - void* array[10]; - char** strings; - int size, i; - size = backtrace(array, 10); - strings = backtrace_symbols(array, size); - if (strings != NULL) { - std::cout << "Obtained " << size << "stack frames.\n"; - for (i = 0; i < size; i++) { - std::cout << strings[i] << "\n"; - } - } - free(strings); -} \ No newline at end of file diff --git a/src/test/setup_common.h b/src/test/setup_common.h index 8a26e9606c..8818513071 100644 --- a/src/test/setup_common.h +++ b/src/test/setup_common.h @@ -168,6 +168,10 @@ struct StdOutTestStreamRedirectScope : StdOutRedirectScope { boost::test_tools::output_test_stream output{}; }; +#ifdef __linux__ + void print_backtrace(); #endif + +#endif From 58689591b92f1a3cef3ad901fd54a40a49398f69 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Thu, 17 Aug 2023 16:17:42 +0800 Subject: [PATCH 02/22] Abstract and reduce noise in transfer domain tests (#2338) * Isolate linux specific helpers * Reduce transfer domain noise --- test/functional/feature_evm_transferdomain.py | 229 +++--------------- 1 file changed, 35 insertions(+), 194 deletions(-) diff --git a/test/functional/feature_evm_transferdomain.py b/test/functional/feature_evm_transferdomain.py index 4f3f763eaf..076833b0f1 100755 --- a/test/functional/feature_evm_transferdomain.py +++ b/test/functional/feature_evm_transferdomain.py @@ -9,31 +9,22 @@ from decimal import Decimal +def transfer_domain(node, fromAddr, toAddr, amount, fromDomain, toDomain): + return node.transferdomain([ + { + "src": {"address": fromAddr, "amount": amount, "domain": fromDomain}, + "dst": { + "address": toAddr, + "amount": amount, + "domain": toDomain, + } + }]) + class EVMTest(DefiTestFramework): def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True - self.extra_args = [ - [ - "-txordering=2", - "-dummypos=0", - "-txnotokens=0", - "-amkheight=50", - "-bayfrontheight=51", - "-eunosheight=80", - "-fortcanningheight=82", - "-fortcanninghillheight=84", - "-fortcanningroadheight=86", - "-fortcanningcrunchheight=88", - "-fortcanningspringheight=90", - "-fortcanninggreatworldheight=94", - "-fortcanningepilogueheight=96", - "-grandcentralheight=101", - "-nextnetworkupgradeheight=150", - "-subsidytest=1", - "-txindex=1", - ], - [ + node_args = [ "-txordering=2", "-dummypos=0", "-txnotokens=0", @@ -51,8 +42,8 @@ def set_test_params(self): "-nextnetworkupgradeheight=150", "-subsidytest=1", "-txindex=1", - ], ] + self.extra_args = [ node_args, node_args ] def setup(self): self.address = self.nodes[0].get_genesis_keys().ownerAuthAddress @@ -157,17 +148,7 @@ def invalid_before_fork_and_disabled(self): assert_raises_rpc_error( -32600, "called before NextNetworkUpgrade height", - self.nodes[0].transferdomain, - [ - { - "src": {"address": self.address, "amount": "100@DFI", "domain": 2}, - "dst": { - "address": self.eth_address, - "amount": "100@DFI", - "domain": 3, - }, - } - ], + lambda: transfer_domain(self.nodes[0], self.address, self.eth_address, "100@DFI", 2, 3) ) # Move to fork height @@ -176,17 +157,7 @@ def invalid_before_fork_and_disabled(self): assert_raises_rpc_error( -32600, "Cannot create tx, transfer domain is not enabled", - self.nodes[0].transferdomain, - [ - { - "src": {"address": self.address, "amount": "100@DFI", "domain": 2}, - "dst": { - "address": self.eth_address, - "amount": "100@DFI", - "domain": 3, - }, - } - ], + lambda: transfer_domain(self.nodes[0], self.address, self.eth_address, "100@DFI", 2, 3) ) # Activate EVM @@ -199,17 +170,7 @@ def invalid_before_fork_and_disabled(self): assert_raises_rpc_error( -32600, "Cannot create tx, transfer domain is not enabled", - self.nodes[0].transferdomain, - [ - { - "src": {"address": self.address, "amount": "100@DFI", "domain": 2}, - "dst": { - "address": self.eth_address, - "amount": "100@DFI", - "domain": 3, - }, - } - ], + lambda: transfer_domain(self.nodes[0], self.address, self.eth_address, "100@DFI", 2, 3) ) # Activate transferdomain @@ -232,32 +193,12 @@ def invalid_before_fork_and_disabled(self): assert_raises_rpc_error( -32600, "DVM to EVM is not currently enabled", - self.nodes[0].transferdomain, - [ - { - "src": {"address": self.address, "amount": "100@DFI", "domain": 2}, - "dst": { - "address": self.eth_address, - "amount": "100@DFI", - "domain": 3, - }, - } - ], + lambda: transfer_domain(self.nodes[0], self.address, self.eth_address, "100@DFI", 2, 3) ) assert_raises_rpc_error( -32600, "EVM to DVM is not currently enabled", - self.nodes[0].transferdomain, - [ - { - "src": {"address": self.address, "amount": "100@DFI", "domain": 3}, - "dst": { - "address": self.eth_address, - "amount": "100@DFI", - "domain": 2, - }, - } - ], + lambda: transfer_domain(self.nodes[0], self.address, self.eth_address, "100@DFI", 3, 2) ) self.nodes[0].setgov( @@ -273,32 +214,12 @@ def invalid_before_fork_and_disabled(self): assert_raises_rpc_error( -32600, "transferdomain for DST20 from DVM to EVM is not enabled", - self.nodes[0].transferdomain, - [ - { - "src": {"address": self.address, "amount": "1@BTC", "domain": 2}, - "dst": { - "address": self.eth_address, - "amount": "1@BTC", - "domain": 3, - }, - } - ], + lambda: transfer_domain(self.nodes[0], self.address, self.eth_address, "1@BTC", 2, 3) ) assert_raises_rpc_error( -32600, "transferdomain for DST20 from EVM to DVM is not enabled", - self.nodes[0].transferdomain, - [ - { - "src": {"address": self.address, "amount": "1@BTC", "domain": 3}, - "dst": { - "address": self.eth_address, - "amount": "1@BTC", - "domain": 2, - }, - } - ], + lambda: transfer_domain(self.nodes[0], self.address, self.eth_address, "1@BTC", 3, 2) ) # Activate DAT transferdomain @@ -455,49 +376,19 @@ def invalid_parameters(self): def invalid_values_dvm_evm(self): # Check for valid values DVM->EVM in transferdomain rpc assert_raises_rpc_error( - -32600, - 'Src address must be a legacy or Bech32 address in case of "DVM" domain', - self.nodes[0].transferdomain, - [ - { - "src": { - "address": self.eth_address, - "amount": "100@DFI", - "domain": 2, - }, - "dst": { - "address": self.eth_address, - "amount": "100@DFI", - "domain": 3, - }, - } - ], + None, + None, + lambda: transfer_domain(self.nodes[0], self.address, self.eth_address, "100@DFI", 2, 3) ) assert_raises_rpc_error( -32600, 'Dst address must be an ERC55 address in case of "EVM" domain', - self.nodes[0].transferdomain, - [ - { - "src": {"address": self.address, "amount": "100@DFI", "domain": 2}, - "dst": {"address": self.address, "amount": "100@DFI", "domain": 3}, - } - ], + lambda: transfer_domain(self.nodes[0], self.address, self.address, "100@DFI", 2, 3) ) assert_raises_rpc_error( -32600, "Cannot transfer inside same domain", - self.nodes[0].transferdomain, - [ - { - "src": {"address": self.address, "amount": "100@DFI", "domain": 2}, - "dst": { - "address": self.eth_address, - "amount": "100@DFI", - "domain": 2, - }, - } - ], + lambda: transfer_domain(self.nodes[0], self.address, self.eth_address, "100@DFI", 2, 2) ) assert_raises_rpc_error( -32600, @@ -553,56 +444,17 @@ def invalid_values_dvm_evm(self): assert_raises_rpc_error( -32600, "Non-DAT or LP tokens are not supported for transferdomain", - self.nodes[0].transferdomain, - [ - { - "src": { - "address": self.address, - "amount": "1@" + self.symbolUSER, - "domain": 2, - }, - "dst": { - "address": self.eth_address, - "amount": "1@" + self.symbolUSER, - "domain": 3, - }, - } - ], + lambda: transfer_domain(self.nodes[0], self.address, self.eth_address, "1@" + self.symbolUSER, 2, 3) ) assert_raises_rpc_error( -32600, "Non-DAT or LP tokens are not supported for transferdomain", - self.nodes[0].transferdomain, - [ - { - "src": { - "address": self.address, - "amount": "1@" + self.symbolBTCDFI, - "domain": 2, - }, - "dst": { - "address": self.eth_address, - "amount": "1@" + self.symbolBTCDFI, - "domain": 3, - }, - } - ], + lambda: transfer_domain(self.nodes[0], self.address, self.eth_address, "1@" + self.symbolBTCDFI, 2, 3) ) def valid_transfer_dvm_evm(self): # Transfer 100 DFI from DVM to EVM - tx1 = self.nodes[0].transferdomain( - [ - { - "src": {"address": self.address, "amount": "100@DFI", "domain": 2}, - "dst": { - "address": self.eth_address, - "amount": "100@DFI", - "domain": 3, - }, - } - ] - ) + tx1 = transfer_domain(self.nodes[0], self.address, self.eth_address, "100@DFI", 2, 3) self.nodes[0].generate(1) # Check tx1 fields @@ -666,8 +518,8 @@ def invalid_values_evm_dvm(self): ], ) assert_raises_rpc_error( - -32600, - 'Dst address must be a legacy or Bech32 address in case of "DVM" domain', + None, + None, self.nodes[0].transferdomain, [ { @@ -685,8 +537,8 @@ def invalid_values_evm_dvm(self): ], ) assert_raises_rpc_error( - -32600, - "Cannot transfer inside same domain", + None, + None, self.nodes[0].transferdomain, [ { @@ -700,8 +552,8 @@ def invalid_values_evm_dvm(self): ], ) assert_raises_rpc_error( - -32600, - "Source amount must be equal to destination amount", + None, + None, self.nodes[0].transferdomain, [ { @@ -787,18 +639,7 @@ def valid_transfer_evm_dvm(self): self.valid_transfer_dvm_evm() # Transfer 100 DFI from EVM to DVM - tx = self.nodes[0].transferdomain( - [ - { - "src": { - "address": self.eth_address, - "amount": "100@DFI", - "domain": 3, - }, - "dst": {"address": self.address, "amount": "100@DFI", "domain": 2}, - } - ] - ) + tx = transfer_domain(self.nodes[0], self.eth_address, self.address, "100@DFI", 3, 2) self.nodes[0].generate(1) # Check tx fields From 1ce233557a418608444e6273f5abbf892baab7a7 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Thu, 17 Aug 2023 16:17:52 +0800 Subject: [PATCH 03/22] Add ExtendedTxToUniv, VmInfoUniv for better logging (#2339) * Isolate linux specific helpers * Reduce transfer domain noise * Add ExtendedTxToUniv --- src/rpc/blockchain.cpp | 47 ++++++++++++++++++++++++------------------ src/rpc/blockchain.h | 4 ++++ 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index f5180d3948..96348adeaa 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -266,12 +266,9 @@ struct RewardInfo { } }; -UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails, int version) -{ - // Serialize passed information without accessing chain state of the active chain! - AssertLockNotHeld(cs_main); // For performance reasons - const auto consensus = Params().GetConsensus(); +std::optional VmInfoUniv(const CTransaction& tx) { + auto evmBlockHeaderToUniValue = [](const EVMBlockHeader& header) { UniValue r(UniValue::VOBJ); r.pushKV("parenthash", uint256::FromByteArray(header.parent_hash).ToString()); @@ -287,7 +284,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn return r; }; - auto txVmInfo = [&evmBlockHeaderToUniValue](const CTransaction& tx) -> std::optional { CustomTxType guess; UniValue txResults(UniValue::VOBJ); if (tx.IsCoinBase()) { @@ -322,24 +318,35 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn result.pushKV("msg", txResults); } return result; - }; +} + +UniValue ExtendedTxToUniv(const CTransaction& tx, bool include_hex, int serialize_flags, int version, bool txDetails) { - auto txsToUniValue = [&txVmInfo](const CBlock& block, bool txDetails, int version) { + if (txDetails) { + UniValue objTx(UniValue::VOBJ); + TxToUniv(tx, uint256(), objTx, version != 3, RPCSerializationFlags(), version); + if (version > 2) { + if (auto r = VmInfoUniv(tx); r) { + objTx.pushKV("vm", *r); + } + } + return objTx; + } else { + return tx.GetHash().GetHex(); + } +} + +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails, int version) +{ + // Serialize passed information without accessing chain state of the active chain! + AssertLockNotHeld(cs_main); // For performance reasons + const auto consensus = Params().GetConsensus(); + + auto txsToUniValue = [](const CBlock& block, bool txDetails, int version) { UniValue txs(UniValue::VARR); for(const auto& tx : block.vtx) { - if (txDetails) { - UniValue objTx(UniValue::VOBJ); - TxToUniv(*tx, uint256(), objTx, version != 3, RPCSerializationFlags(), version); - if (version > 2) { - if (auto r = txVmInfo(*tx); r) { - objTx.pushKV("vm", *r); - } - } - txs.push_back(objTx); - } else { - txs.push_back(tx->GetHash().GetHex()); - } + txs.push_back(ExtendedTxToUniv(*tx, txDetails, RPCSerializationFlags(), version, txDetails)); } return txs; }; diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index 4cc8de4d1b..308c6ef720 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -17,6 +17,7 @@ class CBlock; class CBlockIndex; class CTxMemPool; class UniValue; +class CTransaction; static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5; @@ -31,6 +32,9 @@ double GetDifficulty(const CBlockIndex* blockindex); /** Callback for when block tip changed. */ void RPCNotifyBlockChange(bool ibd, const CBlockIndex *); +std::optional VmInfoUniv(const CTransaction& tx); +UniValue ExtendedTxToUniv(const CTransaction& tx, bool include_hex, int serialize_flags, int version, bool txDetails); + /** Block description to JSON */ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false, int verbosity = 0) LOCKS_EXCLUDED(cs_main); From 7fda957868253ca207154995083d98790099423c Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Fri, 18 Aug 2023 07:24:35 +0800 Subject: [PATCH 04/22] Adding logging category CONNECT, SIGN (#2340) * Isolate linux specific helpers * Reduce transfer domain noise * Add ExtendedTxToUniv * Add log category CONNECT and SIGN * Split more --- src/core_io.h | 4 ++ src/core_write.cpp | 82 ++++++++++++++++----------------- src/logging.h | 4 +- src/rpc/blockchain.cpp | 67 +++++++++++++-------------- src/rpc/rawtransaction_util.cpp | 10 ++++ src/validation.cpp | 6 +++ 6 files changed, 96 insertions(+), 77 deletions(-) diff --git a/src/core_io.h b/src/core_io.h index 0bcae456c8..faaaa38152 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -15,6 +15,8 @@ class CBlock; class CBlockHeader; class CScript; class CTransaction; +class CTxIn; +class CTxOut; struct CMutableTransaction; class uint256; class UniValue; @@ -46,6 +48,8 @@ std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0); std::string SighashToStr(unsigned char sighash_type); void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); void ScriptToUniv(const CScript& script, UniValue& out, bool include_address); +UniValue TxInToUniv(const CTransaction& tx, const CTxIn& txin, const unsigned int index, bool include_hex, int version); +UniValue TxOutToUniv(const CTransaction& tx, const CTxOut& txout, const unsigned int index, bool include_hex, int version); void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, int verbosity = 0); #endif // DEFI_CORE_IO_H diff --git a/src/core_write.cpp b/src/core_write.cpp index 8f690047f4..b234fb3e34 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -183,48 +183,48 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("addresses", a); } -void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, int version) -{ - const auto txInToUniValue = [](const CTransaction& tx, const CTxIn& txin, const unsigned int index, bool include_hex, int version) { - UniValue in(UniValue::VOBJ); - if (tx.IsCoinBase()) - in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); - else { - in.pushKV("txid", txin.prevout.hash.GetHex()); - in.pushKV("vout", (int64_t)txin.prevout.n); - UniValue o(UniValue::VOBJ); - o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); - if (include_hex || version <= 2) { - o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); - } - in.pushKV("scriptSig", o); - if (!tx.vin[index].scriptWitness.IsNull()) { - UniValue txinwitness(UniValue::VARR); - for (const auto& item : tx.vin[index].scriptWitness.stack) { - txinwitness.push_back(HexStr(item.begin(), item.end())); - } - in.pushKV("txinwitness", txinwitness); - } - } - in.pushKV("sequence", (int64_t)txin.nSequence); - return in; - }; - - const auto txOutToUniValue = [](const CTransaction& tx, const CTxOut& txout, const unsigned int index, bool include_hex, int version) { - UniValue out(UniValue::VOBJ); - out.pushKV("value", ValueFromAmount(txout.nValue)); - out.pushKV("n", (int64_t)index); +UniValue TxInToUniv(const CTransaction& tx, const CTxIn& txin, const unsigned int index, bool include_hex, int version) { + UniValue in(UniValue::VOBJ); + if (tx.IsCoinBase()) + in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); + else { + in.pushKV("txid", txin.prevout.hash.GetHex()); + in.pushKV("vout", (int64_t)txin.prevout.n); UniValue o(UniValue::VOBJ); - ScriptPubKeyToUniv(txout.scriptPubKey, o, include_hex || version <= 2); - out.pushKV("scriptPubKey", o); - // We skip this for v3+ as we tokenId field is unused. - if (version <= 2 && tx.nVersion >= CTransaction::TOKENS_MIN_VERSION) { - // Start to print tokenId start from version TOKENS_MIN_VERSION - out.pushKV("tokenId", (uint64_t)txout.nTokenId.v); + o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); + if (include_hex || version != 3) { + o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); + } + in.pushKV("scriptSig", o); + if (!tx.vin[index].scriptWitness.IsNull()) { + UniValue txinwitness(UniValue::VARR); + for (const auto& item : tx.vin[index].scriptWitness.stack) { + txinwitness.push_back(HexStr(item.begin(), item.end())); + } + in.pushKV("txinwitness", txinwitness); } - return out; - }; + } + in.pushKV("sequence", (int64_t)txin.nSequence); + return in; +} +UniValue TxOutToUniv(const CTransaction& tx, const CTxOut& txout, const unsigned int index, bool include_hex, int version) { + UniValue out(UniValue::VOBJ); + out.pushKV("value", ValueFromAmount(txout.nValue)); + out.pushKV("n", (int64_t)index); + UniValue o(UniValue::VOBJ); + ScriptPubKeyToUniv(txout.scriptPubKey, o, include_hex || version != 3); + out.pushKV("scriptPubKey", o); + // We skip this for v3+ as we tokenId field is unused. + if (version <= 2 && tx.nVersion >= CTransaction::TOKENS_MIN_VERSION) { + // Start to print tokenId start from version TOKENS_MIN_VERSION + out.pushKV("tokenId", (uint64_t)txout.nTokenId.v); + } + return out; +} + +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, int version) +{ entry.pushKV("txid", tx.GetHash().GetHex()); entry.pushKV("hash", tx.GetWitnessHash().GetHex()); entry.pushKV("version", tx.nVersion); @@ -235,13 +235,13 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, UniValue vin(UniValue::VARR); for (unsigned int i = 0; i < tx.vin.size(); i++) { - vin.push_back(txInToUniValue(tx, tx.vin[i], i, include_hex, version)); + vin.push_back(TxInToUniv(tx, tx.vin[i], i, include_hex, version)); } entry.pushKV("vin", vin); UniValue vout(UniValue::VARR); for (unsigned int i = 0; i < tx.vout.size(); i++) { - vout.push_back(txOutToUniValue(tx, tx.vout[i], i, include_hex, version)); + vout.push_back(TxOutToUniv(tx, tx.vout[i], i, include_hex, version)); } entry.pushKV("vout", vout); diff --git a/src/logging.h b/src/logging.h index 4835f86f5d..4988aa102e 100644 --- a/src/logging.h +++ b/src/logging.h @@ -65,6 +65,8 @@ namespace BCLog { TOKENSPLIT = (1UL << 28), RPCCACHE = (1UL << 29), CUSTOMTXBENCH = (1UL << 30), + CONNECT = (1UL << 31), + SIGN = (1UL << 32), ALL = ~(0UL), }; @@ -84,7 +86,7 @@ namespace BCLog { std::atomic_bool m_started_new_line{true}; /** Log categories bitfield. */ - std::atomic m_categories{0}; + std::atomic m_categories{0}; std::string LogTimestampStr(const std::string& str); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 96348adeaa..de2b3ed484 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -268,7 +268,6 @@ struct RewardInfo { std::optional VmInfoUniv(const CTransaction& tx) { - auto evmBlockHeaderToUniValue = [](const EVMBlockHeader& header) { UniValue r(UniValue::VOBJ); r.pushKV("parenthash", uint256::FromByteArray(header.parent_hash).ToString()); @@ -284,45 +283,44 @@ std::optional VmInfoUniv(const CTransaction& tx) { return r; }; - CustomTxType guess; - UniValue txResults(UniValue::VOBJ); - if (tx.IsCoinBase()) { - if (tx.vout.size() < 2) { - // TODO: Decode vout 0 to dvm - return {}; - } - auto tx1ScriptPubKey = tx.vout[1].scriptPubKey; - if (tx1ScriptPubKey.size() == 0) return {}; - auto xvm = XVM::TryFrom(tx1ScriptPubKey); - if (!xvm) return {}; - UniValue result(UniValue::VOBJ); - result.pushKV("vmtype", "coinbase"); - result.pushKV("txtype", "coinbase"); - result.pushKV("msg", xvm->ToUniValue()); - CrossBoundaryResult res; - auto evmBlockHeader = evm_try_get_block_header_by_hash(res, xvm->evm.blockHash.GetByteArray()); - if (!res.ok) return {}; - result.pushKV("xvmHeader", evmBlockHeaderToUniValue(evmBlockHeader)); - return result; - } - auto res = RpcInfo(tx, std::numeric_limits::max(), guess, txResults); - if (guess == CustomTxType::None) { + CustomTxType guess; + UniValue txResults(UniValue::VOBJ); + if (tx.IsCoinBase()) { + if (tx.vout.size() < 2) { + // TODO: Decode vout 0 to dvm return {}; } + auto tx1ScriptPubKey = tx.vout[1].scriptPubKey; + if (tx1ScriptPubKey.size() == 0) return {}; + auto xvm = XVM::TryFrom(tx1ScriptPubKey); + if (!xvm) return {}; UniValue result(UniValue::VOBJ); - result.pushKV("vmtype", guess == CustomTxType::EvmTx ? "evm" : "dvm"); - result.pushKV("txtype", ToString(guess)); - if (!res.ok) { - result.pushKV("error", res.msg); - } else { - result.pushKV("msg", txResults); - } + result.pushKV("vmtype", "coinbase"); + result.pushKV("txtype", "coinbase"); + result.pushKV("msg", xvm->ToUniValue()); + CrossBoundaryResult res; + auto evmBlockHeader = evm_try_get_block_header_by_hash(res, xvm->evm.blockHash.GetByteArray()); + if (!res.ok) return {}; + result.pushKV("xvmHeader", evmBlockHeaderToUniValue(evmBlockHeader)); return result; + } + auto res = RpcInfo(tx, std::numeric_limits::max(), guess, txResults); + if (guess == CustomTxType::None) { + return {}; + } + UniValue result(UniValue::VOBJ); + result.pushKV("vmtype", guess == CustomTxType::EvmTx ? "evm" : "dvm"); + result.pushKV("txtype", ToString(guess)); + if (!res.ok) { + result.pushKV("error", res.msg); + } else { + result.pushKV("msg", txResults); + } + return result; } UniValue ExtendedTxToUniv(const CTransaction& tx, bool include_hex, int serialize_flags, int version, bool txDetails) { - - if (txDetails) { + if (txDetails) { UniValue objTx(UniValue::VOBJ); TxToUniv(tx, uint256(), objTx, version != 3, RPCSerializationFlags(), version); if (version > 2) { @@ -344,8 +342,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn auto txsToUniValue = [](const CBlock& block, bool txDetails, int version) { UniValue txs(UniValue::VARR); - for(const auto& tx : block.vtx) - { + for(const auto& tx : block.vtx) { txs.push_back(ExtendedTxToUniv(*tx, txDetails, RPCSerializationFlags(), version, txDetails)); } return txs; diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index 6fd9fccf3a..06f660a211 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -296,8 +296,14 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std:: vErrorsRet.push_back(entry); } +int RPCSerializationFlags(); +UniValue ExtendedTxToUniv(const CTransaction& tx, bool include_hex, int serialize_flags, int version, bool txDetails); + UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map& coins, bool is_temp_keystore, const UniValue& hashType) { + if (LogAcceptCategory(BCLog::SIGN)) { + LogPrintf("SignTransaction::Pre: %s\n", ExtendedTxToUniv(CTransaction(mtx), true, RPCSerializationFlags(), 4, true).write(2)); + } // Add previous txouts given in the RPC call: if (!prevTxsUnival.isNull()) { UniValue prevTxs = prevTxsUnival.get_array(); @@ -425,6 +431,10 @@ UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival } bool fComplete = vErrors.empty(); + if (LogAcceptCategory(BCLog::SIGN)) { + LogPrintf("SignTransaction::Post: %s\n", ExtendedTxToUniv(CTransaction(mtx), true, RPCSerializationFlags(), 4, true).write(2)); + } + UniValue result(UniValue::VOBJ); result.pushKV("hex", EncodeHexTx(CTransaction(mtx))); result.pushKV("complete", fComplete); diff --git a/src/validation.cpp b/src/validation.cpp index 63d6f8547d..6df3252177 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -72,6 +72,8 @@ #define MICRO 0.000001 #define MILLI 0.001 +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails, int version); + bool CBlockIndexWorkComparator::operator()(const CBlockIndex *pa, const CBlockIndex *pb) const { // First sort by most total work, ... if (pa->nChainWork > pb->nChainWork) return false; @@ -3406,6 +3408,9 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, nTimePostConnect * MILLI / nBlocksTotal); LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime1) * MILLI, nTimeTotal * MICRO, nTimeTotal * MILLI / nBlocksTotal); + if (LogAcceptCategory(BCLog::CONNECT)) { + LogPrintf("ConnectTip: %s\n", blockToJSON(*pthisBlock, pindexNew, pindexNew, true, 4).write(2)); + } connectTrace.BlockConnected(pindexNew, std::move(pthisBlock)); return true; } @@ -3500,6 +3505,7 @@ static CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOC return nullptr; } + /** * Try to make some progress towards making pindexMostWork the active block. * pblock is either nullptr or a pointer to a CBlock corresponding to pindexMostWork. From f278de4dd80d526e0439b2401bdf828b5821586b Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Fri, 18 Aug 2023 01:25:47 +0200 Subject: [PATCH 05/22] EVM: DST20 migration TX (#2327) * Add DST20 migration TX and receipt * Temporary disable of ValidateCoinbaseXVMOutput * Temporary disable of rollback related test failure * Extract contract (tx, receipt) creation * Fix test balance issue * Revert "Temporary disable of ValidateCoinbaseXVMOutput" This reverts commit 91fa9aefb79a54cc6c7cd2a2815922a7cbb37012. * Fix test * Refactor to add migration txs in construct_block when genesis EVM block * Get loan tokens from cache * Restore failing test * Remove block cloning * Fix hash used in recover sender address * Use same sender address for receipt and SignedTx * Index bytecode on migration * Restore failing test * Use token_id as migratory TX nonce --- lib/ain-contracts/src/lib.rs | 4 +- lib/ain-cpp-imports/src/bridge.rs | 9 ++ lib/ain-cpp-imports/src/lib.rs | 14 ++ lib/ain-evm/src/evm.rs | 108 ++++++++++++--- lib/ain-evm/src/receipt.rs | 20 +-- lib/ain-evm/src/transaction/mod.rs | 49 +------ lib/ain-evm/src/transaction/system.rs | 1 + lib/ain-rs-exports/src/evm.rs | 9 +- lib/ain-rs-exports/src/lib.rs | 7 +- src/ffi/ffiexports.cpp | 15 +++ src/ffi/ffiexports.h | 7 + src/masternodes/errors.h | 4 - src/masternodes/govvariables/attributes.cpp | 4 +- src/masternodes/mn_checks.cpp | 10 +- src/masternodes/validation.cpp | 50 +------ src/masternodes/validation.h | 2 - src/miner.cpp | 9 +- test/functional/feature_dst20.py | 141 +++++++++++++++++++- 18 files changed, 317 insertions(+), 146 deletions(-) diff --git a/lib/ain-contracts/src/lib.rs b/lib/ain-contracts/src/lib.rs index 2f48aa88a3..29a8543578 100644 --- a/lib/ain-contracts/src/lib.rs +++ b/lib/ain-contracts/src/lib.rs @@ -76,8 +76,8 @@ pub fn get_dst20_codehash() -> Result { Ok(Blake2Hasher::hash(&bytecode)) } -pub fn dst20_address_from_token_id(token_id: &str) -> Result { - let number_str = format!("{:x}", token_id.parse::()?); +pub fn dst20_address_from_token_id(token_id: u64) -> Result { + let number_str = format!("{:x}", token_id); let padded_number_str = format!("{number_str:0>38}"); let final_str = format!("ff{padded_number_str}"); diff --git a/lib/ain-cpp-imports/src/bridge.rs b/lib/ain-cpp-imports/src/bridge.rs index 32e14feed2..00446242aa 100644 --- a/lib/ain-cpp-imports/src/bridge.rs +++ b/lib/ain-cpp-imports/src/bridge.rs @@ -7,9 +7,17 @@ pub mod ffi { pub finality_count: u64, } + #[derive(Debug, Clone)] + pub struct DST20Token { + pub id: u64, + pub name: String, + pub symbol: String, + } + unsafe extern "C++" { include!("ffi/ffiexports.h"); type Attributes; + type DST20Token; fn getChainId() -> u64; fn isMining() -> bool; @@ -28,5 +36,6 @@ pub mod ffi { fn getCurrentHeight() -> i32; fn getAttributeDefaults() -> Attributes; fn CppLogPrintf(message: String); + fn getDST20Tokens(mnview_ptr: usize) -> Vec; } } diff --git a/lib/ain-cpp-imports/src/lib.rs b/lib/ain-cpp-imports/src/lib.rs index ad6f2c81bd..0c068c2138 100644 --- a/lib/ain-cpp-imports/src/lib.rs +++ b/lib/ain-cpp-imports/src/lib.rs @@ -15,6 +15,12 @@ mod ffi { pub finality_count: u64, } + pub struct DST20Token { + pub id: u64, + pub name: String, + pub symbol: String, + } + const UNIMPL_MSG: &str = "This cannot be used on a test path"; pub fn getChainId() -> u64 { unimplemented!("{}", UNIMPL_MSG) @@ -69,6 +75,10 @@ mod ffi { // Intentionally left empty, so it can be used from everywhere. // Just the logs are skipped. } + + pub fn getDST20Tokens(_mnview_ptr: usize) -> Vec { + unimplemented!("{}", UNIMPL_MSG) + } } pub use ffi::Attributes; @@ -155,5 +165,9 @@ pub fn log_print(message: &str) { ffi::CppLogPrintf(message.to_owned()); } +pub fn get_dst20_tokens(mnview_ptr: usize) -> Vec { + ffi::getDST20Tokens(mnview_ptr) +} + #[cfg(test)] mod tests {} diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index ed7f5541d7..4b6adb074f 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -3,7 +3,10 @@ use std::sync::Arc; use ain_contracts::{Contracts, CONTRACT_ADDRESSES}; use anyhow::format_err; -use ethereum::{Block, PartialHeader, ReceiptV3}; +use ethereum::{ + Block, EIP1559ReceiptData, LegacyTransaction, PartialHeader, ReceiptV3, TransactionAction, + TransactionSignature, TransactionV2, +}; use ethereum_types::{Bloom, H160, H64, U256}; use log::debug; use primitive_types::H256; @@ -22,9 +25,9 @@ use crate::storage::traits::BlockStorage; use crate::storage::Storage; use crate::traits::Executor; use crate::transaction::system::{BalanceUpdate, DST20Data, DeployContractData, SystemTx}; -use crate::transaction::SignedTx; +use crate::transaction::{SignedTx, LOWER_H256}; use crate::trie::GENESIS_STATE_ROOT; -use crate::txqueue::{BlockData, QueueTx}; +use crate::txqueue::{BlockData, QueueTx, QueueTxItem}; use crate::Result; pub struct EVMServices { @@ -55,6 +58,8 @@ pub struct DST20BridgeInfo { pub storage: Vec<(H256, H256)>, } +pub type ReceiptAndOptionalContractAddress = (ReceiptV3, Option); + impl EVMServices { /// Constructs a new Handlers instance. Depending on whether the defid -ethstartstate flag is set, /// it either revives the storage from a previously saved state or initializes new storage using input from a JSON file. @@ -114,13 +119,22 @@ impl EVMServices { beneficiary: H160, timestamp: u64, dvm_block_number: u64, + mnview_ptr: usize, ) -> Result { let tx_queue = self.core.tx_queues.get(queue_id)?; let mut queue = tx_queue.data.lock().unwrap(); + + let is_evm_genesis_block = queue.target_block == U256::zero(); + if is_evm_genesis_block { + let migration_txs = get_dst20_migration_txs(mnview_ptr)?; + queue.transactions.extend(migration_txs.into_iter()) + } + let queue_txs_len = queue.transactions.len(); let mut all_transactions = Vec::with_capacity(queue_txs_len); let mut failed_transactions = Vec::with_capacity(queue_txs_len); - let mut receipts_v3: Vec = Vec::with_capacity(queue_txs_len); + let mut receipts_v3: Vec = + Vec::with_capacity(queue_txs_len); let mut total_gas_used = 0u64; let mut total_gas_fees = U256::zero(); let mut logs_bloom: Bloom = Bloom::default(); @@ -188,8 +202,7 @@ impl EVMServices { } = EVMServices::counter_contract(dvm_block_number, current_block_number)?; executor.update_storage(address, storage)?; } - - for queue_item in queue.transactions.clone() { + for (idx, queue_item) in queue.transactions.clone().into_iter().enumerate() { match queue_item.tx { QueueTx::SignedTx(signed_tx) => { let nonce = executor.get_nonce(&signed_tx.sender); @@ -208,11 +221,11 @@ impl EVMServices { receipt, ) = executor.exec(&signed_tx, prepay_gas); debug!( - "receipt : {:#?} for signed_tx : {:#x}", + "receipt : {:#?}, exit_reason {:#?} for signed_tx : {:#x}", receipt, + exit_reason, signed_tx.transaction.hash() ); - if !exit_reason.is_succeed() { failed_transactions.push(hex::encode(queue_item.tx_hash)); } @@ -223,7 +236,7 @@ impl EVMServices { all_transactions.push(signed_tx.clone()); EVMCoreService::logs_bloom(logs, &mut logs_bloom); - receipts_v3.push(receipt); + receipts_v3.push((receipt, None)); } QueueTx::SystemTx(SystemTx::EvmIn(BalanceUpdate { address, amount })) => { debug!( @@ -250,6 +263,7 @@ impl EVMServices { name, symbol, address, + token_id, })) => { debug!( "[construct_block] DeployContract for address {}, name {}, symbol {}", @@ -262,9 +276,18 @@ impl EVMServices { storage, } = EVMServices::dst20_contract(&mut executor, address, name, symbol)?; - if let Err(e) = executor.deploy_contract(address, bytecode, storage) { + if let Err(e) = executor.deploy_contract(address, bytecode.clone(), storage) { debug!("[construct_block] EvmOut failed with {e}"); } + let (tx, receipt) = create_deploy_contract_tx( + token_id, + current_block_number, + &base_fee, + bytecode.into_vec(), + )?; + + all_transactions.push(Box::new(tx)); + receipts_v3.push((receipt, Some(address))); } QueueTx::SystemTx(SystemTx::DST20Bridge(DST20Data { to, @@ -336,19 +359,17 @@ impl EVMServices { Vec::new(), ); + let block_hash = *block.header.hash().as_fixed_bytes(); let receipts = self.receipt.generate_receipts( &all_transactions, receipts_v3, block.header.hash(), block.header.number, ); - queue.block_data = Some(BlockData { - block: block.clone(), - receipts, - }); + queue.block_data = Some(BlockData { block, receipts }); Ok(FinalizedBlockInfo { - block_hash: *block.header.hash().as_fixed_bytes(), + block_hash, failed_transactions, total_burnt_fees, total_priority_fees, @@ -570,7 +591,7 @@ impl EVMServices { queue_id: u64, name: &str, symbol: &str, - token_id: &str, + token_id: u64, ) -> Result { let address = ain_contracts::dst20_address_from_token_id(token_id)?; debug!( @@ -592,6 +613,7 @@ impl EVMServices { let deploy_tx = QueueTx::SystemTx(SystemTx::DeployContract(DeployContractData { name: String::from(name), symbol: String::from(symbol), + token_id, address, })); @@ -603,9 +625,7 @@ impl EVMServices { pub fn reserve_dst20_namespace(&self, executor: &mut AinExecutor) -> Result<()> { let bytecode = ain_contracts::get_system_reserved_bytecode()?; let addresses = (1..=1024) - .map(|token_id| { - ain_contracts::dst20_address_from_token_id(&token_id.to_string()).unwrap() - }) + .map(|token_id| ain_contracts::dst20_address_from_token_id(token_id).unwrap()) .collect::>(); for address in addresses { @@ -616,3 +636,53 @@ impl EVMServices { Ok(()) } } + +fn create_deploy_contract_tx( + token_id: u64, + block_number: U256, + base_fee: &U256, + bytecode: Vec, +) -> Result<(SignedTx, ReceiptV3)> { + let tx = TransactionV2::Legacy(LegacyTransaction { + nonce: U256::from(token_id), + gas_price: base_fee.clone(), + gas_limit: U256::from(u64::MAX), + action: TransactionAction::Create, + value: U256::zero(), + input: bytecode, + signature: TransactionSignature::new(27, LOWER_H256, LOWER_H256) + .ok_or(format_err!("Invalid transaction signature format"))?, + }) + .try_into()?; + + let receipt = ReceiptV3::Legacy(EIP1559ReceiptData { + status_code: 1u8, + used_gas: U256::zero(), + logs_bloom: Bloom::default(), + logs: Vec::new(), + }); + + Ok((tx, receipt)) +} + +fn get_dst20_migration_txs(mnview_ptr: usize) -> Result> { + let mut txs = Vec::new(); + for token in ain_cpp_imports::get_dst20_tokens(mnview_ptr) { + let address = ain_contracts::dst20_address_from_token_id(token.id)?; + debug!("Deploying to address {:#?}", address); + + let tx = QueueTx::SystemTx(SystemTx::DeployContract(DeployContractData { + name: token.name, + symbol: token.symbol, + token_id: token.id, + address, + })); + txs.push(QueueTxItem { + tx, + tx_hash: Default::default(), + tx_fee: U256::zero(), + gas_used: U256::zero(), + }); + } + Ok(txs) +} diff --git a/lib/ain-evm/src/receipt.rs b/lib/ain-evm/src/receipt.rs index b9101bdcb9..3c229fe306 100644 --- a/lib/ain-evm/src/receipt.rs +++ b/lib/ain-evm/src/receipt.rs @@ -7,6 +7,7 @@ use primitive_types::{H160, H256, U256}; use rlp::RlpStream; use serde::{Deserialize, Serialize}; +use crate::evm::ReceiptAndOptionalContractAddress; use crate::storage::{traits::ReceiptStorage, Storage}; use crate::transaction::SignedTx; use crate::Result; @@ -43,18 +44,18 @@ impl ReceiptService { Self { storage } } - pub fn get_receipts_root(receipts: &[ReceiptV3]) -> H256 { + pub fn get_receipts_root(receipts: &[ReceiptAndOptionalContractAddress]) -> H256 { ordered_trie_root( receipts .iter() - .map(|r| EnvelopedEncodable::encode(r).freeze()), + .map(|(r, _)| EnvelopedEncodable::encode(r).freeze()), ) } pub fn generate_receipts( &self, transactions: &[Box], - receipts: Vec, + receipts_and_contract_address: Vec, block_hash: H256, block_number: U256, ) -> Vec { @@ -64,8 +65,8 @@ impl ReceiptService { transactions .iter() .enumerate() - .zip(receipts) - .map(|((index, signed_tx), receipt)| { + .zip(receipts_and_contract_address) + .map(|((index, signed_tx), (receipt, contract_address))| { let receipt_data = match &receipt { ReceiptV3::Legacy(data) | ReceiptV3::EIP2930(data) @@ -84,10 +85,11 @@ impl ReceiptService { to: signed_tx.to(), tx_index: index, tx_type: signed_tx.transaction.type_id().unwrap_or_default(), - contract_address: signed_tx - .to() - .is_none() - .then(|| get_contract_address(&signed_tx.sender, &signed_tx.nonce())), + contract_address: signed_tx.to().is_none().then(|| { + contract_address.unwrap_or_else(|| { + get_contract_address(&signed_tx.sender, &signed_tx.nonce()) + }) + }), logs_index: logs_size - logs_len, cumulative_gas, } diff --git a/lib/ain-evm/src/transaction/mod.rs b/lib/ain-evm/src/transaction/mod.rs index 74b206379b..0b0255b256 100644 --- a/lib/ain-evm/src/transaction/mod.rs +++ b/lib/ain-evm/src/transaction/mod.rs @@ -4,7 +4,6 @@ use ethereum::{ AccessList, EnvelopedDecoderError, LegacyTransaction, TransactionAction, TransactionSignature, TransactionV2, }; -use libsecp256k1::PublicKey; use primitive_types::{H160, H256, U256}; use rlp::RlpStream; use sha3::Digest; @@ -101,26 +100,15 @@ impl From<&LegacyTransaction> for LegacyUnsignedTransaction { pub struct SignedTx { pub transaction: TransactionV2, pub sender: H160, - pub pubkey: PublicKey, } impl TryFrom for SignedTx { type Error = TransactionError; - fn try_from(src: TransactionV2) -> Result { - let pubkey = match &src { + fn try_from(transaction: TransactionV2) -> Result { + let pubkey = match &transaction { TransactionV2::Legacy(tx) => { - let msg = ethereum::LegacyTransactionMessage { - nonce: tx.nonce, - gas_price: tx.gas_price, - gas_limit: tx.gas_limit, - action: tx.action, - value: tx.value, - input: tx.input.clone(), - chain_id: tx.signature.chain_id(), - }; - let signing_message = libsecp256k1::Message::parse_slice(&msg.hash()[..])?; - let hash = H256::from(signing_message.serialize()); + let hash = tx.hash(); recover_public_key( &hash, tx.signature.r(), @@ -129,41 +117,17 @@ impl TryFrom for SignedTx { ) } TransactionV2::EIP2930(tx) => { - let msg = ethereum::EIP2930TransactionMessage { - chain_id: tx.chain_id, - nonce: tx.nonce, - gas_price: tx.gas_price, - gas_limit: tx.gas_limit, - action: tx.action, - value: tx.value, - input: tx.input.clone(), - access_list: tx.access_list.clone(), - }; - let signing_message = libsecp256k1::Message::parse_slice(&msg.hash()[..])?; - let hash = H256::from(signing_message.serialize()); + let hash = tx.hash(); recover_public_key(&hash, &tx.r, &tx.s, u8::from(tx.odd_y_parity)) } TransactionV2::EIP1559(tx) => { - let msg = ethereum::EIP1559TransactionMessage { - chain_id: tx.chain_id, - nonce: tx.nonce, - max_priority_fee_per_gas: tx.max_priority_fee_per_gas, - max_fee_per_gas: tx.max_fee_per_gas, - gas_limit: tx.gas_limit, - action: tx.action, - value: tx.value, - input: tx.input.clone(), - access_list: tx.access_list.clone(), - }; - let signing_message = libsecp256k1::Message::parse_slice(&msg.hash()[..])?; - let hash = H256::from(signing_message.serialize()); + let hash = tx.hash(); recover_public_key(&hash, &tx.r, &tx.s, u8::from(tx.odd_y_parity)) } }?; Ok(SignedTx { - transaction: src, + transaction, sender: public_key_to_address(&pubkey), - pubkey, }) } } @@ -359,7 +323,6 @@ mod tests { // Legacy let signed_tx = crate::transaction::SignedTx::try_from("f86b8085689451eee18252089434c1ca09a2dc717d89baef2f30ff6a6b2975e17e872386f26fc10000802da0ae5c76f8073460cbc7a911d3cc1b367072db64848a9532343559ce6917c51a46a01d2e4928450c59acca3de8340eb15b7446b37936265a51ab35e63f749a048002").unwrap(); - assert_eq!(hex::encode(signed_tx.pubkey.serialize()), "044c6412f7cd3ac0e2538c3c9843d27d1e03b422eaf655c6a699da22b57a89802989318dbaeea62f5fc751fa8cd1404e687d67b8ab8513fe0d37bafbf407aa6cf7"); assert_eq!( hex::encode(signed_tx.sender.as_fixed_bytes()), "f829754bae400b679febefdcfc9944c323e1f94e" diff --git a/lib/ain-evm/src/transaction/system.rs b/lib/ain-evm/src/transaction/system.rs index 2aae18fa27..e4c145615c 100644 --- a/lib/ain-evm/src/transaction/system.rs +++ b/lib/ain-evm/src/transaction/system.rs @@ -5,6 +5,7 @@ pub struct DeployContractData { pub name: String, pub symbol: String, pub address: H160, + pub token_id: u64, } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 881876c52c..2656987b9b 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -437,6 +437,7 @@ pub fn evm_unsafe_try_construct_block_in_q( miner_address: [u8; 20], timestamp: u64, dvm_block_number: u64, + mnview_ptr: usize, ) -> ffi::FinalizeBlockCompletion { let eth_address = H160::from(miner_address); unsafe { @@ -446,6 +447,7 @@ pub fn evm_unsafe_try_construct_block_in_q( eth_address, timestamp, dvm_block_number, + mnview_ptr, ) { Ok(FinalizedBlockInfo { block_hash, @@ -621,7 +623,7 @@ pub fn evm_try_is_dst20_deployed_or_queued( queue_id: u64, name: &str, symbol: &str, - token_id: &str, + token_id: u64, ) -> bool { unsafe { match SERVICES @@ -736,7 +738,7 @@ pub fn evm_try_create_dst20( native_hash: [u8; 32], name: &str, symbol: &str, - token_id: &str, + token_id: u64, ) { let address = match ain_contracts::dst20_address_from_token_id(token_id) { Ok(address) => address, @@ -748,6 +750,7 @@ pub fn evm_try_create_dst20( name: String::from(name), symbol: String::from(symbol), address, + token_id, })); unsafe { @@ -767,7 +770,7 @@ pub fn evm_try_bridge_dst20( address: &str, amount: [u8; 32], native_hash: [u8; 32], - token_id: &str, + token_id: u64, out: bool, ) { let Ok(address) = address.parse() else { diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 17a886092f..53739eb4c0 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -160,6 +160,7 @@ pub mod ffi { miner_address: [u8; 20], timestamp: u64, dvm_block_number: u64, + mnview_ptr: usize, ) -> FinalizeBlockCompletion; fn evm_unsafe_try_commit_queue(result: &mut CrossBoundaryResult, queue_id: u64); fn evm_try_set_attribute( @@ -196,7 +197,7 @@ pub mod ffi { native_hash: [u8; 32], name: &str, symbol: &str, - token_id: &str, + token_id: u64, ); fn evm_try_bridge_dst20( result: &mut CrossBoundaryResult, @@ -204,7 +205,7 @@ pub mod ffi { address: &str, amount: [u8; 32], native_hash: [u8; 32], - token_id: &str, + token_id: u64, out: bool, ); fn evm_try_is_dst20_deployed_or_queued( @@ -212,7 +213,7 @@ pub mod ffi { queue_id: u64, name: &str, symbol: &str, - token_id: &str, + token_id: u64, ) -> bool; fn evm_unsafe_try_get_target_block_in_q( diff --git a/src/ffi/ffiexports.cpp b/src/ffi/ffiexports.cpp index 712a7e295a..d250f02540 100644 --- a/src/ffi/ffiexports.cpp +++ b/src/ffi/ffiexports.cpp @@ -224,3 +224,18 @@ int getCurrentHeight() { Attributes getAttributeDefaults() { return Attributes::Default(); } + +rust::vec getDST20Tokens(std::size_t mnview_ptr) { + LOCK(cs_main); + + rust::vec tokens; + CCustomCSView* cache = reinterpret_cast(static_cast(mnview_ptr)); + cache->ForEachToken([&](DCT_ID const &id, CTokensView::CTokenImpl token) { + if (!token.IsDAT() || token.IsPoolShare()) + return true; + + tokens.push_back({id.v, token.name, token.symbol}); + return true; + }, DCT_ID{1}); // start from non-DFI + return tokens; +} diff --git a/src/ffi/ffiexports.h b/src/ffi/ffiexports.h index cb31ad4f0e..a19cfbf19d 100644 --- a/src/ffi/ffiexports.h +++ b/src/ffi/ffiexports.h @@ -23,6 +23,12 @@ struct Attributes { } }; +struct DST20Token { + uint64_t id; + rust::string name; + rust::string symbol; +}; + uint64_t getChainId(); bool isMining(); rust::string publishEthTransaction(rust::Vec rawTransaction); @@ -40,5 +46,6 @@ int getHighestBlock(); int getCurrentHeight(); Attributes getAttributeDefaults(); void CppLogPrintf(rust::string message); +rust::vec getDST20Tokens(std::size_t mnview_ptr); #endif // DEFI_FFI_FFIEXPORTS_H diff --git a/src/masternodes/errors.h b/src/masternodes/errors.h index 008eac67ec..4f50f30cf9 100644 --- a/src/masternodes/errors.h +++ b/src/masternodes/errors.h @@ -541,10 +541,6 @@ class DeFiErrors { static Res InvalidBlockNumberString(const std::string &number) { return Res::Err("Invalid block number: %s", number); } - - static Res DST20MigrationFailure(const std::string &reason) { - return Res::Err("Error migrating DST20 token: %s", reason); - } }; #endif // DEFI_MASTERNODES_ERRORS_H diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp index 8887ee7b96..2dabf6b273 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -1819,11 +1819,11 @@ Res ATTRIBUTES::Validate(const CCustomCSView &view) const { GetValue(enabledKey, false) && evmQueueId && !evm_try_is_dst20_deployed_or_queued(result, evmQueueId, token->name, token->symbol, - tokenID.ToString())) { + tokenID.v)) { evm_try_create_dst20(result, evmQueueId, token->creationTx.GetByteArray(), token->name, token->symbol, - tokenID.ToString()); + tokenID.v); if (!result.ok) { return DeFiErrors::GovVarErrorCreatingDST20(result.reason.c_str()); diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 350e5c52d3..b63d02a88f 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -1076,7 +1076,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { evm_try_create_dst20(result, evmQueueId, tx.GetHash().GetByteArray(), rust::string(tokenName.c_str()), rust::string(tokenSymbol.c_str()), - tokenId->ToString()); + tokenId->v); if (!result.ok) { return Res::Err("Error creating DST20 token: %s", result.reason); @@ -3892,7 +3892,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { Res operator()(const CTransferDomainMessage &obj) const { auto res = ValidateTransferDomain(tx, height, coins, mnview, consensus, obj, isEvmEnabledForBlock); if (!res) { return res; } - + auto attributes = mnview.GetAttributes(); auto stats = attributes->GetValue(CTransferDomainStatsLive::Key, CTransferDomainStatsLive{}); @@ -3925,7 +3925,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { else { CrossBoundaryResult result; evm_try_bridge_dst20(result, evmQueueId, HexStr(toAddress.begin(), toAddress.end()), - ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray(), tokenId.ToString(), false); + ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray(), tokenId.v, false); if (!result.ok) { return Res::Err("Error bridging DST20: %s", result.reason); @@ -3955,7 +3955,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { else { CrossBoundaryResult result; evm_try_bridge_dst20(result, evmQueueId, HexStr(fromAddress.begin(), fromAddress.end()), - ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray(), tokenId.ToString(), true); + ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray(), tokenId.v, true); if (!result.ok) { return Res::Err("Error bridging DST20: %s", result.reason); @@ -5445,4 +5445,4 @@ void TransferDomainConfig::SetToAttributesIfNotExists(ATTRIBUTES& attrs) const { if (!attrs.CheckKey(k.evm_to_dvm_auth_formats)) attrs.SetValue(k.evm_to_dvm_auth_formats, evmToDvmAuthFormats); if (!attrs.CheckKey(k.evm_to_dvm_native_enabled)) attrs.SetValue(k.evm_to_dvm_native_enabled, evmToDvmNativeTokenEnabled); if (!attrs.CheckKey(k.evm_to_dvm_dat_enabled)) attrs.SetValue(k.evm_to_dvm_dat_enabled, evmToDvmDatEnabled); -} \ No newline at end of file +} diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index 7475cdd426..feb326f340 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2383,7 +2383,7 @@ static void RevertFailedTransferDomainTxs(const std::vector &failed static Res ValidateCoinbaseXVMOutput(const XVM &xvm, const FinalizeBlockCompletion &blockResult) { const auto blockResultBlockHash = uint256::FromByteArray(blockResult.block_hash); - + if (xvm.evm.blockHash != blockResultBlockHash) { return Res::Err("Incorrect EVM block hash in coinbase output"); } @@ -2440,7 +2440,7 @@ static Res ProcessEVMQueue(const CBlock &block, const CBlockIndex *pindex, CCust if (!xvmRes) return std::move(xvmRes); CrossBoundaryResult result; - const auto blockResult = evm_unsafe_try_construct_block_in_q(result, evmQueueId, block.nBits, xvmRes->evm.beneficiary, block.GetBlockTime(), pindex->nHeight); + const auto blockResult = evm_unsafe_try_construct_block_in_q(result, evmQueueId, block.nBits, xvmRes->evm.beneficiary, block.GetBlockTime(), pindex->nHeight, static_cast(reinterpret_cast(&cache))); if (!result.ok) { return Res::Err(result.reason.c_str()); } @@ -2519,45 +2519,6 @@ static Res ProcessEVMQueue(const CBlock &block, const CBlockIndex *pindex, CCust return Res::Ok(); } -Res ProcessDST20Migration(const CBlockIndex *pindex, CCustomCSView &cache, const CChainParams& chainparams, const uint64_t evmQueueId) { - auto res = XResultValue(evm_unsafe_try_get_target_block_in_q(result, evmQueueId)); - if (!res.ok) return DeFiErrors::DST20MigrationFailure(res.msg); - - auto evmTargetBlock = *res; - if (evmTargetBlock > 0) return Res::Ok(); - - auto time = GetTimeMillis(); - LogPrintf("DST20 migration ...\n"); - - std::string errMsg = ""; - cache.ForEachToken([&](DCT_ID const &id, CTokensView::CTokenImpl token) { - if (!token.IsDAT() || token.IsPoolShare()) - return true; - - CrossBoundaryResult result; - auto alreadyExists = evm_try_is_dst20_deployed_or_queued(result, evmQueueId, token.name, token.symbol, id.ToString()); - if (!result.ok) { - errMsg = result.reason.c_str(); - return false; - } - - if (alreadyExists) { - return true; - } - - evm_try_create_dst20(result, evmQueueId, token.creationTx.GetByteArray(), token.name, token.symbol, id.ToString()); - if (!result.ok) { - errMsg = result.reason.c_str(); - return false; - } - - return true; - }, DCT_ID{1}); // start from non-DFI - - LogPrint(BCLog::BENCH, " - DST20 migration took: %dms\n", GetTimeMillis() - time); - return errMsg.empty() ? Res::Ok() : DeFiErrors::DST20MigrationFailure(errMsg); -} - static void FlushCacheCreateUndo(const CBlockIndex *pindex, CCustomCSView &mnview, CCustomCSView &cache, const uint256 hash) { // construct undo auto& flushable = cache.GetStorage(); @@ -2572,13 +2533,10 @@ static void FlushCacheCreateUndo(const CBlockIndex *pindex, CCustomCSView &mnvie Res ProcessDeFiEventFallible(const CBlock &block, const CBlockIndex *pindex, CCustomCSView &mnview, const CChainParams& chainparams, const uint64_t evmQueueId, const bool isEvmEnabledForBlock) { CCustomCSView cache(mnview); - - if (isEvmEnabledForBlock) { - auto res = ProcessDST20Migration(pindex, cache, chainparams, evmQueueId); - if (!res) return res; + if (isEvmEnabledForBlock) { // Process EVM block - res = ProcessEVMQueue(block, pindex, cache, chainparams, evmQueueId); + auto res = ProcessEVMQueue(block, pindex, cache, chainparams, evmQueueId); if (!res) return res; } diff --git a/src/masternodes/validation.h b/src/masternodes/validation.h index 0611453940..beb992b4f9 100644 --- a/src/masternodes/validation.h +++ b/src/masternodes/validation.h @@ -21,8 +21,6 @@ void ProcessDeFiEvent(const CBlock &block, const CBlockIndex* pindex, CCustomCSV Res ProcessDeFiEventFallible(const CBlock &block, const CBlockIndex *pindex, CCustomCSView &mnview, const CChainParams& chainparams, const uint64_t evmQueueId, const bool isEvmEnabledForBlock); -Res ProcessDST20Migration(const CBlockIndex *pindex, CCustomCSView &cache, const CChainParams& chainparams, const uint64_t evmQueueId); - std::vector CollectAuctionBatches(const CVaultAssets& vaultAssets, const TAmounts& collBalances, const TAmounts& loanBalances); diff --git a/src/miner.cpp b/src/miner.cpp index a650744f60..47ce386b9b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -286,15 +286,10 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc XVM xvm{}; if (isEvmEnabledForBlock) { - if (auto res = ProcessDST20Migration(pindexPrev, mnview, chainparams, evmQueueId); !res) { - LogPrintf("ThreadStaker: Failed to process DST20 migration: %s\n", res.msg); - return nullptr; - } - - auto res = XResultValueLogged(evm_unsafe_try_construct_block_in_q(result, evmQueueId, pos::GetNextWorkRequired(pindexPrev, pblock->nTime, consensus), evmBeneficiary, blockTime, nHeight)); + auto res = XResultValueLogged(evm_unsafe_try_construct_block_in_q(result, evmQueueId, pos::GetNextWorkRequired(pindexPrev, pblock->nTime, consensus), evmBeneficiary, blockTime, nHeight, static_cast(reinterpret_cast(&mnview)))); if (!res) { return nullptr; } auto blockResult = *res; - + auto r = XResultStatusLogged(evm_unsafe_try_remove_queue(result, evmQueueId)); if (!r) { return nullptr; } diff --git a/test/functional/feature_dst20.py b/test/functional/feature_dst20.py index cc7f3804ae..90adf89349 100755 --- a/test/functional/feature_dst20.py +++ b/test/functional/feature_dst20.py @@ -42,6 +42,139 @@ def set_test_params(self): ] ] + def test_dst20_migration_txs(self): + block_height = self.nodes[0].getblockcount() + + self.node.createtoken( + { + "symbol": "USDT", + "name": "USDT token", + "isDAT": True, + "collateralAddress": self.address, + } + ) + self.node.createtoken( + { + "symbol": "BTC", + "name": "BTC token", + "isDAT": True, + "collateralAddress": self.address, + } + ) + self.node.createtoken( + { + "symbol": "ETH", + "name": "ETH token", + "isDAT": True, + "collateralAddress": self.address, + } + ) + self.nodes[0].generate(1) + + # enable EVM, transferdomain, DVM to EVM transfers and EVM to DVM transfers + self.nodes[0].setgov( + { + "ATTRIBUTES": { + "v0/params/feature/evm": "true", + } + } + ) + self.nodes[0].generate(1) + + # Trigger EVM genesis DST20 migration + self.nodes[0].generate(1) + + # should have code on contract address + assert ( + self.nodes[0].w3.to_hex( + self.nodes[0].w3.eth.get_code(self.contract_address_btc) + ) + != "0x" + ) + assert ( + self.nodes[0].w3.to_hex( + self.nodes[0].w3.eth.get_code(self.contract_address_eth) + ) + != "0x" + ) + self.btc = self.nodes[0].w3.eth.contract( + address=self.contract_address_btc, abi=self.abi + ) + assert_equal(self.btc.functions.name().call(), "BTC token") + assert_equal(self.btc.functions.symbol().call(), "BTC") + + self.eth = self.nodes[0].w3.eth.contract( + address=self.contract_address_eth, abi=self.abi + ) + assert_equal(self.eth.functions.name().call(), "ETH token") + assert_equal(self.eth.functions.symbol().call(), "ETH") + + # Check that migration has associated EVM TX and receipt + block = self.nodes[0].eth_getBlockByNumber("latest") + all_tokens = self.nodes[0].listtokens() + # Keep only DAT non-DFI tokens + loanTokens = [token for token in all_tokens.values() if token['isDAT'] == True and token['symbol'] != 'DFI'] + assert_equal(len(block['transactions']), len(loanTokens)) + + # check USDT migration + usdt_tx = block['transactions'][0] + receipt = self.nodes[0].eth_getTransactionReceipt(usdt_tx) + tx1 = self.nodes[0].eth_getTransactionByHash(usdt_tx) + assert_equal(self.w0.to_checksum_address(receipt['contractAddress']), self.contract_address_usdt) + assert_equal(receipt['from'], tx1['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_usdt) + ) + , tx1['input'] + ) + + # check BTC migration + btc_tx = block['transactions'][1] + receipt = self.nodes[0].eth_getTransactionReceipt(btc_tx) + tx2 = self.nodes[0].eth_getTransactionByHash(btc_tx) + assert_equal(self.w0.to_checksum_address(receipt['contractAddress']), self.contract_address_btc) + assert_equal(receipt['from'], tx2['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) + ) + , tx2['input'] + ) + + # check ETH migration + eth_tx = block['transactions'][2] + receipt = self.nodes[0].eth_getTransactionReceipt(eth_tx) + tx3 = self.nodes[0].eth_getTransactionByHash(eth_tx) + assert_equal(self.w0.to_checksum_address(receipt['contractAddress']), self.contract_address_eth) + assert_equal(receipt['from'], tx3['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_eth) + ) + , tx3['input'] + ) + + assert_equal(tx1['input'], tx2['input']) + assert_equal(tx2['input'], tx3['input']) + + self.rollback_to(block_height) + def test_unused_dst20(self): # should have system reserved bytecode assert ( @@ -56,6 +189,7 @@ def test_pre_evm_token(self): assert ( self.nodes[0].w3.to_hex( self.nodes[0].w3.eth.get_code(self.contract_address_usdt) + ) != self.reserved_bytecode ) @@ -658,6 +792,11 @@ def run_test(self): # Generate chain self.node.generate(150) self.nodes[0].utxostoaccount({self.address: "1000@DFI"}) + self.nodes[0].generate(1) + + # Create token and check DST20 migration pre EVM activation + self.test_dst20_migration_txs() + # Create token before EVM self.node.createtoken( { @@ -689,6 +828,7 @@ def run_test(self): self.nodes[0].generate(2) self.test_pre_evm_token() + self.test_deploy_token() self.test_deploy_multiple_tokens() @@ -706,6 +846,5 @@ def run_test(self): self.test_different_tokens() self.test_loan_token() - if __name__ == "__main__": DST20().main() From cd461d245e08c35619d3b58d735d2273aebe61ab Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Fri, 18 Aug 2023 07:31:12 +0800 Subject: [PATCH 06/22] Fix TxDest abstraction defaults (#2341) * Isolate linux specific helpers * Reduce transfer domain noise * Add ExtendedTxToUniv * Add log category CONNECT and SIGN * Split more * Fix txdest abstraction defaults --- src/init.cpp | 4 ++-- src/masternodes/masternodes.cpp | 4 ++-- src/masternodes/mn_checks.cpp | 10 +++++----- src/masternodes/mn_rpc.cpp | 2 -- src/masternodes/rpc_customtx.cpp | 6 +++--- src/masternodes/rpc_masternodes.cpp | 8 ++++---- src/masternodes/validation.cpp | 4 ++-- src/miner.cpp | 8 ++++---- src/pubkey.h | 6 +++--- src/script/sign.cpp | 1 + src/script/signingprovider.cpp | 4 ++-- src/script/standard.h | 6 +++--- src/validation.cpp | 4 ++-- 13 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index d46b03e609..958607430a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2381,9 +2381,9 @@ bool AppInitMain(InitInterfaces& interfaces) if (optMasternodeID) { auto nodePtr = pcustomcsview->GetMasternode(*optMasternodeID); assert(nodePtr); // this should not happen if MN was found by operator's id - ownerDest = FromOrDefaultKeyIDToDestination(nodePtr->ownerAuthAddress, FromOrDefaultDestinationTypeToKeyType(nodePtr->ownerType), KeyType::MNOwnerKeyType); + ownerDest = FromOrDefaultKeyIDToDestination(nodePtr->ownerAuthAddress, TxDestTypeToKeyType(nodePtr->ownerType), KeyType::MNOwnerKeyType); if (nodePtr->rewardAddressType != 0) { - rewardDest = FromOrDefaultKeyIDToDestination(nodePtr->rewardAddress, FromOrDefaultDestinationTypeToKeyType(nodePtr->rewardAddressType), KeyType::MNRewardKeyType); + rewardDest = FromOrDefaultKeyIDToDestination(nodePtr->rewardAddress, TxDestTypeToKeyType(nodePtr->rewardAddressType), KeyType::MNRewardKeyType); } } diff --git a/src/masternodes/masternodes.cpp b/src/masternodes/masternodes.cpp index 4ea8d42f9a..f3bef2c344 100644 --- a/src/masternodes/masternodes.cpp +++ b/src/masternodes/masternodes.cpp @@ -1342,13 +1342,13 @@ CAmount CCustomCSView::GetFeeBurnPctFromAttributes() const { void CalcMissingRewardTempFix(CCustomCSView &mnview, const uint32_t targetHeight, const CWallet &wallet) { mnview.ForEachMasternode([&](const uint256 &id, const CMasternode &node) { if (node.rewardAddressType) { - const CScript rewardAddress = GetScriptForDestination(FromOrDefaultKeyIDToDestination(node.rewardAddress, FromOrDefaultDestinationTypeToKeyType(node.rewardAddressType), KeyType::MNRewardKeyType)); + const CScript rewardAddress = GetScriptForDestination(FromOrDefaultKeyIDToDestination(node.rewardAddress, TxDestTypeToKeyType(node.rewardAddressType), KeyType::MNRewardKeyType)); if (IsMineCached(wallet, rewardAddress) == ISMINE_SPENDABLE) { mnview.CalculateOwnerRewards(rewardAddress, targetHeight); } } - const CScript rewardAddress = GetScriptForDestination(FromOrDefaultKeyIDToDestination(node.ownerAuthAddress, FromOrDefaultDestinationTypeToKeyType(node.ownerType), KeyType::MNOwnerKeyType)); + const CScript rewardAddress = GetScriptForDestination(FromOrDefaultKeyIDToDestination(node.ownerAuthAddress, TxDestTypeToKeyType(node.ownerType), KeyType::MNOwnerKeyType)); if (IsMineCached(wallet, rewardAddress) == ISMINE_SPENDABLE) { mnview.CalculateOwnerRewards(rewardAddress, targetHeight); } diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index b63d02a88f..967c0630b7 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -1017,7 +1017,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { // next hard fork as this is a workaround for the issue fixed in the following PR: // https://github.com/DeFiCh/ain/pull/1766 if (auto addresses = mnview.SettingsGetRewardAddresses()) { - const CScript rewardAddress = GetScriptForDestination(FromOrDefaultKeyIDToDestination(keyID, FromOrDefaultDestinationTypeToKeyType(addressType), KeyType::MNRewardKeyType)); + const CScript rewardAddress = GetScriptForDestination(FromOrDefaultKeyIDToDestination(keyID, TxDestTypeToKeyType(addressType), KeyType::MNRewardKeyType)); addresses->insert(rewardAddress); mnview.SettingsSetRewardAddresses(*addresses); } @@ -3864,7 +3864,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { if (!node) return Res::Err("masternode <%s> does not exist", obj.masternodeId.GetHex()); - auto ownerDest = FromOrDefaultKeyIDToDestination(node->ownerAuthAddress, FromOrDefaultDestinationTypeToKeyType(node->ownerType), KeyType::MNOwnerKeyType); + auto ownerDest = FromOrDefaultKeyIDToDestination(node->ownerAuthAddress, TxDestTypeToKeyType(node->ownerType), KeyType::MNOwnerKeyType); if (!IsValidDestination(ownerDest)) return Res::Err("masternode <%s> owner address is not invalid", obj.masternodeId.GetHex()); @@ -4536,7 +4536,7 @@ ResVal ApplyAnchorRewardTx(CCustomCSView &mnview, } } - CTxDestination destination = FromOrDefaultKeyIDToDestination(finMsg.rewardKeyID, FromOrDefaultDestinationTypeToKeyType(finMsg.rewardKeyType), KeyType::MNOwnerKeyType); + CTxDestination destination = FromOrDefaultKeyIDToDestination(finMsg.rewardKeyID, TxDestTypeToKeyType(finMsg.rewardKeyType), KeyType::MNOwnerKeyType); if (!IsValidDestination(destination) || tx.vout[1].scriptPubKey != GetScriptForDestination(destination)) { return Res::ErrDbg("bad-ar-dest", "anchor pay destination is incorrect"); } @@ -4621,9 +4621,9 @@ ResVal ApplyAnchorRewardTxPlus(CCustomCSView &mnview, CTxDestination destination; if (height < consensusParams.NextNetworkUpgradeHeight) { - destination = FromOrDefaultKeyIDToDestination(finMsg.rewardKeyID, FromOrDefaultDestinationTypeToKeyType(finMsg.rewardKeyType), KeyType::MNOwnerKeyType); + destination = FromOrDefaultKeyIDToDestination(finMsg.rewardKeyID, TxDestTypeToKeyType(finMsg.rewardKeyType), KeyType::MNOwnerKeyType); } else { - destination = FromOrDefaultKeyIDToDestination(finMsg.rewardKeyID, FromOrDefaultDestinationTypeToKeyType(finMsg.rewardKeyType), KeyType::MNRewardKeyType); + destination = FromOrDefaultKeyIDToDestination(finMsg.rewardKeyID, TxDestTypeToKeyType(finMsg.rewardKeyType), KeyType::MNRewardKeyType); } if (!IsValidDestination(destination) || tx.vout[1].scriptPubKey != GetScriptForDestination(destination)) { return Res::ErrDbg("bad-ar-dest", "anchor pay destination is incorrect"); diff --git a/src/masternodes/mn_rpc.cpp b/src/masternodes/mn_rpc.cpp index 349aa035c7..d44c410a3b 100644 --- a/src/masternodes/mn_rpc.cpp +++ b/src/masternodes/mn_rpc.cpp @@ -334,10 +334,8 @@ static CTransactionRef CreateAuthTx(CWalletCoinsUnlocker& pwallet, // Only set change to auth on single auth TXs if (auths.size() == 1) { - // Get auth ScriptPubkey auto auth = *auths.cbegin(); - // Create output to cover 1KB transaction CTxOut authOut(GetMinimumFee(*pwallet, 1000, coinControl, nullptr), auth); mtx.vout.push_back(authOut); diff --git a/src/masternodes/rpc_customtx.cpp b/src/masternodes/rpc_customtx.cpp index f6626c03f4..b97b70df33 100644 --- a/src/masternodes/rpc_customtx.cpp +++ b/src/masternodes/rpc_customtx.cpp @@ -74,7 +74,7 @@ class CCustomTxRpcVisitor { void operator()(const CCreateMasterNodeMessage &obj) const { rpcInfo.pushKV("collateralamount", ValueFromAmount(GetMnCollateralAmount(height))); - rpcInfo.pushKV("masternodeoperator", EncodeDestination(FromOrDefaultKeyIDToDestination(obj.operatorAuthAddress, FromOrDefaultDestinationTypeToKeyType(obj.operatorType), KeyType::MNOperatorKeyType))); + rpcInfo.pushKV("masternodeoperator", EncodeDestination(FromOrDefaultKeyIDToDestination(obj.operatorAuthAddress, TxDestTypeToKeyType(obj.operatorType), KeyType::MNOperatorKeyType))); rpcInfo.pushKV("timelock", CMasternode::GetTimelockToString(static_cast(obj.timelock))); } @@ -85,7 +85,7 @@ class CCustomTxRpcVisitor { for (const auto &[updateType, addressPair] : obj.updates) { const auto &[addressType, rawAddress] = addressPair; if (updateType == static_cast(UpdateMasternodeType::OperatorAddress)) { - rpcInfo.pushKV("operatorAddress", EncodeDestination(FromOrDefaultKeyIDToDestination(CKeyID(uint160(rawAddress)), FromOrDefaultDestinationTypeToKeyType(addressType), KeyType::MNOperatorKeyType))); + rpcInfo.pushKV("operatorAddress", EncodeDestination(FromOrDefaultKeyIDToDestination(CKeyID(uint160(rawAddress)), TxDestTypeToKeyType(addressType), KeyType::MNOperatorKeyType))); } else if (updateType == static_cast(UpdateMasternodeType::OwnerAddress)) { CTxDestination dest; if (tx.vout.size() >= 2 && ExtractDestination(tx.vout[1].scriptPubKey, dest)) { @@ -93,7 +93,7 @@ class CCustomTxRpcVisitor { } } if (updateType == static_cast(UpdateMasternodeType::SetRewardAddress)) { - rpcInfo.pushKV("rewardAddress", EncodeDestination(FromOrDefaultKeyIDToDestination(CKeyID(uint160(rawAddress)), FromOrDefaultDestinationTypeToKeyType(addressType), KeyType::MNRewardKeyType))); + rpcInfo.pushKV("rewardAddress", EncodeDestination(FromOrDefaultKeyIDToDestination(CKeyID(uint160(rawAddress)), TxDestTypeToKeyType(addressType), KeyType::MNRewardKeyType))); } else if (updateType == static_cast(UpdateMasternodeType::RemRewardAddress)) { rpcInfo.pushKV("rewardAddress", ""); } diff --git a/src/masternodes/rpc_masternodes.cpp b/src/masternodes/rpc_masternodes.cpp index 03cb245b2e..adc409bbeb 100644 --- a/src/masternodes/rpc_masternodes.cpp +++ b/src/masternodes/rpc_masternodes.cpp @@ -12,12 +12,12 @@ UniValue mnToJSON(CCustomCSView& view, uint256 const & nodeId, CMasternode const } else { UniValue obj(UniValue::VOBJ); - CTxDestination ownerDest = FromOrDefaultKeyIDToDestination(node.ownerAuthAddress, FromOrDefaultDestinationTypeToKeyType(node.ownerType), KeyType::MNOwnerKeyType); + CTxDestination ownerDest = FromOrDefaultKeyIDToDestination(node.ownerAuthAddress, TxDestTypeToKeyType(node.ownerType), KeyType::MNOwnerKeyType); obj.pushKV("ownerAuthAddress", EncodeDestination(ownerDest)); - CTxDestination operatorDest = FromOrDefaultKeyIDToDestination(node.operatorAuthAddress, FromOrDefaultDestinationTypeToKeyType(node.operatorType), KeyType::MNOperatorKeyType); + CTxDestination operatorDest = FromOrDefaultKeyIDToDestination(node.operatorAuthAddress, TxDestTypeToKeyType(node.operatorType), KeyType::MNOperatorKeyType); obj.pushKV("operatorAuthAddress", EncodeDestination(operatorDest)); if (node.rewardAddressType != 0) { - obj.pushKV("rewardAddress", EncodeDestination(FromOrDefaultKeyIDToDestination(node.rewardAddress, FromOrDefaultDestinationTypeToKeyType(node.rewardAddressType), KeyType::MNRewardKeyType))); + obj.pushKV("rewardAddress", EncodeDestination(FromOrDefaultKeyIDToDestination(node.rewardAddress, TxDestTypeToKeyType(node.rewardAddressType), KeyType::MNRewardKeyType))); } else { obj.pushKV("rewardAddress", EncodeDestination(CTxDestination())); @@ -251,7 +251,7 @@ UniValue resignmasternode(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("The masternode %s does not exist", nodeIdStr)); } - ownerDest = FromOrDefaultKeyIDToDestination(nodePtr->ownerAuthAddress, FromOrDefaultDestinationTypeToKeyType(nodePtr->ownerType), KeyType::MNOwnerKeyType); + ownerDest = FromOrDefaultKeyIDToDestination(nodePtr->ownerAuthAddress, TxDestTypeToKeyType(nodePtr->ownerType), KeyType::MNOwnerKeyType); if (!nodePtr->collateralTx.IsNull()) { const auto& coin = ::ChainstateActive().CoinsTip().AccessCoin({nodePtr->collateralTx, 1}); if (coin.IsSpent() || !ExtractDestination(coin.out.scriptPubKey, collateralDest)) { diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index feb326f340..6cfe400005 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2234,9 +2234,9 @@ static void ProcessProposalEvents(const CBlockIndex* pindex, CCustomCSView& cach CScript scriptPubKey; if (mn->rewardAddressType != 0) { - scriptPubKey = GetScriptForDestination(FromOrDefaultKeyIDToDestination(mn->rewardAddress, FromOrDefaultDestinationTypeToKeyType(mn->rewardAddressType), KeyType::MNRewardKeyType)); + scriptPubKey = GetScriptForDestination(FromOrDefaultKeyIDToDestination(mn->rewardAddress, TxDestTypeToKeyType(mn->rewardAddressType), KeyType::MNRewardKeyType)); } else { - scriptPubKey = GetScriptForDestination(FromOrDefaultKeyIDToDestination(mn->ownerAuthAddress, FromOrDefaultDestinationTypeToKeyType(mn->ownerType), KeyType::MNOwnerKeyType)); + scriptPubKey = GetScriptForDestination(FromOrDefaultKeyIDToDestination(mn->ownerAuthAddress, TxDestTypeToKeyType(mn->ownerType), KeyType::MNOwnerKeyType)); } CAccountsHistoryWriter subView(cache, pindex->nHeight, GetNextAccPosition(), pindex->GetBlockHash(), uint8_t(CustomTxType::ProposalFeeRedistribution)); diff --git a/src/miner.cpp b/src/miner.cpp index 47ce386b9b..da8841969f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -221,9 +221,9 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc CTxDestination destination; if (nHeight < consensus.NextNetworkUpgradeHeight) { - destination = FromOrDefaultKeyIDToDestination(finMsg.rewardKeyID, FromOrDefaultDestinationTypeToKeyType(finMsg.rewardKeyType), KeyType::MNOwnerKeyType); + destination = FromOrDefaultKeyIDToDestination(finMsg.rewardKeyID, TxDestTypeToKeyType(finMsg.rewardKeyType), KeyType::MNOwnerKeyType); } else { - destination = FromOrDefaultKeyIDToDestination(finMsg.rewardKeyID, FromOrDefaultDestinationTypeToKeyType(finMsg.rewardKeyType), KeyType::MNRewardKeyType); + destination = FromOrDefaultKeyIDToDestination(finMsg.rewardKeyID, TxDestTypeToKeyType(finMsg.rewardKeyType), KeyType::MNRewardKeyType); } if (IsValidDestination(destination)) { @@ -1037,9 +1037,9 @@ Staker::Status Staker::stake(const CChainParams& chainparams, const ThreadStaker if (args.coinbaseScript.empty()) { // this is safe because MN was found if (tip->nHeight >= chainparams.GetConsensus().FortCanningHeight && nodePtr->rewardAddressType != 0) { - scriptPubKey = GetScriptForDestination(FromOrDefaultKeyIDToDestination(nodePtr->rewardAddress, FromOrDefaultDestinationTypeToKeyType(nodePtr->rewardAddressType), KeyType::MNRewardKeyType)); + scriptPubKey = GetScriptForDestination(FromOrDefaultKeyIDToDestination(nodePtr->rewardAddress, TxDestTypeToKeyType(nodePtr->rewardAddressType), KeyType::MNRewardKeyType)); } else { - scriptPubKey = GetScriptForDestination(FromOrDefaultKeyIDToDestination(nodePtr->ownerAuthAddress, FromOrDefaultDestinationTypeToKeyType(nodePtr->ownerType), KeyType::MNOwnerKeyType)); + scriptPubKey = GetScriptForDestination(FromOrDefaultKeyIDToDestination(nodePtr->ownerAuthAddress, TxDestTypeToKeyType(nodePtr->ownerType), KeyType::MNOwnerKeyType)); } } else { scriptPubKey = args.coinbaseScript; diff --git a/src/pubkey.h b/src/pubkey.h index 883c6cddf7..f63e3e0966 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -33,8 +33,8 @@ class CKeyID : public uint160 KeyAddressType type{KeyAddressType::DEFAULT}; - static std::optional TryFromDestination(const CTxDestination &dest, KeyType filter=KeyType::UnknownKeyType) { - auto destType = FromOrDefaultDestinationTypeToKeyType(dest.index()) & filter; + static std::optional TryFromDestination(const CTxDestination &dest, KeyType filter=KeyType::AllKeyType) { + auto destType = TxDestTypeToKeyType(dest.index()) & filter; switch (destType) { case KeyType::PKHashKeyType: return CKeyID(std::get(dest)); @@ -49,7 +49,7 @@ class CKeyID : public uint160 } } - static CKeyID FromOrDefaultDestination(const CTxDestination &dest, KeyType filter=KeyType::UnknownKeyType) { + static CKeyID FromOrDefaultDestination(const CTxDestination &dest, KeyType filter=KeyType::AllKeyType) { auto key = TryFromDestination(dest, filter); if (key) { return *key; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 9f8bca5eb3..ed4f3cf1ce 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -12,6 +12,7 @@ #include