From c2df9366f0a924bbdc7760c9c78bef056666222c Mon Sep 17 00:00:00 2001 From: fanquake Date: Fri, 4 Oct 2019 13:27:52 -0400 Subject: [PATCH 1/9] Merge #16507: feefilter: Compute the absolute fee rather than stored rate eb7b78165966f2c79da71b993c4c4d793e37297f modify p2p_feefilter test to catch rounding error (Gregory Sanders) 6a51f7951716d6d6fc0f9b56028f3a0dd02b61c8 Disallow implicit conversion for CFeeRate constructor (Gregory Sanders) 8e59af55aaf1b196575084bce2448af02d97d745 feefilter: Compute the absolute fee rather than stored rate to match mempool acceptance logic (Gregory Sanders) Pull request description: This means we will use the rounding-down behavior in `GetFee` to match both mempool acceptance and wallet logic, with minimal changes. Fixes https://github.com/bitcoin/bitcoin/issues/16499 Replacement PR for https://github.com/bitcoin/bitcoin/pull/16500 ACKs for top commit: ajtowns: ACK eb7b78165966f2c79da71b993c4c4d793e37297f code review only naumenkogs: utACK eb7b78165966f2c79da71b993c4c4d793e37297f achow101: re ACK eb7b78165966f2c79da71b993c4c4d793e37297f promag: ACK eb7b78165966f2c79da71b993c4c4d793e37297f. Tree-SHA512: 484a11c8f0e825f0c983b1f7e71cf6252b1bba6858194abfe4c088da3bae8a418ec539ef6c4181bf30940e277a95c08d493595d59dfcc6ddf77c65b05563dd7e --- src/policy/feerate.h | 2 +- src/txmempool.cpp | 2 +- src/txmempool.h | 7 +++++-- src/wallet/rpcwallet.cpp | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/policy/feerate.h b/src/policy/feerate.h index fd5b581710..386ef05fbd 100644 --- a/src/policy/feerate.h +++ b/src/policy/feerate.h @@ -25,7 +25,7 @@ public: /** Fee rate of 0 satoshis per kB */ CFeeRate() : nSatoshisPerK(0) { } template - CFeeRate(const I _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { + explicit CFeeRate(const I _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { // We've previously had bugs creep in from silent double->int conversion... static_assert(std::is_integral::value, "CFeeRate should be used without floats"); } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 569a7e89bb..d8a1e21d01 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1207,7 +1207,7 @@ void CTxMemPool::queryHashes(std::vector& vtxid) const } static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) { - return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize()), it->GetModifiedFee() - it->GetFee()}; + return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), it->GetFee(), it->GetTxSize(), it->GetModifiedFee() - it->GetFee()}; } std::vector CTxMemPool::infoAll() const diff --git a/src/txmempool.h b/src/txmempool.h index 6fa21023a8..1e1ae30ee5 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -343,8 +343,11 @@ struct TxMempoolInfo /** Time the transaction entered the mempool. */ std::chrono::seconds m_time; - /** Feerate of the transaction. */ - CFeeRate feeRate; + /** Fee of the transaction. */ + CAmount fee; + + /** Virtual size of the transaction. */ + size_t vsize; /** The fee delta. */ int64_t nFeeDelta; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 854bb927df..1d85741912 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2315,7 +2315,7 @@ static UniValue settxfee(const JSONRPCRequest& request) CAmount nAmount = AmountFromValue(request.params[0]); CFeeRate tx_fee_rate(nAmount, 1000); CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000); - if (tx_fee_rate == 0) { + if (tx_fee_rate == CFeeRate(0)) { // automatic selection } else if (tx_fee_rate < pwallet->chain().relayMinFee()) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString())); From 5d8f25027082f7c73699966e25dae3ee9ad36608 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 2 Oct 2019 13:42:47 -0400 Subject: [PATCH 2/9] Merge #16524: Wallet: Disable -fallbackfee by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ea4cc3a7b36a9c77dbf0aff439da3ef0ea58e6e4 Truly decouple wallet from chainparams for -fallbackfee (Jorge Timón) Pull request description: Before it was 0 by default for main and 20000 for test and regtest. Now it is 0 by default for all chains, thus there's no need to call Params(). Also now the default for main is properly documented. Suggestion for release notes: -fallbackfee was 0 (disabled) by default for the main chain, but 20000 by default for the test chains. Now it is 0 by default for all chains. Testnet and regtest users will have to add fallbackfee=20000 to their configuration if they weren't setting it and they want it to keep working like before. Should I propose them to the wiki for the release notes or only after merge? For more context, see https://github.com/bitcoin/bitcoin/pull/16402#issuecomment-515701042 ACKs for top commit: MarcoFalke: ACK ea4cc3a7b36a9c77dbf0aff439da3ef0ea58e6e4 Tree-SHA512: fdfaba5d813da4221e405e0988bef44f3856d10f897a94f9614386d14b7716f4326ab8a6646e26d41ef3f4fa61b936191e216b1b605e9ab0520b0657fc162e6c ---- Co-Authored-By: UdjinM6 --- doc/release-notes-16524.md | 8 ++++++++ src/wallet/init.cpp | 2 +- src/wallet/test/coinjoin_tests.cpp | 1 + src/wallet/test/wallet_tests.cpp | 20 ++++++++++++++------ src/wallet/wallet.cpp | 5 +++-- src/wallet/wallet.h | 4 ++-- test/functional/test_framework/util.py | 1 + 7 files changed, 30 insertions(+), 11 deletions(-) create mode 100644 doc/release-notes-16524.md diff --git a/doc/release-notes-16524.md b/doc/release-notes-16524.md new file mode 100644 index 0000000000..7000c9c665 --- /dev/null +++ b/doc/release-notes-16524.md @@ -0,0 +1,8 @@ + +Low-level changes +================= + +Tests +--- + +- `-fallbackfee` was 0 (disabled) by default for the main chain, but 1000 by default for the test chains. Now it is 0 by default for all chains. Testnet and regtest users will have to add fallbackfee=1000 to their configuration if they weren't setting it and they want it to keep working like before. (bitcoin#16524) diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 49d490fa7c..483bc7e4e7 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -73,7 +73,7 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const argsman.AddArg("-discardfee=", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). " "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target", CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET_FEE); - argsman.AddArg("-fallbackfee=", strprintf("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)", + argsman.AddArg("-fallbackfee=", strprintf("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data. 0 to entirely disable the fallbackfee feature. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET_FEE); argsman.AddArg("-maxtxfee=", strprintf("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); diff --git a/src/wallet/test/coinjoin_tests.cpp b/src/wallet/test/coinjoin_tests.cpp index 6193b6f387..53aefdfe05 100644 --- a/src/wallet/test/coinjoin_tests.cpp +++ b/src/wallet/test/coinjoin_tests.cpp @@ -178,6 +178,7 @@ public: int nChangePosRet = -1; bilingual_str strError; CCoinControl coinControl; + coinControl.m_feerate = CFeeRate(1000); { LOCK(wallet->cs_wallet); BOOST_CHECK(reserveDest.GetReservedDestination(tallyItem.txdest, false)); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 97a8cfb9d7..ddf52096ff 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -38,6 +38,10 @@ extern RecursiveMutex cs_wallets; BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup) +namespace { +constexpr CAmount fallbackFee = 1000; +} // anonymous namespace + static std::shared_ptr TestLoadWallet(interfaces::Chain& chain) { DatabaseOptions options; @@ -869,7 +873,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup) coinControl.Select(GetCoins({{100000, false}})[0]); // Start with fallback feerate - runTest(1, DEFAULT_FALLBACK_FEE, { + runTest(1, fallbackFee, { {0, {true, ChangeTest::ChangeExpected}}, {1, {true, ChangeTest::ChangeExpected}}, {2, {true, ChangeTest::ChangeExpected}}, @@ -886,7 +890,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup) {13, {false, ChangeTest::Skip}} }); // Now with 100x fallback feerate - runTest(2, DEFAULT_FALLBACK_FEE * 100, { + runTest(2, fallbackFee * 100, { {0, {true, ChangeTest::ChangeExpected}}, {1, {false, ChangeTest::Skip}}, {2, {true, ChangeTest::ChangeExpected}}, @@ -912,7 +916,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup) } // Start with fallback feerate - runTest(3, DEFAULT_FALLBACK_FEE, { + runTest(3, fallbackFee, { {0, {true, ChangeTest::ChangeExpected}}, {1, {false, ChangeTest::Skip}}, {2, {true, ChangeTest::ChangeExpected}}, @@ -929,7 +933,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup) {13, {false, ChangeTest::Skip}} }); // Now with 100x fallback feerate - runTest(4, DEFAULT_FALLBACK_FEE * 100, { + runTest(4, fallbackFee * 100, { {0, {true, ChangeTest::ChangeExpected}}, {1, {false, ChangeTest::Skip}}, {2, {true, ChangeTest::ChangeExpected}}, @@ -958,7 +962,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup) } // Start with fallback feerate - runTest(5, DEFAULT_FALLBACK_FEE, { + runTest(5, fallbackFee, { {0, {true, ChangeTest::ChangeExpected}}, {1, {false, ChangeTest::Skip}}, {2, {true, ChangeTest::ChangeExpected}}, @@ -975,7 +979,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup) {13, {false, ChangeTest::Skip}} }); // Now with 100x fallback feerate - runTest(6, DEFAULT_FALLBACK_FEE * 100, { + runTest(6, fallbackFee * 100, { {0, {false, ChangeTest::Skip}}, {1, {false, ChangeTest::Skip}}, {2, {false, ChangeTest::Skip}}, @@ -996,6 +1000,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup) // which inputs to use { coinControl.SetNull(); + coinControl.m_feerate = CFeeRate(fallbackFee); auto setCoins = GetCoins({{1000, false}, {1000, false}, {1000, false}, {1000, false}, {1000, false}, {1100, false}, {1200, false}, {1300, false}, {1400, false}, {1500, false}, {3000, false}, {3000, false}, {2000, false}, {2000, false}, {1000, false}}); @@ -1044,6 +1049,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup) // Test if the change output ends up at the requested position { coinControl.SetNull(); + coinControl.m_feerate = CFeeRate(fallbackFee); coinControl.Select(GetCoins({{100000, false}})[0]); BOOST_CHECK(CreateTransaction({{25000, false}, {25000, false}, {25000, false}}, {}, 0, true, ChangeTest::ChangeExpected)); @@ -1054,6 +1060,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup) // Test error cases { coinControl.SetNull(); + coinControl.m_feerate = CFeeRate(fallbackFee); // First try to send something without any coins available { // Lock all other coins @@ -1090,6 +1097,7 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup) }; coinControl.SetNull(); + coinControl.m_feerate = CFeeRate(fallbackFee); coinControl.Select(GetCoins({{100 * COIN, false}})[0]); BOOST_CHECK(CreateTransaction({{-5000, false}}, strAmountNotNegative, false)); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 29caa15bf7..72f478575d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4610,7 +4610,6 @@ std::shared_ptr CWallet::Create(interfaces::Chain& chain, const std::st walletInstance->m_min_fee = CFeeRate{min_tx_fee.value()}; } - walletInstance->m_allow_fallback_fee = Params().IsTestChain(); if (gArgs.IsArgSet("-fallbackfee")) { std::optional fallback_fee = ParseMoney(gArgs.GetArg("-fallbackfee", "")); if (!fallback_fee) { @@ -4621,8 +4620,10 @@ std::shared_ptr CWallet::Create(interfaces::Chain& chain, const std::st _("This is the transaction fee you may pay when fee estimates are not available.")); } walletInstance->m_fallback_fee = CFeeRate{fallback_fee.value()}; - walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.GetFeePerK() != 0; //disable fallback fee in case value was set to 0, enable if non-null value } + // Disable fallback fee in case value was set to 0, enable if non-null value + walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.GetFeePerK() != 0; + if (gArgs.IsArgSet("-discardfee")) { std::optional discard_fee = ParseMoney(gArgs.GetArg("-discardfee", "")); if (!discard_fee) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index c8fe99ba83..60c854638b 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -67,7 +67,7 @@ std::unique_ptr MakeWalletDatabase(const std::string& name, cons //! -paytxfee default constexpr CAmount DEFAULT_PAY_TX_FEE = 0; //! -fallbackfee default -static const CAmount DEFAULT_FALLBACK_FEE = 1000; +static const CAmount DEFAULT_FALLBACK_FEE = 0; //! -discardfee default static const CAmount DEFAULT_DISCARD_FEE = 10000; //! -mintxfee default @@ -1070,7 +1070,7 @@ public: CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE}; unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET}; bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE}; - bool m_allow_fallback_fee{true}; //!< will be defined via chainparams + bool m_allow_fallback_fee{true}; //!< will be false if -fallbackfee=0 CFeeRate m_min_fee{DEFAULT_TRANSACTION_MINFEE}; //!< Override with -mintxfee /** * If fee estimation does not have enough data to provide estimates, use this fee instead. diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index c9b5c73d2f..43bdf366ba 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -340,6 +340,7 @@ def initialize_datadir(dirname, n, chain): f.write("[{}]\n".format(chain_name_conf_section)) f.write("port=" + str(p2p_port(n)) + "\n") f.write("rpcport=" + str(rpc_port(n)) + "\n") + f.write("fallbackfee=0.00001\n") f.write("server=1\n") f.write("keypool=1\n") f.write("discover=0\n") From d8f96924f8339a18f9019e3a1799571e564cba64 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Fri, 18 Oct 2019 09:56:43 -0400 Subject: [PATCH 3/9] Merge #16889: Add some general std::vector utility functions 7d8d3e6a2ad827fa916e3909a18dedb9f7fdce43 Add tests for util/vector.h's Cat and Vector (Pieter Wuille) e65e61c812df90a56e3ce4a8e76c4b746766f387 Add some general std::vector utility functions (Pieter Wuille) Pull request description: This is another general improvement extracted from #16800 . Two functions are added are: * Vector(arg1,arg2,arg3,...) constructs a vector with the specified arguments as elements. The vector's type is derived from the arguments. If some of the arguments are rvalue references, they will be moved into place rather than copied (which can't be achieved using list initialization). * Cat(vector1,vector2) returns a concatenation of the two vectors, efficiently moving elements when relevant. Vector generalizes (and replaces) the `Singleton` function in src/descriptor.cpp, and `Cat` replaces the function in bech32.cpp ACKs for top commit: laanwj: ACK 7d8d3e6a2ad827fa916e3909a18dedb9f7fdce43 MarcoFalke: ACK 7d8d3e6a2ad827fa916e3909a18dedb9f7fdce43 (enjoyed reading the tests, but did not compile) Tree-SHA512: 92325f14e90d7e7d9d920421979aec22bb0d730e0291362b4326cccc76f9c2d865bec33a797c5c0201773468c3773cb50ce52c8eee4c1ec1a4d10db5cf2b9d2a --- src/Makefile.am | 1 + src/script/descriptor.cpp | 30 +++++++++++------------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index ada9398bad..c2cf71e509 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -327,6 +327,7 @@ BITCOIN_CORE_H = \ util/vector.h \ util/url.h \ util/validation.h \ + util/vector.h \ validation.h \ validationinterface.h \ versionbits.h \ diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 4a4ae250a2..68ab75e84c 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -549,22 +550,13 @@ public: } }; -/** Construct a vector with one element, which is moved into it. */ -template -std::vector Singleton(T elem) -{ - std::vector ret; - ret.emplace_back(std::move(elem)); - return ret; -} - /** A parsed addr(A) descriptor. */ class AddressDescriptor final : public DescriptorImpl { const CTxDestination m_destination; protected: std::string ToStringExtra() const override { return EncodeDestination(m_destination); } - std::vector MakeScripts(const std::vector&, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(m_destination)); } + std::vector MakeScripts(const std::vector&, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); } public: AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {} bool IsSolvable() const final { return false; } @@ -576,7 +568,7 @@ class RawDescriptor final : public DescriptorImpl const CScript m_script; protected: std::string ToStringExtra() const override { return HexStr(m_script); } - std::vector MakeScripts(const std::vector&, const CScript*, FlatSigningProvider&) const override { return Singleton(m_script); } + std::vector MakeScripts(const std::vector&, const CScript*, FlatSigningProvider&) const override { return Vector(m_script); } public: RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {} bool IsSolvable() const final { return false; } @@ -586,9 +578,9 @@ public: class PKDescriptor final : public DescriptorImpl { protected: - std::vector MakeScripts(const std::vector& keys, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForRawPubKey(keys[0])); } + std::vector MakeScripts(const std::vector& keys, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); } public: - PKDescriptor(std::unique_ptr prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pk") {} + PKDescriptor(std::unique_ptr prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pk") {} }; /** A parsed pkh(P) descriptor. */ @@ -599,10 +591,10 @@ protected: { CKeyID id = keys[0].GetID(); out.pubkeys.emplace(id, keys[0]); - return Singleton(GetScriptForDestination(PKHash(id))); + return Vector(GetScriptForDestination(PKHash(id))); } public: - PKHDescriptor(std::unique_ptr prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {} + PKHDescriptor(std::unique_ptr prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pkh") {} }; /** A parsed multi(...) or sortedmulti(...) descriptor */ @@ -616,9 +608,9 @@ protected: if (m_sorted) { std::vector sorted_keys(keys); std::sort(sorted_keys.begin(), sorted_keys.end()); - return Singleton(GetScriptForMultisig(m_threshold, sorted_keys)); + return Vector(GetScriptForMultisig(m_threshold, sorted_keys)); } - return Singleton(GetScriptForMultisig(m_threshold, keys)); + return Vector(GetScriptForMultisig(m_threshold, keys)); } public: MultisigDescriptor(int threshold, std::vector> providers, bool sorted = false) : DescriptorImpl(std::move(providers), {}, sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {} @@ -628,7 +620,7 @@ public: class SHDescriptor final : public DescriptorImpl { protected: - std::vector MakeScripts(const std::vector&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(ScriptHash(*script))); } + std::vector MakeScripts(const std::vector&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(ScriptHash(*script))); } public: SHDescriptor(std::unique_ptr desc) : DescriptorImpl({}, std::move(desc), "sh") {} }; @@ -653,7 +645,7 @@ protected: } public: - ComboDescriptor(std::unique_ptr prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "combo") {} + ComboDescriptor(std::unique_ptr prov) : DescriptorImpl(Vector(std::move(prov)), {}, "combo") {} }; //////////////////////////////////////////////////////////////////////////// From 4052f1e548c6c72f5c43ad922c4c5a6d51d6637e Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 21 Oct 2019 12:29:44 +0200 Subject: [PATCH 4/9] Merge #17195: gui: send amount placeholder value 57e2edea0bfea664e3f12dad2508139eb7f461bc Send amount shows minimum amount placeholder (JeremyCrookshank) Pull request description: Noticed that there wasn't a default value for the send amount. However if you put a value in or click the up and down arrows you're unable to get it blank again, so it makes sense that it has a default value. I hope this also makes it more clear that users can send less than 1 BTC if it shows the 8 decimal places PR: ![Capture](https://user-images.githubusercontent.com/46864828/67132088-549c6180-f1ff-11e9-9ba5-67fdcd6db894.PNG) ACKs for top commit: promag: ACK 57e2edea0bfea664e3f12dad2508139eb7f461bc. GChuf: ACK 57e2edea0bfea664e3f12dad2508139eb7f461bc laanwj: ACK 57e2edea0bfea664e3f12dad2508139eb7f461bc, this is a surprisingly compact solution too Tree-SHA512: 354590d2a88231b8649f7ae985c8a7864d74ca0e1f8603cb1730ba46747084de90ee6285ce4d39ee04b054fb9cd2d78ebc71146f3af694c37a8a3aff7f051800 --- src/qt/bitcoinamountfield.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index e432e7551f..7442782ac4 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -130,6 +130,7 @@ public: currentUnit = unit; amountValidator->updateUnit(unit); + setPlaceholderText(BitcoinUnits::format(currentUnit, m_min_amount, false, BitcoinUnits::separatorAlways)); if(valid) setValue(val); else From 97b1f6875e3c0f40b20625e7148f6fcf7fecf51b Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 23 Oct 2019 12:03:57 +0200 Subject: [PATCH 5/9] Merge #16911: wallet: Only check the hash of transactions loaded from disk cd68594dcdadc195bd2ea9394fa04edfdbdf1149 Only check the hash of transactions loaded from disk (Andrew Chow) Pull request description: It feels unnecessary to do a full `CheckTransaction` for every transaction saved in the wallet. It should not be possible for an invalid transaction to get into the wallet in the first place, and if there is any disk corruption, the hash check will catch it. ACKs for top commit: MarcoFalke: ACK cd68594dcdadc195bd2ea9394fa04edfdbdf1149 laanwj: ACK cd68594dcdadc195bd2ea9394fa04edfdbdf1149 promag: ACK cd68594dcdadc195bd2ea9394fa04edfdbdf1149, AFAICT the check is not needed, hash comparison gives data integrity. Tree-SHA512: 5b2e719f76097cfbf125392db6cc6c764355c81f0b7a5b60aee4b06af1afcca80cfd38a3cf5307fd9e2c1afc405f8321929a4552943099a8161e6762965451fb --- src/wallet/walletdb.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index b32544b28a..90eb2c6342 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -6,8 +6,6 @@ #include -#include -#include #include #include #include @@ -255,8 +253,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, ssKey >> hash; CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef()); ssValue >> wtx; - CValidationState state; - if (!(CheckTransaction(*wtx.tx, state) && (wtx.GetHash() == hash) && state.IsValid())) + if (wtx.GetHash() != hash) return false; // Undo serialize changes in 31600 From 091d813e0010a5ab5ef0db9c76264347c36bb23c Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 24 Oct 2019 10:43:02 +0200 Subject: [PATCH 6/9] Merge #17004: validation: Remove REJECT code from CValidationState 9075d13153ce06cd59a45644831ecc43126e1e82 [docs] Add release notes for removal of REJECT reasons (John Newbery) 04a2f326ec0f06fb4fce1c4f93500752f05dede8 [validation] Fix REJECT message comments (John Newbery) e9d5a59e34ff2d538d8f5315efd9908bf24d0fdc [validation] Remove REJECT code from CValidationState (John Newbery) 0053e16714323c1694c834fdca74f064a1a33529 [logging] Don't log REJECT code when transaction is rejected (John Newbery) a1a07cfe99fc8cee30ba5976dc36b47b1f6532ab [validation] Fix peer punishment for bad blocks (John Newbery) Pull request description: We no longer send BIP 61 REJECT messages, so there's no need to set a REJECT code in the CValidationState object. Note that there is a minor bug fix in p2p behaviour here. Because the call to `MaybePunishNode()` in `PeerLogicValidation::BlockChecked()` only previously happened if the REJECT code was > 0 and < `REJECT_INTERNAL`, then there are cases were `MaybePunishNode()` can get called where it wasn't previously: - when `AcceptBlockHeader()` fails with `CACHED_INVALID`. - when `AcceptBlockHeader()` fails with `BLOCK_MISSING_PREV`. Note that `BlockChecked()` cannot fail with an 'internal' reject code. The only internal reject code was `REJECT_HIGHFEE`, which was only set in ATMP. This reverts a minor bug introduced in 5d08c9c579ba8cc7b684105c6a08263992b08d52. ACKs for top commit: ariard: ACK 9075d13, changes since last reviewed are splitting them in separate commits to ease understanding and fix nits fjahr: ACK 9075d13153ce06cd59a45644831ecc43126e1e82, confirmed diff to last review was fixing nits in docs/comments. ryanofsky: Code review ACK 9075d13153ce06cd59a45644831ecc43126e1e82. Only changes since last review are splitting the main commit and updating comments Tree-SHA512: 58e8a1a4d4e6f156da5d29fb6ad6a62fc9c594bbfc6432b3252e962d0e9e10149bf3035185dc5320c46c09f3e49662bc2973ec759679c0f3412232087cb8a3a7 --- doc/release-notes-17004.md | 31 +++++ src/consensus/tx_check.cpp | 20 +-- src/consensus/tx_verify.cpp | 13 +- src/consensus/validation.h | 19 +-- src/evo/cbtx.cpp | 34 ++--- src/evo/deterministicmns.cpp | 152 +++++++++++----------- src/evo/mnhftx.cpp | 12 +- src/evo/specialtxman.cpp | 10 +- src/llmq/blockprocessor.cpp | 24 ++-- src/llmq/commitment.cpp | 16 +-- src/net_processing.cpp | 44 ++----- src/rpc/rawtransaction.cpp | 2 +- src/test/specialtx_tests.cpp | 4 +- src/util/validation.cpp | 5 +- src/validation.cpp | 133 ++++++++++--------- src/validation.h | 8 -- test/functional/feature_bip68_sequence.py | 2 +- test/functional/feature_cltv.py | 2 +- test/functional/feature_dersig.py | 2 +- test/functional/feature_nulldummy.py | 2 +- test/functional/mempool_accept.py | 44 +++---- test/functional/rpc_rawtransaction.py | 4 +- 22 files changed, 290 insertions(+), 293 deletions(-) create mode 100644 doc/release-notes-17004.md diff --git a/doc/release-notes-17004.md b/doc/release-notes-17004.md new file mode 100644 index 0000000000..8789daeafe --- /dev/null +++ b/doc/release-notes-17004.md @@ -0,0 +1,31 @@ +P2P and network changes +----------------------- + +#### Removal of reject network messages from Dash Core (BIP61) + +The command line option to enable BIP61 (`-enablebip61`) has been removed. + +This feature has been disabled by default since Dash Core version 0.19.0. +Nodes on the network can not generally be trusted to send valid ("reject") +messages, so this should only ever be used when connected to a trusted node. + +Since Dash Core version 0.20.0 there are extra changes: + +The removal of BIP61 REJECT message support also has the following minor RPC +and logging implications: + +* `testmempoolaccept` and `sendrawtransaction` no longer return the P2P REJECT + code when a transaction is not accepted to the mempool. They still return the + verbal reject reason. + +* Log messages that previously reported the REJECT code when a transaction was + not accepted to the mempool now no longer report the REJECT code. The reason + for rejection is still reported. + +Updated RPCs +------------ + +- `testmempoolaccept` and `sendrawtransaction` no longer return the P2P REJECT + code when a transaction is not accepted to the mempool. See the Section + _Removal of reject network messages from Bitcoin Core (BIP61)_ for details on + the removal of BIP61 REJECT message support. diff --git a/src/consensus/tx_check.cpp b/src/consensus/tx_check.cpp index f7799a48e2..36b91dc58a 100644 --- a/src/consensus/tx_check.cpp +++ b/src/consensus/tx_check.cpp @@ -19,25 +19,25 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state) // Basic checks that don't depend on any context if (!allowEmptyTxInOut && tx.vin.empty()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vin-empty"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vin-empty"); if (!allowEmptyTxInOut && tx.vout.empty()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-empty"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-empty"); // Size limits if (::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-oversize"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-oversize"); if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-payload-oversize"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-payload-oversize"); // Check for negative or overflow output values (see CVE-2010-5139) CAmount nValueOut = 0; for (const auto& txout : tx.vout) { if (txout.nValue < 0) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-negative"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-negative"); if (txout.nValue > MAX_MONEY) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-toolarge"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-toolarge"); nValueOut += txout.nValue; if (!MoneyRange(nValueOut)) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-txouttotal-toolarge"); } // Check for duplicate inputs (see CVE-2018-17144) @@ -48,7 +48,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state) std::set vInOutPoints; for (const auto& txin : tx.vin) { if (!vInOutPoints.insert(txin.prevout).second) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputs-duplicate"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputs-duplicate"); } if (tx.IsCoinBase()) { @@ -58,11 +58,11 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state) minCbSize = 1; } if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-length"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-length"); } else { for (const auto& txin : tx.vin) if (txin.prevout.IsNull()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-prevout-null"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-prevout-null"); } return true; diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index ef28c169db..bcad06db3d 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -162,7 +162,8 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c { // are the actual inputs available? if (!inputs.HaveInputs(tx)) { - return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", strprintf("%s: inputs missing/spent", __func__)); + return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, "bad-txns-inputs-missingorspent", + strprintf("%s: inputs missing/spent", __func__)); } CAmount nValueIn = 0; @@ -173,25 +174,27 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c // If prev is coinbase, check that it's matured if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) { - return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight)); + return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "bad-txns-premature-spend-of-coinbase", + strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight)); } // Check for negative or overflow input values nValueIn += coin.out.nValue; if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputvalues-outofrange"); } } const CAmount value_out = tx.GetValueOut(); if (nValueIn < value_out) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-in-belowout", strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out))); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-in-belowout", + strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out))); } // Tally transaction fees const CAmount txfee_aux = nValueIn - value_out; if (!MoneyRange(txfee_aux)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-fee-outofrange"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-fee-outofrange"); } txfee = txfee_aux; diff --git a/src/consensus/validation.h b/src/consensus/validation.h index 5120c90e49..6628926255 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -8,20 +8,8 @@ #include -/** "reject" message codes */ -static const unsigned char REJECT_MALFORMED = 0x01; -static const unsigned char REJECT_INVALID = 0x10; -static const unsigned char REJECT_OBSOLETE = 0x11; -static const unsigned char REJECT_DUPLICATE = 0x12; -static const unsigned char REJECT_NONSTANDARD = 0x40; -// static const unsigned char REJECT_DUST = 0x41; // part of BIP 61 -static const unsigned char REJECT_INSUFFICIENTFEE = 0x42; -static const unsigned char REJECT_CHECKPOINT = 0x43; - /** A "reason" why something was invalid, suitable for determining whether the * provider of the object should be banned/ignored/disconnected/etc. - * These are much more granular than the rejection codes, which may be more - * useful for some other use-cases. */ enum class ValidationInvalidReason { // txn and blocks: @@ -94,15 +82,13 @@ private: } mode; ValidationInvalidReason m_reason; std::string strRejectReason; - unsigned int chRejectCode; std::string strDebugMessage; public: - CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE), chRejectCode(0) {} + CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE) {} bool Invalid(ValidationInvalidReason reasonIn, bool ret = false, - unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="", + const std::string &strRejectReasonIn="", const std::string &strDebugMessageIn="") { m_reason = reasonIn; - chRejectCode = chRejectCodeIn; strRejectReason = strRejectReasonIn; strDebugMessage = strDebugMessageIn; if (mode == MODE_ERROR) @@ -126,7 +112,6 @@ public: return mode == MODE_ERROR; } ValidationInvalidReason GetReason() const { return m_reason; } - unsigned int GetRejectCode() const { return chRejectCode; } std::string GetRejectReason() const { return strRejectReason; } std::string GetDebugMessage() const { return strDebugMessage; } }; diff --git a/src/evo/cbtx.cpp b/src/evo/cbtx.cpp index 8f4b4fb60c..81313526af 100644 --- a/src/evo/cbtx.cpp +++ b/src/evo/cbtx.cpp @@ -18,30 +18,30 @@ bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) { if (tx.nType != TRANSACTION_COINBASE) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-type"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-type"); } if (!tx.IsCoinBase()) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-invalid"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-invalid"); } CCbTx cbTx; if (!GetTxPayload(tx, cbTx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-payload"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-payload"); } if (cbTx.nVersion == 0 || cbTx.nVersion > CCbTx::CURRENT_VERSION) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-version"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-version"); } if (pindexPrev && pindexPrev->nHeight + 1 != cbTx.nHeight) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-height"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-height"); } if (pindexPrev) { bool fDIP0008Active = pindexPrev->nHeight >= Params().GetConsensus().DIP0008Height; if (fDIP0008Active && cbTx.nVersion < 2) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-version"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-version"); } } @@ -61,7 +61,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const CCbTx cbTx; if (!GetTxPayload(*block.vtx[0], cbTx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-payload"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-payload"); } int64_t nTime2 = GetTimeMicros(); nTimePayload += nTime2 - nTime1; @@ -77,7 +77,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const return false; } if (calculatedMerkleRoot != cbTx.merkleRootMNList) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-mnmerkleroot"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-mnmerkleroot"); } int64_t nTime3 = GetTimeMicros(); nTimeMerkleMNL += nTime3 - nTime2; @@ -89,7 +89,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const return false; } if (calculatedMerkleRoot != cbTx.merkleRootQuorums) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cbtx-quorummerkleroot"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-quorummerkleroot"); } } @@ -134,7 +134,7 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev if (sml == smlCached) { merkleRootRet = merkleRootCached; if (mutatedCached) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-cached-calc-cb-mnmerkleroot"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "mutated-cached-calc-cb-mnmerkleroot"); } return true; } @@ -150,13 +150,13 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev mutatedCached = mutated; if (mutated) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-calc-cb-mnmerkleroot"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "mutated-calc-cb-mnmerkleroot"); } return true; } catch (const std::exception& e) { LogPrintf("%s -- failed: %s\n", __func__, e.what()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-calc-cb-mnmerkleroot"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-calc-cb-mnmerkleroot"); } } @@ -233,7 +233,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre auto retVal = CachedGetQcHashesQcIndexedHashes(pindexPrev, quorum_block_processor); if (!retVal) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "commitment-not-found"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "commitment-not-found"); } // The returned quorums are in reversed order, so the most recent one is at index 0 auto [qcHashes, qcIndexedHashes] = retVal.value(); @@ -249,7 +249,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre if (tx->nVersion == 3 && tx->nType == TRANSACTION_QUORUM_COMMITMENT) { llmq::CFinalCommitmentTxPayload qc; if (!GetTxPayload(*tx, qc)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload-calc-cbtx-quorummerkleroot"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload-calc-cbtx-quorummerkleroot"); } if (qc.commitment.IsNull()) { // having null commitments is ok but we don't use them here, move to the next tx @@ -257,7 +257,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre } const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType); if (!llmq_params_opt.has_value()) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot"); } const auto& llmq_params = llmq_params_opt.value(); auto qcHash = ::SerializeHash(qc.commitment); @@ -291,7 +291,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType); assert(llmq_params_opt.has_value()); if (vec_hashes.size() > size_t(llmq_params_opt->signingActiveQuorumCount)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "excess-quorums-calc-cbtx-quorummerkleroot"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "excess-quorums-calc-cbtx-quorummerkleroot"); } // Copy vec_hashes into vec_hashes_final std::copy(vec_hashes.begin(), vec_hashes.end(), std::back_inserter(vec_hashes_final)); @@ -308,7 +308,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre LogPrint(BCLog::BENCHMARK, " - ComputeMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkle * 0.000001); if (mutated) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "mutated-calc-cbtx-quorummerkleroot"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "mutated-calc-cbtx-quorummerkleroot"); } return true; diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 6a4a13846b..758b086d0e 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -710,7 +710,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde mnListDiffsCache.emplace(pindex->GetBlockHash(), diff); } catch (const std::exception& e) { LogPrintf("CDeterministicMNManager::%s -- internal error: %s\n", __func__, e.what()); - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-dmn-block"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-dmn-block"); } // Don't hold cs while calling signals @@ -723,7 +723,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde if (!consensusParams.DIP0003EnforcementHash.IsNull() && consensusParams.DIP0003EnforcementHash != pindex->GetBlockHash()) { LogPrintf("CDeterministicMNManager::%s -- DIP3 enforcement block has wrong hash: hash=%s, expected=%s, nHeight=%d\n", __func__, pindex->GetBlockHash().ToString(), consensusParams.DIP0003EnforcementHash.ToString(), nHeight); - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-dip3-enf-block"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-dip3-enf-block"); } LogPrintf("CDeterministicMNManager::%s -- DIP3 is enforced now. nHeight=%d\n", __func__, nHeight); } @@ -820,11 +820,11 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C if (tx.nType == TRANSACTION_PROVIDER_REGISTER) { CProRegTx proTx; if (!GetTxPayload(tx, proTx)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); } if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); } auto dmn = std::make_shared(newList.GetTotalRegisteredCount(), proTx.nType); @@ -842,7 +842,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C if (!proTx.collateralOutpoint.hash.IsNull() && (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral)) { // should actually never get to this point as CheckProRegTx should have handled this case. // We do this additional check nevertheless to be 100% sure - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-collateral"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-collateral"); } auto replacedDmn = newList.GetMNByCollateral(dmn->collateralOutpoint); @@ -858,10 +858,10 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C } if (newList.HasUniqueProperty(proTx.addr)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_DUPLICATE, "bad-protx-dup-addr"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-dup-addr"); } if (newList.HasUniqueProperty(proTx.keyIDOwner) || newList.HasUniqueProperty(proTx.pubKeyOperator)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_DUPLICATE, "bad-protx-dup-key"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-dup-key"); } dmn->nOperatorReward = proTx.nOperatorReward; @@ -883,26 +883,26 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) { CProUpServTx proTx; if (!GetTxPayload(tx, proTx)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); } if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); } if (newList.HasUniqueProperty(proTx.addr) && newList.GetUniquePropertyMN(proTx.addr)->proTxHash != proTx.proTxHash) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_DUPLICATE, "bad-protx-dup-addr"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-dup-addr"); } CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash); if (!dmn) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash"); } if (proTx.nType != dmn->nType) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type-mismatch"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type-mismatch"); } if (!IsValidMnType(proTx.nType)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type"); } auto newState = std::make_shared(*dmn->pdmnState); @@ -932,12 +932,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REGISTRAR) { CProUpRegTx proTx; if (!GetTxPayload(tx, proTx)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); } CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash); if (!dmn) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash"); } auto newState = std::make_shared(*dmn->pdmnState); if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) { @@ -958,12 +958,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) { CProUpRevTx proTx; if (!GetTxPayload(tx, proTx)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); } CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash); if (!dmn) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash"); } auto newState = std::make_shared(*dmn->pdmnState); newState->ResetOperatorFields(); @@ -979,19 +979,19 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C } else if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) { llmq::CFinalCommitmentTxPayload qc; if (!GetTxPayload(tx, qc)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload"); } if (!qc.commitment.IsNull()) { const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType); if (!llmq_params_opt.has_value()) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type"); } int qcnHeight = int(qc.nHeight); int quorumHeight = qcnHeight - (qcnHeight % llmq_params_opt->dkgInterval) + int(qc.commitment.quorumIndex); auto pQuorumBaseBlockIndex = pindexPrev->GetAncestor(quorumHeight); if (!pQuorumBaseBlockIndex || pQuorumBaseBlockIndex->GetBlockHash() != qc.commitment.quorumHash) { // we should actually never get into this case as validation should have caught it...but let's be sure - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash"); + return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-quorum-hash"); } HandleQuorumCommitment(qc.commitment, pQuorumBaseBlockIndex, newList, debugLogs); @@ -1351,23 +1351,23 @@ template static bool CheckService(const ProTx& proTx, CValidationState& state) { if (!proTx.addr.IsValid()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr"); } if (Params().RequireRoutableExternalIP() && !proTx.addr.IsRoutable()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr"); } static int mainnetDefaultPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort(); if (Params().NetworkIDString() == CBaseChainParams::MAIN) { if (proTx.addr.GetPort() != mainnetDefaultPort) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr-port"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr-port"); } } else if (proTx.addr.GetPort() == mainnetDefaultPort) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr-port"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr-port"); } if (!proTx.addr.IsIPv4()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-ipaddr"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr"); } return true; @@ -1377,35 +1377,35 @@ template static bool CheckPlatformFields(const ProTx& proTx, CValidationState& state) { if (proTx.platformNodeID.IsNull()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-nodeid"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-nodeid"); } static int mainnetPlatformP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformP2PPort(); if (Params().NetworkIDString() == CBaseChainParams::MAIN) { if (proTx.platformP2PPort != mainnetPlatformP2PPort) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-p2p-port"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-p2p-port"); } } static int mainnetPlatformHTTPPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformHTTPPort(); if (Params().NetworkIDString() == CBaseChainParams::MAIN) { if (proTx.platformHTTPPort != mainnetPlatformHTTPPort) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-http-port"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-http-port"); } } static int mainnetDefaultP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort(); if (proTx.platformP2PPort == mainnetDefaultP2PPort) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-p2p-port"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-p2p-port"); } if (proTx.platformHTTPPort == mainnetDefaultP2PPort) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-http-port"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-http-port"); } if (proTx.platformP2PPort == proTx.platformHTTPPort || proTx.platformP2PPort == proTx.addr.GetPort() || proTx.platformHTTPPort == proTx.addr.GetPort()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-platform-dup-ports"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-dup-ports"); } return true; @@ -1416,7 +1416,7 @@ static bool CheckHashSig(const ProTx& proTx, const PKHash& pkhash, CValidationSt { std::string strError; if (!CHashSigner::VerifyHash(::SerializeHash(proTx), ToKeyID(pkhash), proTx.vchSig, strError)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig"); } return true; } @@ -1426,7 +1426,7 @@ static bool CheckStringSig(const ProTx& proTx, const PKHash& pkhash, CValidation { std::string strError; if (!CMessageSigner::VerifyMessage(ToKeyID(pkhash), proTx.vchSig, proTx.MakeSignString(), strError)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig"); } return true; } @@ -1435,7 +1435,7 @@ template static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, CValidationState& state) { if (!proTx.sig.VerifyInsecure(pubKey, ::SerializeHash(proTx))) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig"); } return true; } @@ -1443,16 +1443,16 @@ static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, CValid bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) { if (tx.nType != TRANSACTION_PROVIDER_REGISTER) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type"); } CProRegTx ptx; if (!GetTxPayload(tx, ptx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); } if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); } // It's allowed to set addr to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later @@ -1477,31 +1477,31 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid if (!ptx.collateralOutpoint.hash.IsNull()) { Coin coin; if (!view.GetCoin(ptx.collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral"); } if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-dest"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-dest"); } // Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH. // Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx keyForPayloadSig = std::get_if(&collateralTxDest); if (!keyForPayloadSig) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-pkh"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-pkh"); } collateralOutpoint = ptx.collateralOutpoint; } else { if (ptx.collateralOutpoint.n >= tx.vout.size()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-index"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-index"); } if (tx.vout[ptx.collateralOutpoint.n].nValue != expectedCollateral) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral"); } if (!ExtractDestination(tx.vout[ptx.collateralOutpoint.n].scriptPubKey, collateralTxDest)) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-dest"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-dest"); } collateralOutpoint = COutPoint(tx.GetHash(), ptx.collateralOutpoint.n); @@ -1510,7 +1510,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid // don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server) // this check applies to internal and external collateral, but internal collaterals are not necessarily a P2PKH if (collateralTxDest == CTxDestination(PKHash(ptx.keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-reuse"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-reuse"); } if (pindexPrev) { @@ -1518,30 +1518,30 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid // only allow reusing of addresses when it's for the same collateral (which replaces the old MN) if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->collateralOutpoint != collateralOutpoint) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-addr"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-addr"); } // never allow duplicate keys, even if this ProTx would replace an existing MN if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.pubKeyOperator)) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-key"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-key"); } // never allow duplicate platformNodeIds for HPMNs if (ptx.nType == MnType::HighPerformance) { if (mnList.HasUniqueProperty(ptx.platformNodeID)) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-platformnodeid"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-platformnodeid"); } } if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) { if (ptx.keyIDOwner != ptx.keyIDVoting) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-key-not-same"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-key-not-same"); } } } if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); } if (keyForPayloadSig) { @@ -1553,7 +1553,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid } else { // collateral is part of this ProRegTx, so we know the collateral is owned by the issuer if (!ptx.vchSig.empty()) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-sig"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig"); } } @@ -1563,16 +1563,16 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs) { if (tx.nType != TRANSACTION_PROVIDER_UPDATE_SERVICE) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type"); } CProUpServTx ptx; if (!GetTxPayload(tx, ptx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); } if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); } if (!CheckService(ptx, state)) { @@ -1590,34 +1590,34 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); auto mn = mnList.GetMN(ptx.proTxHash); if (!mn) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash"); } // don't allow updating to addresses already used by other MNs if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->proTxHash != ptx.proTxHash) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-addr"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-addr"); } // don't allow updating to platformNodeIds already used by other HPMNs if (ptx.nType == MnType::HighPerformance) { if (mnList.HasUniqueProperty(ptx.platformNodeID) && mnList.GetUniquePropertyMN(ptx.platformNodeID)->proTxHash != ptx.proTxHash) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-platformnodeid"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-platformnodeid"); } } if (ptx.scriptOperatorPayout != CScript()) { if (mn->nOperatorReward == 0) { // don't allow setting operator reward payee in case no operatorReward was set - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-operator-payee"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-operator-payee"); } if (!ptx.scriptOperatorPayout.IsPayToPublicKeyHash() && !ptx.scriptOperatorPayout.IsPayToScriptHash()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-operator-payee"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-operator-payee"); } } // we can only check the signature if pindexPrev != nullptr and the MN is known if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); } if (check_sigs && !CheckHashSig(ptx, mn->pdmnState->pubKeyOperator.Get(), state)) { // pass the state returned by the function above @@ -1631,66 +1631,66 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) { if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type"); } CProUpRegTx ptx; if (!GetTxPayload(tx, ptx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); } if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); } CTxDestination payoutDest; if (!ExtractDestination(ptx.scriptPayout, payoutDest)) { // should not happen as we checked script types before - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-payee-dest"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-payee-dest"); } if (pindexPrev) { auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); auto dmn = mnList.GetMN(ptx.proTxHash); if (!dmn) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash"); } // don't allow reuse of payee key for other keys (don't allow people to put the payee key onto an online server) if (payoutDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || payoutDest == CTxDestination(PKHash(ptx.keyIDVoting))) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-payee-reuse"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-payee-reuse"); } Coin coin; if (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent()) { // this should never happen (there would be no dmn otherwise) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-collateral"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-collateral"); } // don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server) CTxDestination collateralTxDest; if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-collateral-dest"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-collateral-dest"); } if (collateralTxDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-collateral-reuse"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-reuse"); } if (mnList.HasUniqueProperty(ptx.pubKeyOperator)) { auto otherDmn = mnList.GetUniquePropertyMN(ptx.pubKeyOperator); if (ptx.proTxHash != otherDmn->proTxHash) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_DUPLICATE, "bad-protx-dup-key"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-key"); } } if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) { if (dmn->pdmnState->keyIDOwner != ptx.keyIDVoting) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-protx-key-not-same"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-key-not-same"); } } if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); } if (check_sigs && !CheckHashSig(ptx, PKHash(dmn->pdmnState->keyIDOwner), state)) { // pass the state returned by the function above @@ -1704,26 +1704,26 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs) { if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-type"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type"); } CProUpRevTx ptx; if (!GetTxPayload(tx, ptx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); } if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); } if (pindexPrev) { auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); auto dmn = mnList.GetMN(ptx.proTxHash); if (!dmn) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash"); if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); } if (check_sigs && !CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator.Get(), state)) { // pass the state returned by the function above diff --git a/src/evo/mnhftx.cpp b/src/evo/mnhftx.cpp index 81b9310167..e12ce03861 100644 --- a/src/evo/mnhftx.cpp +++ b/src/evo/mnhftx.cpp @@ -38,29 +38,29 @@ bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidat { MNHFTxPayload mnhfTx; if (!GetTxPayload(tx, mnhfTx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-payload"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-payload"); } if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-version"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-version"); } const CBlockIndex* pindexQuorum = g_chainman.m_blockman.LookupBlockIndex(mnhfTx.signal.quorumHash); if (!pindexQuorum) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-quorum-hash"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-quorum-hash"); } if (pindexQuorum != pindexPrev->GetAncestor(pindexQuorum->nHeight)) { // not part of active chain - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-quorum-hash"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-quorum-hash"); } if (!llmq::GetLLMQParams(Params().GetConsensus().llmqTypeMnhf).has_value()) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-type"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-type"); } if (!mnhfTx.signal.Verify(pindexQuorum)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-invalid"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-invalid"); } return true; diff --git a/src/evo/specialtxman.cpp b/src/evo/specialtxman.cpp index 54dd69e63c..0c2083d3f9 100644 --- a/src/evo/specialtxman.cpp +++ b/src/evo/specialtxman.cpp @@ -24,7 +24,7 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali return true; if (pindexPrev && pindexPrev->nHeight + 1 < Params().GetConsensus().DIP0003Height) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-tx-type"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-tx-type"); } try { @@ -46,10 +46,10 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali } } catch (const std::exception& e) { LogPrintf("%s -- failed: %s\n", __func__, e.what()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-check-special-tx"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-check-special-tx"); } - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, REJECT_INVALID, "bad-tx-type-check"); + return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-tx-type-check"); } bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValidationState& state) @@ -72,7 +72,7 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida return true; // handled per block } - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-tx-type-proc"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-tx-type-proc"); } bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex) @@ -154,7 +154,7 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, ll LogPrint(BCLog::BENCHMARK, " - CheckCbTxMerkleRoots: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeMerkle * 0.000001); } catch (const std::exception& e) { LogPrintf("%s -- failed: %s\n", __func__, e.what()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-procspectxsinblock"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-procspectxsinblock"); } return true; diff --git a/src/llmq/blockprocessor.cpp b/src/llmq/blockprocessor.cpp index 9e57b7979b..86782e14e4 100644 --- a/src/llmq/blockprocessor.cpp +++ b/src/llmq/blockprocessor.cpp @@ -172,11 +172,11 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex* const auto numCommitmentsInNewBlock = qcs.count(params.type); if (numCommitmentsRequired < numCommitmentsInNewBlock) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-not-allowed"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-not-allowed"); } if (numCommitmentsRequired > numCommitmentsInNewBlock) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-missing"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-missing"); } if (llmq::utils::IsQuorumRotationEnabled(params, pindex)) { LogPrintf("[ProcessBlock] h[%d] numCommitmentsRequired[%d] numCommitmentsInNewBlock[%d]\n", pindex->nHeight, numCommitmentsRequired, numCommitmentsInNewBlock); @@ -234,31 +234,31 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH if (quorumHash.IsNull()) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s quorumHash is null.\n", __func__, nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-block"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-block"); } if (quorumHash != qc.quorumHash) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, qc.quorumHash=%s signers=%s, validMembers=%d, quorumPublicKey=%s non equal quorumHash.\n", __func__, nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-block"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-block"); } if (qc.IsNull()) { if (!qc.VerifyNull()) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%dqc verifynull failed.\n", __func__, nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid-null"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid-null"); } return true; } if (HasMinedCommitment(llmq_params.type, quorumHash)) { // should not happen as it's already handled in ProcessBlock - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-dup"); } if (!IsMiningPhase(llmq_params, nHeight)) { // should not happen as it's already handled in ProcessBlock - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-height"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-height"); } const auto* pQuorumBaseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(qc.quorumHash); @@ -266,7 +266,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH if (!qc.Verify(pQuorumBaseBlockIndex, fBLSChecks)) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s qc verify failed.\n", __func__, nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid"); } if (fJustCheck) { @@ -421,19 +421,19 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C if (!GetTxPayload(*tx, qc)) { // should not happen as it was verified before processing the block LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d GetTxPayload fails\n", __func__, pindex->nHeight); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload"); } const auto& llmq_params_opt = GetLLMQParams(qc.commitment.llmqType); if (!llmq_params_opt.has_value()) { // should not happen as it was verified before processing the block - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type"); } // only allow one commitment per type and per block (This was changed with rotation) if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) { if (ret.count(qc.commitment.llmqType) != 0) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-dup"); } } @@ -442,7 +442,7 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C } if (pindex->nHeight < consensus.DIP0003Height && !ret.empty()) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-premature"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-premature"); } return true; diff --git a/src/llmq/commitment.cpp b/src/llmq/commitment.cpp index 7d4718b024..730d1814ea 100644 --- a/src/llmq/commitment.cpp +++ b/src/llmq/commitment.cpp @@ -181,13 +181,13 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, CFinalCommitmentTxPayload qcTx; if (!GetTxPayload(tx, qcTx)) { LogPrintfFinalCommitment("h[%d] GetTxPayload failed\n", pindexPrev->nHeight); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload"); } const auto& llmq_params_opt = GetLLMQParams(qcTx.commitment.llmqType); if (!llmq_params_opt.has_value()) { LogPrintfFinalCommitment("h[%d] GetLLMQParams failed for llmqType[%d]\n", pindexPrev->nHeight, ToUnderlying(qcTx.commitment.llmqType)); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type"); } if (LogAcceptCategory(BCLog::LLMQ)) { @@ -201,36 +201,36 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, if (qcTx.nVersion == 0 || qcTx.nVersion > CFinalCommitmentTxPayload::CURRENT_VERSION) { LogPrintfFinalCommitment("h[%d] invalid qcTx.nVersion[%d]\n", pindexPrev->nHeight, qcTx.nVersion); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-version"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-version"); } if (qcTx.nHeight != uint32_t(pindexPrev->nHeight + 1)) { LogPrintfFinalCommitment("h[%d] invalid qcTx.nHeight[%d]\n", pindexPrev->nHeight, qcTx.nHeight); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-height"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-height"); } const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash)); if (pQuorumBaseBlockIndex == nullptr) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-quorum-hash"); } if (pQuorumBaseBlockIndex != pindexPrev->GetAncestor(pQuorumBaseBlockIndex->nHeight)) { // not part of active chain - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-quorum-hash"); } if (qcTx.commitment.IsNull()) { if (!qcTx.commitment.VerifyNull()) { LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid-null"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid-null"); } return true; } if (!qcTx.commitment.Verify(pQuorumBaseBlockIndex, false)) { LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] Verify failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid"); } LogPrintfFinalCommitment("h[%d] CheckLLMQCommitment VALID\n", pindexPrev->nHeight); diff --git a/src/net_processing.cpp b/src/net_processing.cpp index e5dd27c204..152bd572e4 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -173,8 +173,8 @@ namespace { int nSyncStarted GUARDED_BY(cs_main) = 0; /** - * Sources of received blocks, saved to be able to send them reject - * messages or ban them when processing happens afterwards. + * Sources of received blocks, saved to be able punish them when processing + * happens afterwards. * Set mapBlockSource[hash].second to false if the node should not be * punished if the block is invalid. */ @@ -1513,11 +1513,12 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta const uint256 hash(block.GetHash()); std::map >::iterator it = mapBlockSource.find(hash); - if (state.IsInvalid()) { - // Don't send reject message with code 0 or an internal reject code. - if (it != mapBlockSource.end() && State(it->second.first) && state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) { + // If the block failed validation, we know where it came from and we're still connected + // to that peer, maybe punish. + if (state.IsInvalid() && + it != mapBlockSource.end() && + State(it->second.first)) { MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second); - } } // Check that: // 1. The block is valid @@ -2523,25 +2524,6 @@ static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainPar connman.PushMessage(&peer, std::move(msg)); } -std::string RejectCodeToString(const unsigned char code) -{ - if (code == REJECT_MALFORMED) - return "malformed"; - if (code == REJECT_INVALID) - return "invalid"; - if (code == REJECT_OBSOLETE) - return "obsolete"; - if (code == REJECT_DUPLICATE) - return "duplicate"; - if (code == REJECT_NONSTANDARD) - return "nonstandard"; - if (code == REJECT_INSUFFICIENTFEE) - return "insufficientfee"; - if (code == REJECT_CHECKPOINT) - return "checkpoint"; - return ""; -} - std::pair static ValidateDSTX(CTxMemPool& mempool, CCoinJoinBroadcastTx& dstx, uint256 hashTx) { if (!dstx.IsValidStructure()) { @@ -3750,11 +3732,12 @@ void PeerLogicValidation::ProcessMessage( // been run). This is handled below, so just treat this as // though the block was successfully read, and rely on the // handling in ProcessNewBlock to ensure the block index is - // updated, reject messages go out, etc. + // updated, etc. MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer fBlockRead = true; - // mapBlockSource is only used for sending reject messages and DoS scores, - // so the race between here and cs_main in ProcessNewBlock is fine. + // mapBlockSource is used for potentially punishing peers and + // updating which peers send us compact blocks, so the race + // between here and cs_main in ProcessNewBlock is fine. // BIP 152 permits peers to relay compact blocks after validating // the header only; we should not punish peers if the block turns // out to be invalid. @@ -3835,8 +3818,9 @@ void PeerLogicValidation::ProcessMessage( // Also always process if we requested the block explicitly, as we may // need it even though it is not a candidate for a new best tip. forceProcessing |= MarkBlockAsReceived(hash); - // mapBlockSource is only used for sending reject messages and DoS scores, - // so the race between here and cs_main in ProcessNewBlock is fine. + // mapBlockSource is only used for punishing peers and setting + // which peers send us compact blocks, so the race between here and + // cs_main in ProcessNewBlock is fine. mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true)); } bool fNewBlock = false; diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index cd1891138c..0392695503 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -929,7 +929,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) result_0.pushKV("allowed", test_accept_res); if (!test_accept_res) { if (state.IsInvalid()) { - result_0.pushKV("reject-reason", strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); + result_0.pushKV("reject-reason", strprintf("%s", state.GetRejectReason())); } else if (missing_inputs) { result_0.pushKV("reject-reason", "missing-inputs"); } else { diff --git a/src/test/specialtx_tests.cpp b/src/test/specialtx_tests.cpp index fc325122f6..773d1a47cd 100644 --- a/src/test/specialtx_tests.cpp +++ b/src/test/specialtx_tests.cpp @@ -22,11 +22,11 @@ bool VerifyMNHFTx(const CTransaction& tx, CValidationState& state) { MNHFTxPayload mnhfTx; if (!GetTxPayload(tx, mnhfTx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-payload"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-payload"); } if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-version"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-version"); } return true; diff --git a/src/util/validation.cpp b/src/util/validation.cpp index e2050b1077..0992ca658f 100644 --- a/src/util/validation.cpp +++ b/src/util/validation.cpp @@ -11,8 +11,7 @@ /** Convert CValidationState to a human-readable message for logging */ std::string FormatStateMessage(const CValidationState &state) { - return strprintf("%s%s (code %i)", + return strprintf("%s%s", state.GetRejectReason(), - state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(), - state.GetRejectCode()); + state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage()); } diff --git a/src/validation.cpp b/src/validation.cpp index d7c0bb06d9..79c555efd0 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -379,18 +379,18 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, tx.nType != TRANSACTION_COINBASE && tx.nType != TRANSACTION_QUORUM_COMMITMENT && tx.nType != TRANSACTION_MNHF_SIGNAL) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-type"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-type"); } if (tx.IsCoinBase() && tx.nType != TRANSACTION_COINBASE) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-cb-type"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-cb-type"); } else if (tx.nType != TRANSACTION_NORMAL) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-type"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-type"); } } // Size limits if (fDIP0001Active_context && ::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_STANDARD_TX_SIZE) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-oversize"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-oversize"); return true; } @@ -597,11 +597,11 @@ private: { CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size); if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) { - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee)); + return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee)); } if (package_fee < ::minRelayTxFee.GetFee(package_size)) { - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size))); + return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size))); } return true; } @@ -655,35 +655,35 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) if (tx.nVersion == 3 && tx.nType == TRANSACTION_QUORUM_COMMITMENT) { // quorum commitment is not allowed outside of blocks - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "qc-not-allowed"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "qc-not-allowed"); } // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "coinbase"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "coinbase"); // Rather not work on nonstandard transactions (unless -testnet/-regtest) std::string reason; if (fRequireStandard && !IsStandardTx(tx, reason)) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, reason); + return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, reason); // Do not work on transactions that are too small. // A transaction with 1 empty scriptSig input and 1 P2SH output has size of 83 bytes. // Transactions smaller than this are not relayed to mitigate CVE-2017-12842 by not relaying // 64-byte transactions. if (::GetSerializeSize(tx, PROTOCOL_VERSION) < MIN_STANDARD_TX_SIZE) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "tx-size-small"); + return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "tx-size-small"); // Only accept nLockTime-using transactions that can be mined in the next // block; we don't want our mempool filled up with transactions that can't // be mined yet. if (!CheckFinalTx(m_active_chainstate.m_chain.Tip(), tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) - return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-final"); + return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "non-final"); // is it already in the memory pool? if (m_pool.exists(hash)) { statsClient.inc("transactions.duplicate", 1.0f); - return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-in-mempool"); + return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-already-in-mempool"); } llmq::CInstantSendLockPtr conflictLock = llmq::quorumInstantSendManager->GetConflictingLock(tx); @@ -693,7 +693,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) if (txConflict) { GetMainSignals().NotifyInstantSendDoubleSpendAttempt(ptx, txConflict); } - return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("AcceptToMemoryPool : Transaction %s conflicts with locked TX %s", hash.ToString(), conflictLock->txid.ToString()), REJECT_INVALID, "tx-txlock-conflict"); + return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("AcceptToMemoryPool : Transaction %s conflicts with locked TX %s", hash.ToString(), conflictLock->txid.ToString()), "tx-txlock-conflict"); } if (llmq::quorumInstantSendManager->IsWaitingForTx(hash)) { @@ -707,7 +707,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) if (ptxConflicting) { // Transaction conflicts with mempool and RBF doesn't exist in Dash - return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-mempool-conflict"); + return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-mempool-conflict"); } } } @@ -731,7 +731,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) for (size_t out = 0; out < tx.vout.size(); out++) { // Optimistically just do efficient check of cache for outputs if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) { - return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-known"); + return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-already-known"); } } // Otherwise assume this might be an orphan tx for which we just haven't seen parents yet @@ -757,7 +757,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // CoinsViewCache instead of create its own assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate)); if (!CheckSequenceLocks(m_active_chainstate, m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) - return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-BIP68-final"); + return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "non-BIP68-final"); assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_active_chainstate.m_blockman)); CAmount nFees = 0; @@ -767,7 +767,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // Check for non-standard pay-to-script-hash in inputs if (fRequireStandard && !AreInputsStandard(tx, m_view)) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs"); + return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "bad-txns-nonstandard-inputs"); unsigned int nSigOps = GetTransactionSigOpCount(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS); @@ -792,7 +792,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) unsigned int nSize = entry->GetTxSize(); if (nSigOps > MAX_STANDARD_TX_SIGOPS) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", + return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "bad-txns-too-many-sigops", strprintf("%d", nSigOps)); // No transactions are allowed below minRelayTxFee except from disconnected @@ -801,8 +801,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) if (nAbsurdFee && nFees > nAbsurdFee) return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, - REJECT_HIGHFEE, "absurdly-high-fee", - strprintf("%d > %d", nFees, nAbsurdFee)); + "absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee)); // Calculate in-mempool ancestors, up to a limit. std::string errString; @@ -822,7 +821,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || !m_pool.CalculateMemPoolAncestors(*entry, setAncestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) { - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too-long-mempool-chain", errString); + return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "too-long-mempool-chain", errString); } } @@ -834,7 +833,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) return false; if (m_pool.existsProviderTxConflict(tx)) { - return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "protx-dup"); + return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "protx-dup"); } return true; @@ -935,7 +934,7 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws) assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(m_active_chainstate.CoinsTip())); LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip(), gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); if (!m_pool.exists(hash)) - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool full"); + return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "mempool full"); } return true; } @@ -1593,7 +1592,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi CScriptCheck check2(coin.out, tx, i, (flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS) | SCRIPT_ENABLE_DIP0020_OPCODES, cacheSigStore, &txdata); if (check2()) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); + return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); } // MANDATORY flag failures correspond to // ValidationInvalidReason::CONSENSUS. Because CONSENSUS @@ -1604,7 +1603,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // support, to avoid splitting the network (but this // depends on the details of how net_processing handles // such errors). - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); } } @@ -2126,7 +2125,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl } if (pindex->pprev && pindex->phashBlock && m_clhandler->HasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) { - return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: conflicting with chainlock", __func__), REJECT_INVALID, "bad-chainlock"); + return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: conflicting with chainlock", __func__), "bad-chainlock"); } // verify that the view's current state corresponds to the previous block @@ -2214,7 +2213,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl for (const auto& tx : block.vtx) { for (size_t o = 0; o < tx->vout.size(); o++) { if (view.HaveCoin(COutPoint(tx->GetHash(), o))) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"), REJECT_INVALID, "bad-txns-BIP30"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"), "bad-txns-BIP30"); } } } @@ -2226,7 +2225,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl if (pindex->nHeight == chainparams.GetConsensus().nSuperblockStartBlock && chainparams.GetConsensus().nSuperblockStartHash != uint256() && block_hash != chainparams.GetConsensus().nSuperblockStartHash) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): invalid superblock start"), REJECT_INVALID, "bad-sb-start"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): invalid superblock start"), "bad-sb-start"); } /// END DASH @@ -2289,13 +2288,14 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl // defined for a block, so we reset the reason flag to // CONSENSUS here. state.Invalid(ValidationInvalidReason::CONSENSUS, false, - state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage()); + state.GetRejectReason(), state.GetDebugMessage()); } return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state)); } nFees += txfee; if (!MoneyRange(nFees)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: accumulated fee in the block out of range.", __func__), REJECT_INVALID, "bad-txns-accumulated-fee-outofrange"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: accumulated fee in the block out of range.", __func__), + "bad-txns-accumulated-fee-outofrange"); } // Check that transaction is BIP68 final @@ -2307,7 +2307,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl } if (!SequenceLocks(tx, nLockTimeFlags, prevheights, *pindex)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: contains a non-BIP68-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: contains a non-BIP68-final transaction", __func__), + "bad-txns-nonfinal"); } if (fAddressIndex || fSpentIndex) @@ -2357,7 +2358,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl // * p2sh (when P2SH enabled in flags and excludes coinbase) nSigOps += GetTransactionSigOpCount(tx, view, flags); if (nSigOps > MaxBlockSigOps(fDIP0001Active_context)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): too many sigops"), + "bad-blk-sigops"); } if (!tx.IsCoinBase()) @@ -2374,7 +2376,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl // consider whether rewriting to CONSENSUS or // RECENT_CONSENSUS_CHANGE would be more appropriate. state.Invalid(ValidationInvalidReason::CONSENSUS, false, - state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage()); + state.GetRejectReason(), state.GetDebugMessage()); } return error("ConnectBlock(): CheckInputs on %s failed with %s", tx.GetHash().ToString(), FormatStateMessage(state)); @@ -2425,7 +2427,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl LogPrint(BCLog::BENCHMARK, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal); if (!control.Wait()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: CheckQueue failed", __func__), "block-validation-failed"); int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; LogPrint(BCLog::BENCHMARK, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal); @@ -2453,7 +2455,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl } else { // The node which relayed this should switch to correct chain. // TODO: relay instantsend data/proof. - return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("ConnectBlock(DASH): transaction %s conflicts with transaction lock %s", tx->GetHash().ToString(), conflictLock->txid.ToString()), REJECT_INVALID, "conflict-tx-lock"); + return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("ConnectBlock(DASH): transaction %s conflicts with transaction lock %s", tx->GetHash().ToString(), conflictLock->txid.ToString()), "conflict-tx-lock"); } } } @@ -2473,7 +2475,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl if (!IsBlockValueValid(*sporkManager, *governance, *::masternodeSync, block, pindex->nHeight, blockReward, strError)) { // NOTE: Do not punish, the node might be missing governance data - return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): %s", strError), REJECT_INVALID, "bad-cb-amount"); + return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): %s", strError), "bad-cb-amount"); } int64_t nTime5_3 = GetTimeMicros(); nTimeValueValid += nTime5_3 - nTime5_2; @@ -2481,7 +2483,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl if (!IsBlockPayeeValid(*sporkManager, *governance, *block.vtx[0], pindex->nHeight, blockReward)) { // NOTE: Do not punish, the node might be missing governance data - return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): couldn't find masternode or superblock payments"), REJECT_INVALID, "bad-cb-payee"); + return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): couldn't find masternode or superblock payments"), "bad-cb-payee"); } int64_t nTime5_4 = GetTimeMicros(); nTimePayeeValid += nTime5_4 - nTime5_3; @@ -3806,13 +3808,13 @@ static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, { // Check proof of work matches claimed amount if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "high-hash", "proof of work failed"); + return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "high-hash", "proof of work failed"); // Check DevNet if (!consensusParams.hashDevnetGenesisBlock.IsNull() && block.hashPrevBlock == consensusParams.hashGenesisBlock && block.GetHash() != consensusParams.hashDevnetGenesisBlock) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("CheckBlockHeader(): wrong devnet genesis"), REJECT_INVALID, "devnet-genesis"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, error("CheckBlockHeader(): wrong devnet genesis"), "devnet-genesis"); } return true; @@ -3837,13 +3839,13 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P bool mutated; uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated); if (block.hashMerkleRoot != hashMerkleRoot2) - return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "bad-txnmrklroot", "hashMerkleRoot mismatch"); + return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "bad-txnmrklroot", "hashMerkleRoot mismatch"); // Check for merkle tree malleability (CVE-2012-2459): repeating sequences // of transactions in a block without affecting the merkle root of a block, // while still invalidating it. if (mutated) - return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "bad-txns-duplicate", "duplicate transaction"); + return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "bad-txns-duplicate", "duplicate transaction"); } // All potential-corruption validation must be done before we do any @@ -3852,19 +3854,19 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P // Size limits (relaxed) if (block.vtx.empty() || block.vtx.size() > MaxBlockSize() || ::GetSerializeSize(block, PROTOCOL_VERSION) > MaxBlockSize()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-length", "size limits failed"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-length", "size limits failed"); // First transaction must be coinbase, the rest must not be if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-missing", "first tx is not coinbase"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-missing", "first tx is not coinbase"); for (unsigned int i = 1; i < block.vtx.size(); i++) if (block.vtx[i]->IsCoinBase()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-multiple", "more than one coinbase"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-multiple", "more than one coinbase"); // Check transactions for (const auto& tx : block.vtx) if (!CheckTransaction(*tx, state)) - return state.Invalid(state.GetReason(), false, state.GetRejectCode(), state.GetRejectReason(), + return state.Invalid(state.GetReason(), false, state.GetRejectReason(), strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage())); unsigned int nSigOps = 0; @@ -3874,7 +3876,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P } // sigops limits (relaxed) if (nSigOps > MaxBlockSigOps()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-sigops", "out-of-bounds SigOpCount"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-sigops", "out-of-bounds SigOpCount"); if (fCheckPOW && fCheckMerkleRoot) block.fChecked = true; @@ -3926,10 +3928,10 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta if (abs(n1-n2) > n1*0.5) return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, error("%s : incorrect proof of work (DGW pre-fork) - %f %f %f at %d", __func__, abs(n1-n2), n1, n2, nHeight), - REJECT_INVALID, "bad-diffbits"); + "bad-diffbits"); } else { if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "bad-diffbits", strprintf("incorrect proof of work at %d", nHeight)); + return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "bad-diffbits", strprintf("incorrect proof of work at %d", nHeight)); } // Check against checkpoints @@ -3940,22 +3942,23 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman)); CBlockIndex* pcheckpoint = blockman.GetLastCheckpoint(params.Checkpoints()); if (pcheckpoint && nHeight < pcheckpoint->nHeight) - return state.Invalid(ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint"); + return state.Invalid(ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), "bad-fork-prior-to-checkpoint"); } // Check timestamp against prev if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "time-too-old", strprintf("block's timestamp is too early %d %d", block.GetBlockTime(), pindexPrev->GetMedianTimePast())); + return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "time-too-old", strprintf("block's timestamp is too early %d %d", block.GetBlockTime(), pindexPrev->GetMedianTimePast())); // Check timestamp if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME) - return state.Invalid(ValidationInvalidReason::BLOCK_TIME_FUTURE, false, REJECT_INVALID, "time-too-new", strprintf("block timestamp too far in the future %d %d", block.GetBlockTime(), nAdjustedTime + 2 * 60 * 60)); + return state.Invalid(ValidationInvalidReason::BLOCK_TIME_FUTURE, false, "time-too-new", strprintf("block timestamp too far in the future %d %d", block.GetBlockTime(), nAdjustedTime + 2 * 60 * 60)); // check for version 2, 3 and 4 upgrades if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) || (block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) || (block.nVersion < 4 && nHeight >= consensusParams.BIP65Height)) - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", block.nVersion), strprintf("rejected nVersion=0x%08x block", block.nVersion)); + return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, strprintf("bad-version(0x%08x)", block.nVersion), + strprintf("rejected nVersion=0x%08x block", block.nVersion)); return true; } @@ -3988,14 +3991,14 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c // Size limits unsigned int nMaxBlockSize = MaxBlockSize(fDIP0001Active_context); if (block.vtx.empty() || block.vtx.size() > nMaxBlockSize || ::GetSerializeSize(block, PROTOCOL_VERSION) > nMaxBlockSize) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-length", "size limits failed"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-length", "size limits failed"); // Check that all transactions are finalized and not over-sized // Also count sigops unsigned int nSigOps = 0; for (const auto& tx : block.vtx) { if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-nonfinal", "non-final transaction"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-nonfinal", "non-final transaction"); } if (!ContextualCheckTransaction(*tx, state, consensusParams, pindexPrev)) { return false; @@ -4005,7 +4008,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c // Check sigops if (nSigOps > MaxBlockSigOps(fDIP0001Active_context)) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-sigops", "out-of-bounds SigOpCount"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-sigops", "out-of-bounds SigOpCount"); // Enforce rule that the coinbase starts with serialized block height // After DIP3/DIP4 activation, we don't enforce the height in the input script anymore. @@ -4015,13 +4018,13 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c CScript expect = CScript() << nHeight; if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() || !std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-height", "block height mismatch in coinbase"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-height", "block height mismatch in coinbase"); } } if (fDIP0003Active_context) { if (block.vtx[0]->nType != TRANSACTION_COINBASE) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-type", "coinbase is not a CbTx"); + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-type", "coinbase is not a CbTx"); } } @@ -4044,9 +4047,9 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState if (ppindex) *ppindex = pindex; if (pindex->nStatus & BLOCK_FAILED_MASK) - return state.Invalid(ValidationInvalidReason::CACHED_INVALID, error("%s: block %s is marked invalid", __func__, hash.ToString()), 0, "duplicate"); + return state.Invalid(ValidationInvalidReason::CACHED_INVALID, error("%s: block %s is marked invalid", __func__, hash.ToString()), "duplicate"); if (pindex->nStatus & BLOCK_CONFLICT_CHAINLOCK) - return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: block %s is marked conflicting", __func__, hash.ToString()), 0, "duplicate"); + return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: block %s is marked conflicting", __func__, hash.ToString()), "duplicate"); return true; } @@ -4057,16 +4060,16 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState CBlockIndex* pindexPrev = nullptr; BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock); if (mi == m_block_index.end()) - return state.Invalid(ValidationInvalidReason::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), 0, "prev-blk-not-found"); + return state.Invalid(ValidationInvalidReason::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), "prev-blk-not-found"); pindexPrev = (*mi).second; assert(pindexPrev); if (pindexPrev->nStatus & BLOCK_FAILED_MASK) - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); + return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk"); if (pindexPrev->nStatus & BLOCK_CONFLICT_CHAINLOCK) // it's ok-ish, the other node is probably missing the latest chainlock - return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: prev block %s conflicts with chainlock", __func__, block.hashPrevBlock.ToString()), REJECT_INVALID, "bad-prevblk-chainlock"); + return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: prev block %s conflicts with chainlock", __func__, block.hashPrevBlock.ToString()), "bad-prevblk-chainlock"); if (!ContextualCheckBlockHeader(block, state, *this, chainparams, pindexPrev, GetAdjustedTime())) return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); @@ -4104,7 +4107,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState setDirtyBlockIndex.insert(invalid_walk); invalid_walk = invalid_walk->pprev; } - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); + return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk"); } } } @@ -4113,7 +4116,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState if (pindex == nullptr) { AddToBlockIndex(block, BLOCK_CONFLICT_CHAINLOCK); } - return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: header %s conflicts with chainlock", __func__, hash.ToString()), REJECT_INVALID, "bad-chainlock"); + return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: header %s conflicts with chainlock", __func__, hash.ToString()), "bad-chainlock"); } } if (pindex == nullptr) @@ -4324,7 +4327,7 @@ bool TestBlockValidity(CValidationState& state, uint256 hash = block.GetHash(); if (clhandler.HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) { - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: conflicting with chainlock", __func__), REJECT_INVALID, "bad-chainlock"); + return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: conflicting with chainlock", __func__), "bad-chainlock"); } CCoinsViewCache viewNew(&chainstate.CoinsTip()); diff --git a/src/validation.h b/src/validation.h index db9fba1f52..f2028d7a41 100644 --- a/src/validation.h +++ b/src/validation.h @@ -1031,14 +1031,6 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para */ bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1); -/** Reject codes greater or equal to this can be returned by AcceptToMemPool - * for transactions, to signal internal conditions. They cannot and should not - * be sent over the P2P network. - */ -static const unsigned int REJECT_INTERNAL = 0x100; -/** Too high fee. Can not be triggered by P2P transactions */ -static const unsigned int REJECT_HIGHFEE = 0x100; - /** Get block file info entry for one block file */ CBlockFileInfo* GetBlockFileInfo(size_t n); diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py index dcb6168488..faf5843b2d 100755 --- a/test/functional/feature_bip68_sequence.py +++ b/test/functional/feature_bip68_sequence.py @@ -22,7 +22,7 @@ SEQUENCE_LOCKTIME_GRANULARITY = 9 # this is a bit-shift SEQUENCE_LOCKTIME_MASK = 0x0000ffff # RPC error for non-BIP68 final transactions -NOT_FINAL_ERROR = "non-BIP68-final (code 64)" +NOT_FINAL_ERROR = "non-BIP68-final" class BIP68Test(BitcoinTestFramework): def set_test_params(self): diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index 6e5e16e673..28ec088df3 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -130,7 +130,7 @@ class BIP65Test(BitcoinTestFramework): # First we show that this tx is valid except for CLTV by getting it # rejected from the mempool for exactly that reason. - assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Negative locktime) (code 64)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0) + assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Negative locktime)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0) # Now we verify that a block with this transaction is also invalid. block.vtx.append(spendtx) diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index e09219f245..ab3d6635ae 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -112,7 +112,7 @@ class BIP66Test(BitcoinTestFramework): # First we show that this tx is valid except for DERSIG by getting it # rejected from the mempool for exactly that reason. - assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Non-canonical DER signature) (code 64)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0) + assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Non-canonical DER signature)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0) # Now we verify that a block with this transaction is also invalid. block.vtx.append(spendtx) diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py index 52cd431247..653a21f070 100755 --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -20,7 +20,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error -NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero) (code 64)" +NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)" def trueDummy(tx): scriptSig = CScript(tx.vin[0].scriptSig) diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index 74d819c8e3..8f3a34dd28 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -77,7 +77,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): node.generate(1) self.mempool_size = 0 self.check_mempool_result( - result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': '18: txn-already-known'}], + result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': 'txn-already-known'}], rawtxs=[raw_tx_in_block], ) @@ -115,7 +115,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): node.sendrawtransaction(hexstring=raw_tx_0) self.mempool_size += 1 self.check_mempool_result( - result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': '18: txn-already-in-mempool'}], + result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': 'txn-already-in-mempool'}], rawtxs=[raw_tx_0], ) @@ -128,7 +128,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): txid_0_reject = tx.rehash() self.check_mempool_result( # No RBF in DASH - result_expected=[{'txid': txid_0_reject, 'allowed': False, 'reject-reason': '18: txn-mempool-conflict'}], + result_expected=[{'txid': txid_0_reject, 'allowed': False, 'reject-reason': 'txn-mempool-conflict'}], rawtxs=[raw_tx_0_reject], ) @@ -140,7 +140,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): tx.vout[0].nValue -= int(4 * fee * COIN) # Set more fee # skip re-signing the tx self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '18: txn-mempool-conflict'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'txn-mempool-conflict'}], rawtxs=[tx.serialize().hex()], maxfeerate=0, ) @@ -199,7 +199,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): # Skip re-signing the transaction for context independent checks from now on # tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(tx.serialize().hex())['hex']))) self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-empty'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-empty'}], rawtxs=[tx.serialize().hex()], ) @@ -207,7 +207,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_SIZE / len(tx.vin[0].serialize())) self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-oversize'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-oversize'}], rawtxs=[tx.serialize().hex()], ) @@ -215,7 +215,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.vout[0].nValue *= -1 self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-negative'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-negative'}], rawtxs=[tx.serialize().hex()], ) @@ -224,7 +224,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.vout[0].nValue = MAX_MONEY + 1 self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-toolarge'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-toolarge'}], rawtxs=[tx.serialize().hex()], ) @@ -233,7 +233,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): tx.vout = [tx.vout[0]] * 2 tx.vout[0].nValue = MAX_MONEY self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-txouttotal-toolarge'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-txouttotal-toolarge'}], rawtxs=[tx.serialize().hex()], ) @@ -241,7 +241,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.vin = [tx.vin[0]] * 2 self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-inputs-duplicate'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-inputs-duplicate'}], rawtxs=[tx.serialize().hex()], ) @@ -250,7 +250,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid']) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent))) self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: coinbase'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'coinbase'}], rawtxs=[tx.serialize().hex()], ) @@ -258,13 +258,13 @@ class MempoolAcceptanceTest(BitcoinTestFramework): tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.nVersion = 4 # A version currently non-standard self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: version'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'version'}], rawtxs=[tx.serialize().hex()], ) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.vout[0].scriptPubKey = CScript([OP_0]) # Some non-standard script self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptpubkey'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptpubkey'}], rawtxs=[tx.serialize().hex()], ) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) @@ -273,25 +273,25 @@ class MempoolAcceptanceTest(BitcoinTestFramework): pubkey = key.get_pubkey().get_bytes() tx.vout[0].scriptPubKey = CScript([OP_2, pubkey, pubkey, pubkey, OP_3, OP_CHECKMULTISIG]) # Some bare multisig script (2-of-3) self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: bare-multisig'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bare-multisig'}], rawtxs=[tx.serialize().hex()], ) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.vin[0].scriptSig = CScript([OP_HASH160]) # Some not-pushonly scriptSig self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-not-pushonly'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-not-pushonly'}], rawtxs=[tx.serialize().hex()], ) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes) self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-size'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-size'}], rawtxs=[tx.serialize().hex()], ) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes) self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-size'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-size'}], rawtxs=[tx.serialize().hex()], ) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) @@ -299,21 +299,21 @@ class MempoolAcceptanceTest(BitcoinTestFramework): num_scripts = 100000 // len(output_p2sh_burn.serialize()) # Use enough outputs to make the tx too large for our policy tx.vout = [output_p2sh_burn] * num_scripts self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: tx-size'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'tx-size'}], rawtxs=[tx.serialize().hex()], ) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.vout[0] = output_p2sh_burn tx.vout[0].nValue -= 1 # Make output smaller, such that it is dust for our policy self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: dust'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'dust'}], rawtxs=[tx.serialize().hex()], ) tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff']) tx.vout = [tx.vout[0]] * 2 self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: multi-op-return'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'multi-op-return'}], rawtxs=[tx.serialize().hex()], ) @@ -322,7 +322,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): tx.vin[0].nSequence -= 1 # Should be non-max, so locktime is not ignored tx.nLockTime = node.getblockcount() + 1 self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-final'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-final'}], rawtxs=[tx.serialize().hex()], ) @@ -331,7 +331,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): tx.vin[0].nSequence = 2 # We could include it in the second block mined from now, but not the very next one # Can skip re-signing the tx because of early rejection self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-BIP68-final'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-BIP68-final'}], rawtxs=[tx.serialize().hex()], maxfeerate=0, ) diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index 35c0d94ae7..df59bee924 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -388,7 +388,7 @@ class RawTransactionsTest(BitcoinTestFramework): # Thus, testmempoolaccept should reject testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0] assert_equal(testres['allowed'], False) - assert_equal(testres['reject-reason'], '256: absurdly-high-fee') + assert_equal(testres['reject-reason'], 'absurdly-high-fee') # and sendrawtransaction should throw assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000) # and the following calls should both succeed @@ -412,7 +412,7 @@ class RawTransactionsTest(BitcoinTestFramework): # Thus, testmempoolaccept should reject testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0] assert_equal(testres['allowed'], False) - assert_equal(testres['reject-reason'], '256: absurdly-high-fee') + assert_equal(testres['reject-reason'], 'absurdly-high-fee') # and sendrawtransaction should throw assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex']) # and the following calls should both succeed From eec81f7b33a1d971d34a96f6297092fbc1cfa509 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 30 Oct 2019 15:27:22 +0100 Subject: [PATCH 7/9] Merge #15921: validation: Tidy up ValidationState interface 3004d5a12d09d94bfc4dee2a8e8f2291996a4aaf [validation] Remove fMissingInputs from AcceptToMemoryPool() (John Newbery) c428622a5bb1e37b2e6ab2c52791ac05d9271238 [validation] Remove unused first_invalid parameter from ProcessNewBlockHeaders() (John Newbery) 7204c6434b944f6ad51b3c895837729d3aa56eea [validation] Remove useless ret parameter from Invalid() (John Newbery) 1a37de4b3174d19a6d8691ae07e92b32fdfaef11 [validation] Remove error() calls from Invalid() calls (John Newbery) 067981e49246822421a7bcc720491427e1dba8a3 [validation] Tidy Up ValidationResult class (John Newbery) a27a2957ed9afbe5a96caa5f0f4cbec730d27460 [validation] Add CValidationState subclasses (John Newbery) Pull request description: Carries out some remaining tidy-ups remaining after PR 15141: - split ValidationState into TxValidationState and BlockValidationState (commit from ajtowns) - various minor code style tidy-ups to the ValidationState class - remove the useless `ret` parameter from `ValidationState::Invalid()` - remove the now unused `first_invalid` parameter from `ProcessNewBlockHeaders()` - remove the `fMissingInputs` parameter from `AcceptToMemoryPool()`, and deal with missing inputs the same way as other errors by using the `TxValidationState` object. Tip for reviewers (thanks ryanofsky!): The first commit ("[validation] Add CValidationState subclasses" ) is huge and can be easier to start reviewing if you revert the rote, mechanical changes: Substitute the commit hash of commit "[validation] Add CValidationState subclasses" for in the commands below. ```sh git checkout git grep -l ValidationState | xargs sed -i 's/BlockValidationState\|TxValidationState/CValidationState/g' git grep -l ValidationResult | xargs sed -i 's/BlockValidationResult\|TxValidationResult/ValidationInvalidReason/g' git grep -l MaybePunish | xargs sed -i 's/MaybePunishNode\(ForBlock\|ForTx\)/MaybePunishNode/g' git diff HEAD^ ``` After that it's possible to easily see the mechanical changes with: ```sh git log -p -n1 -U0 --word-diff-regex=. ``` ACKs for top commit: laanwj: ACK 3004d5a12d09d94bfc4dee2a8e8f2291996a4aaf amitiuttarwar: code review ACK 3004d5a12d09d94bfc4dee2a8e8f2291996a4aaf. Also built & ran tests locally. fjahr: Code review ACK 3004d5a12d09d94bfc4dee2a8e8f2291996a4aaf . Only nit style change and pure virtual destructor added since my last review. ryanofsky: Code review ACK 3004d5a12d09d94bfc4dee2a8e8f2291996a4aaf. Just whitespace change and pure virtual destructor added since last review. Tree-SHA512: 511de1fb380a18bec1944ea82b513b6192df632ee08bb16344a2df3c40811a88f3872f04df24bc93a41643c96c48f376a04551840fd804a961490d6c702c3d36 --- src/bench/block_assemble.cpp | 4 +- src/bench/checkblock.cpp | 2 +- src/bench/duplicate_inputs.cpp | 2 +- src/blockencodings.cpp | 4 +- src/coinjoin/coinjoin.cpp | 4 +- src/coinjoin/server.cpp | 8 +- src/consensus/tx_check.cpp | 22 +- src/consensus/tx_check.h | 4 +- src/consensus/tx_verify.cpp | 12 +- src/consensus/tx_verify.h | 4 +- src/consensus/validation.h | 176 ++++---- src/evo/cbtx.cpp | 42 +- src/evo/cbtx.h | 11 +- src/evo/deterministicmns.cpp | 176 ++++---- src/evo/deterministicmns.h | 14 +- src/evo/mnhftx.cpp | 14 +- src/evo/mnhftx.h | 4 +- src/evo/providertx.cpp | 30 +- src/evo/providertx.h | 4 +- src/evo/specialtx.h | 4 +- src/evo/specialtxman.cpp | 33 +- src/evo/specialtxman.h | 7 +- src/init.cpp | 2 +- src/interfaces/chain.h | 1 - src/llmq/blockprocessor.cpp | 34 +- src/llmq/blockprocessor.h | 8 +- src/llmq/chainlocks.cpp | 8 +- src/llmq/commitment.cpp | 18 +- src/llmq/commitment.h | 4 +- src/llmq/instantsend.cpp | 4 +- src/miner.cpp | 4 +- src/net_processing.cpp | 113 +++--- src/net_processing.h | 2 +- src/node/transaction.cpp | 14 +- src/rpc/blockchain.cpp | 6 +- src/rpc/evo.cpp | 2 +- src/rpc/mining.cpp | 14 +- src/rpc/rawtransaction.cpp | 13 +- src/test/blockfilter_index_tests.cpp | 4 +- src/test/evo_deterministicmns_tests.cpp | 12 +- src/test/fuzz/block.cpp | 8 +- src/test/fuzz/coins_view.cpp | 4 +- src/test/fuzz/transaction.cpp | 2 +- src/test/interfaces_tests.cpp | 2 +- src/test/miner_tests.cpp | 2 +- src/test/sighash_tests.cpp | 2 +- src/test/specialtx_tests.cpp | 8 +- src/test/transaction_tests.cpp | 6 +- src/test/txvalidation_tests.cpp | 5 +- src/test/txvalidationcache_tests.cpp | 14 +- src/test/util/setup_common.cpp | 4 +- src/test/validation_block_tests.cpp | 5 +- .../validation_chainstatemanager_tests.cpp | 4 +- src/txmempool.cpp | 4 +- src/util/validation.cpp | 4 +- src/util/validation.h | 6 +- src/validation.cpp | 377 +++++++++--------- src/validation.h | 41 +- src/validationinterface.cpp | 4 +- src/validationinterface.h | 8 +- .../feature_llmq_is_cl_conflicts.py | 2 +- test/functional/rpc_rawtransaction.py | 2 +- 62 files changed, 707 insertions(+), 651 deletions(-) diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp index 1afedc9963..80a390952a 100644 --- a/src/bench/block_assemble.cpp +++ b/src/bench/block_assemble.cpp @@ -40,8 +40,8 @@ static void AssembleBlock(benchmark::Bench& bench) LOCK(::cs_main); // Required for ::AcceptToMemoryPool. for (const auto& txr : txs) { - CValidationState state; - bool ret{::AcceptToMemoryPool(::ChainstateActive(), *test_setup.m_node.mempool, state, txr, nullptr /* pfMissingInputs */, false /* bypass_limits */, /* nAbsurdFee */ 0)}; + TxValidationState state; + bool ret{::AcceptToMemoryPool(::ChainstateActive(), *test_setup.m_node.mempool, state, txr, false /* bypass_limits */, /* nAbsurdFee */ 0)}; assert(ret); } } diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp index 0916fdd68f..b3da4b0e77 100644 --- a/src/bench/checkblock.cpp +++ b/src/bench/checkblock.cpp @@ -42,7 +42,7 @@ static void DeserializeAndCheckBlockTest(benchmark::Bench& bench) bool rewound = stream.Rewind(benchmark::data::block813851.size()); assert(rewound); - CValidationState validationState; + BlockValidationState validationState; bool checked = CheckBlock(block, validationState, chainParams->GetConsensus(), block.GetBlockTime()); assert(checked); }); diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp index 378861b5df..cd80056ee5 100644 --- a/src/bench/duplicate_inputs.cpp +++ b/src/bench/duplicate_inputs.cpp @@ -56,7 +56,7 @@ static void DuplicateInputs(benchmark::Bench& bench) block.hashMerkleRoot = BlockMerkleRoot(block); bench.minEpochIterations(10).run([&] { - CValidationState cvstate{}; + BlockValidationState cvstate{}; assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false)); assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate"); }); diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index 5653685f9e..49ddd3ecc6 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -198,13 +198,13 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector< if (vtx_missing.size() != tx_missing_offset) return READ_STATUS_INVALID; - CValidationState state; + BlockValidationState state; if (!CheckBlock(block, state, Params().GetConsensus())) { // TODO: We really want to just check merkle tree manually here, // but that is expensive, and CheckBlock caches a block's // "checked-status" (in the CBlock?). CBlock should be able to // check its own merkle root and cache that check. - if (state.GetReason() == ValidationInvalidReason::BLOCK_MUTATED) + if (state.GetResult() == BlockValidationResult::BLOCK_MUTATED) return READ_STATUS_FAILED; // Possible Short ID collision return READ_STATUS_CHECKBLOCK_FAILED; } diff --git a/src/coinjoin/coinjoin.cpp b/src/coinjoin/coinjoin.cpp index c18c72d148..f8bedbaa12 100644 --- a/src/coinjoin/coinjoin.cpp +++ b/src/coinjoin/coinjoin.cpp @@ -351,8 +351,8 @@ bool CCoinJoin::IsCollateralValid(CTxMemPool& mempool, const CTransaction& txCol { LOCK(cs_main); - CValidationState validationState; - if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, MakeTransactionRef(txCollateral), /*pfMissingInputs=*/nullptr, /*bypass_limits=*/false, /*nAbsurdFee=*/DEFAULT_MAX_RAW_TX_FEE, /*test_accept=*/true)) { + TxValidationState validationState; + if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, MakeTransactionRef(txCollateral), /*bypass_limits=*/false, /*nAbsurdFee=*/DEFAULT_MAX_RAW_TX_FEE, /*test_accept=*/true)) { LogPrint(BCLog::COINJOIN, "CCoinJoin::IsCollateralValid -- didn't pass AcceptToMemoryPool()\n"); return false; } diff --git a/src/coinjoin/server.cpp b/src/coinjoin/server.cpp index 1ebcc36b35..fac306d959 100644 --- a/src/coinjoin/server.cpp +++ b/src/coinjoin/server.cpp @@ -320,9 +320,9 @@ void CCoinJoinServer::CommitFinalTransaction() { // See if the transaction is valid TRY_LOCK(cs_main, lockMain); - CValidationState validationState; + TxValidationState validationState; mempool.PrioritiseTransaction(hashTx, 0.1 * COIN); - if (!lockMain || !AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, finalTransaction, nullptr /* pfMissingInputs */, false /* bypass_limits */, DEFAULT_MAX_RAW_TX_FEE /* nAbsurdFee */)) { + if (!lockMain || !AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, finalTransaction, false /* bypass_limits */, DEFAULT_MAX_RAW_TX_FEE /* nAbsurdFee */)) { LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n"); WITH_LOCK(cs_coinjoin, SetNull()); // not much we can do in this case, just notify clients @@ -454,8 +454,8 @@ void CCoinJoinServer::ChargeRandomFees() const void CCoinJoinServer::ConsumeCollateral(const CTransactionRef& txref) const { LOCK(cs_main); - CValidationState validationState; - if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, txref, nullptr /* pfMissingInputs */, false /* bypass_limits */, 0 /* nAbsurdFee */)) { + TxValidationState validationState; + if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, txref, false /* bypass_limits */, 0 /* nAbsurdFee */)) { LogPrint(BCLog::COINJOIN, "%s -- AcceptToMemoryPool failed\n", __func__); } else { connman.RelayTransaction(*txref); diff --git a/src/consensus/tx_check.cpp b/src/consensus/tx_check.cpp index 36b91dc58a..dff067b685 100644 --- a/src/consensus/tx_check.cpp +++ b/src/consensus/tx_check.cpp @@ -10,7 +10,7 @@ #include #include -bool CheckTransaction(const CTransaction& tx, CValidationState& state) +bool CheckTransaction(const CTransaction& tx, TxValidationState& state) { bool allowEmptyTxInOut = false; if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) { @@ -19,25 +19,25 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state) // Basic checks that don't depend on any context if (!allowEmptyTxInOut && tx.vin.empty()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vin-empty"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vin-empty"); if (!allowEmptyTxInOut && tx.vout.empty()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-empty"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-empty"); // Size limits if (::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-oversize"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-oversize"); if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-payload-oversize"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-payload-oversize"); // Check for negative or overflow output values (see CVE-2010-5139) CAmount nValueOut = 0; for (const auto& txout : tx.vout) { if (txout.nValue < 0) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-negative"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-negative"); if (txout.nValue > MAX_MONEY) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-toolarge"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-toolarge"); nValueOut += txout.nValue; if (!MoneyRange(nValueOut)) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-txouttotal-toolarge"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-txouttotal-toolarge"); } // Check for duplicate inputs (see CVE-2018-17144) @@ -48,7 +48,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state) std::set vInOutPoints; for (const auto& txin : tx.vin) { if (!vInOutPoints.insert(txin.prevout).second) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputs-duplicate"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputs-duplicate"); } if (tx.IsCoinBase()) { @@ -58,11 +58,11 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state) minCbSize = 1; } if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-length"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cb-length"); } else { for (const auto& txin : tx.vin) if (txin.prevout.IsNull()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-prevout-null"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-prevout-null"); } return true; diff --git a/src/consensus/tx_check.h b/src/consensus/tx_check.h index c1edb916bc..223b5e0a21 100644 --- a/src/consensus/tx_check.h +++ b/src/consensus/tx_check.h @@ -13,9 +13,9 @@ */ class CTransaction; -class CValidationState; +class TxValidationState; /** Context-independent validity checks */ -bool CheckTransaction(const CTransaction& tx, CValidationState& state); +bool CheckTransaction(const CTransaction& tx, TxValidationState& state); #endif // BITCOIN_CONSENSUS_TX_CHECK_H diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index bcad06db3d..58f1b2fc0b 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -158,11 +158,11 @@ unsigned int GetTransactionSigOpCount(const CTransaction& tx, const CCoinsViewCa return nSigOps; } -bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee) +bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee) { // are the actual inputs available? if (!inputs.HaveInputs(tx)) { - return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, "bad-txns-inputs-missingorspent", + return state.Invalid(TxValidationResult::TX_MISSING_INPUTS, "bad-txns-inputs-missingorspent", strprintf("%s: inputs missing/spent", __func__)); } @@ -174,27 +174,27 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c // If prev is coinbase, check that it's matured if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) { - return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "bad-txns-premature-spend-of-coinbase", + return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-coinbase", strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight)); } // Check for negative or overflow input values nValueIn += coin.out.nValue; if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputvalues-outofrange"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputvalues-outofrange"); } } const CAmount value_out = tx.GetValueOut(); if (nValueIn < value_out) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-in-belowout", + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-in-belowout", strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out))); } // Tally transaction fees const CAmount txfee_aux = nValueIn - value_out; if (!MoneyRange(txfee_aux)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-fee-outofrange"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange"); } txfee = txfee_aux; diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h index 3ab4bd6117..a2dcf362fc 100644 --- a/src/consensus/tx_verify.h +++ b/src/consensus/tx_verify.h @@ -13,7 +13,7 @@ class CBlockIndex; class CCoinsViewCache; class CTransaction; -class CValidationState; +class TxValidationState; /** Transaction validation functions */ @@ -24,7 +24,7 @@ namespace Consensus { * @param[out] txfee Set to the transaction fee if successful. * Preconditions: tx.IsCoinBase() is false. */ -bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee); +bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee); } // namespace Consensus /** Auxiliary functions for transaction validation (ideally should not be exposed) */ diff --git a/src/consensus/validation.h b/src/consensus/validation.h index 6628926255..86efba5dfa 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -8,19 +8,47 @@ #include -/** A "reason" why something was invalid, suitable for determining whether the - * provider of the object should be banned/ignored/disconnected/etc. +/** A "reason" why a transaction was invalid, suitable for determining whether the + * provider of the transaction should be banned/ignored/disconnected/etc. */ -enum class ValidationInvalidReason { - // txn and blocks: - NONE, //!< not actually invalid - CONSENSUS, //!< invalid by consensus rules (excluding any below reasons) +enum class TxValidationResult { + TX_RESULT_UNSET, //!< initial value. Tx has not yet been rejected + TX_CONSENSUS, //!< invalid by consensus rules /** * Invalid by a change to consensus rules more recent than some major deployment. */ - RECENT_CONSENSUS_CHANGE, - // Only blocks (or headers): - CACHED_INVALID, //!< this object was cached as being invalid, but we don't know why + // Only loose txn: + TX_RECENT_CONSENSUS_CHANGE, + TX_NOT_STANDARD, //!< didn't meet our local policy rules + TX_MISSING_INPUTS, //!< transaction was missing some of its inputs + TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks + TX_BAD_SPECIAL, //!< special transaction violates some rules that are not enough for insta-ban + /** + * Tx already in mempool or conflicts with a tx in the chain + * Currently this is only used if the transaction already exists in the mempool or on chain. + */ + TX_CONFLICT, + TX_CONFLICT_LOCK, //!< conflicts with InstantSend lock + TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/etc limits +}; + +/** A "reason" why a block was invalid, suitable for determining whether the + * provider of the block should be banned/ignored/disconnected/etc. + * These are much more granular than the rejection codes, which may be more + * useful for some other use-cases. + */ +enum class BlockValidationResult { + BLOCK_RESULT_UNSET, //!< initial value. Block has not yet been rejected + BLOCK_CONSENSUS, //!< invalid by consensus rules (excluding any below reasons) + /** + * Invalid by a change to consensus rules more recent than SegWit. + * Currently unused as there are no such consensus rule changes, and any download + * sources realistically need to support SegWit in order to provide useful data, + * so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork + * is uninteresting. + */ + BLOCK_RECENT_CONSENSUS_CHANGE, + BLOCK_CACHED_INVALID, //!< this block was cached as being invalid and we didn't store the reason why BLOCK_INVALID_HEADER, //!< invalid proof of work or time too old BLOCK_MUTATED, //!< the block's data didn't match the data committed to by the PoW BLOCK_MISSING_PREV, //!< We don't have the previous block the checked one is built on @@ -28,92 +56,78 @@ enum class ValidationInvalidReason { BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad) BLOCK_CHECKPOINT, //!< the block failed to meet one of our checkpoints BLOCK_CHAINLOCK, //!< the block conflicts with the ChainLock - // Only loose txn: - TX_NOT_STANDARD, //!< didn't meet our local policy rules - TX_MISSING_INPUTS, //!< a transaction was missing some of its inputs - TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks - TX_BAD_SPECIAL, //!< special transaction violates some rules that are not enough for insta-ban - /** - * Tx already in mempool or conflicts with a tx in the chain - * TODO: Currently this is only used if the transaction already exists in the mempool or on chain, - * TODO: ATMP's fMissingInputs and a valid CValidationState being used to indicate missing inputs - */ - TX_CONFLICT, - TX_CONFLICT_LOCK, //!< conflicts with InstantSend lock - TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/etc limits }; -inline bool IsTransactionReason(ValidationInvalidReason r) -{ - return r == ValidationInvalidReason::NONE || - r == ValidationInvalidReason::CONSENSUS || - r == ValidationInvalidReason::RECENT_CONSENSUS_CHANGE || - r == ValidationInvalidReason::TX_NOT_STANDARD || - r == ValidationInvalidReason::TX_PREMATURE_SPEND || - r == ValidationInvalidReason::TX_MISSING_INPUTS || - r == ValidationInvalidReason::TX_BAD_SPECIAL || - r == ValidationInvalidReason::TX_CONFLICT || - r == ValidationInvalidReason::TX_CONFLICT_LOCK || - r == ValidationInvalidReason::TX_MEMPOOL_POLICY; -} -inline bool IsBlockReason(ValidationInvalidReason r) -{ - return r == ValidationInvalidReason::NONE || - r == ValidationInvalidReason::CONSENSUS || - r == ValidationInvalidReason::RECENT_CONSENSUS_CHANGE || - r == ValidationInvalidReason::CACHED_INVALID || - r == ValidationInvalidReason::BLOCK_INVALID_HEADER || - r == ValidationInvalidReason::BLOCK_MUTATED || - r == ValidationInvalidReason::BLOCK_MISSING_PREV || - r == ValidationInvalidReason::BLOCK_INVALID_PREV || - r == ValidationInvalidReason::BLOCK_TIME_FUTURE || - r == ValidationInvalidReason::BLOCK_CHECKPOINT || - r == ValidationInvalidReason::BLOCK_CHAINLOCK; -} -/** Capture information about block/transaction validation */ -class CValidationState { +/** Base class for capturing information about block/transaction validation. This is subclassed + * by TxValidationState and BlockValidationState for validation information on transactions + * and blocks respectively. */ +class ValidationState { private: enum mode_state { MODE_VALID, //!< everything ok MODE_INVALID, //!< network rule violation (DoS value may be set) MODE_ERROR, //!< run-time error - } mode; - ValidationInvalidReason m_reason; - std::string strRejectReason; - std::string strDebugMessage; -public: - CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE) {} - bool Invalid(ValidationInvalidReason reasonIn, bool ret = false, - const std::string &strRejectReasonIn="", - const std::string &strDebugMessageIn="") { - m_reason = reasonIn; - strRejectReason = strRejectReasonIn; - strDebugMessage = strDebugMessageIn; - if (mode == MODE_ERROR) - return ret; - mode = MODE_INVALID; - return ret; + } m_mode; + std::string m_reject_reason; + std::string m_debug_message; +protected: + void Invalid(const std::string &reject_reason="", + const std::string &debug_message="") + { + m_reject_reason = reject_reason; + m_debug_message = debug_message; + if (m_mode != MODE_ERROR) m_mode = MODE_INVALID; } - bool Error(const std::string& strRejectReasonIn) { - if (mode == MODE_VALID) - strRejectReason = strRejectReasonIn; - mode = MODE_ERROR; +public: + // ValidationState is abstract. Have a pure virtual destructor. + virtual ~ValidationState() = 0; + + ValidationState() : m_mode(MODE_VALID) {} + bool Error(const std::string& reject_reason) + { + if (m_mode == MODE_VALID) + m_reject_reason = reject_reason; + m_mode = MODE_ERROR; return false; } - bool IsValid() const { - return mode == MODE_VALID; + bool IsValid() const { return m_mode == MODE_VALID; } + bool IsInvalid() const { return m_mode == MODE_INVALID; } + bool IsError() const { return m_mode == MODE_ERROR; } + std::string GetRejectReason() const { return m_reject_reason; } + std::string GetDebugMessage() const { return m_debug_message; } +}; + +inline ValidationState::~ValidationState() {}; + +class TxValidationState : public ValidationState { +private: + TxValidationResult m_result; +public: + bool Invalid(TxValidationResult result, + const std::string &reject_reason="", + const std::string &debug_message="") + { + m_result = result; + ValidationState::Invalid(reject_reason, debug_message); + return false; } - bool IsInvalid() const { - return mode == MODE_INVALID; + TxValidationResult GetResult() const { return m_result; } +}; + +class BlockValidationState : public ValidationState { +private: + BlockValidationResult m_result; +public: + bool Invalid(BlockValidationResult result, + const std::string &reject_reason="", + const std::string &debug_message="") { + m_result = result; + ValidationState::Invalid(reject_reason, debug_message); + return false; } - bool IsError() const { - return mode == MODE_ERROR; - } - ValidationInvalidReason GetReason() const { return m_reason; } - std::string GetRejectReason() const { return strRejectReason; } - std::string GetDebugMessage() const { return strDebugMessage; } + BlockValidationResult GetResult() const { return m_result; } }; #endif // BITCOIN_CONSENSUS_VALIDATION_H diff --git a/src/evo/cbtx.cpp b/src/evo/cbtx.cpp index 81313526af..81fefe7853 100644 --- a/src/evo/cbtx.cpp +++ b/src/evo/cbtx.cpp @@ -15,33 +15,33 @@ #include #include -bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) +bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state) { if (tx.nType != TRANSACTION_COINBASE) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-type"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-type"); } if (!tx.IsCoinBase()) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-invalid"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-invalid"); } CCbTx cbTx; if (!GetTxPayload(tx, cbTx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-payload"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-payload"); } if (cbTx.nVersion == 0 || cbTx.nVersion > CCbTx::CURRENT_VERSION) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-version"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-version"); } if (pindexPrev && pindexPrev->nHeight + 1 != cbTx.nHeight) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-height"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-height"); } if (pindexPrev) { bool fDIP0008Active = pindexPrev->nHeight >= Params().GetConsensus().DIP0008Height; if (fDIP0008Active && cbTx.nVersion < 2) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-version"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-version"); } } @@ -49,7 +49,7 @@ bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidatio } // This can only be done after the block has been fully processed, as otherwise we won't have the finished MN list -bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const llmq::CQuorumBlockProcessor& quorum_block_processor, CValidationState& state, const CCoinsViewCache& view) +bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const llmq::CQuorumBlockProcessor& quorum_block_processor, BlockValidationState& state, const CCoinsViewCache& view) { if (block.vtx[0]->nType != TRANSACTION_COINBASE) { return true; @@ -61,7 +61,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const CCbTx cbTx; if (!GetTxPayload(*block.vtx[0], cbTx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-payload"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-payload"); } int64_t nTime2 = GetTimeMicros(); nTimePayload += nTime2 - nTime1; @@ -77,7 +77,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const return false; } if (calculatedMerkleRoot != cbTx.merkleRootMNList) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-mnmerkleroot"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-mnmerkleroot"); } int64_t nTime3 = GetTimeMicros(); nTimeMerkleMNL += nTime3 - nTime2; @@ -89,7 +89,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const return false; } if (calculatedMerkleRoot != cbTx.merkleRootQuorums) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cbtx-quorummerkleroot"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-quorummerkleroot"); } } @@ -101,7 +101,7 @@ bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const return true; } -bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state, const CCoinsViewCache& view) +bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, BlockValidationState& state, const CCoinsViewCache& view) { LOCK(deterministicMNManager->cs); @@ -134,7 +134,7 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev if (sml == smlCached) { merkleRootRet = merkleRootCached; if (mutatedCached) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "mutated-cached-calc-cb-mnmerkleroot"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "mutated-cached-calc-cb-mnmerkleroot"); } return true; } @@ -150,13 +150,13 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev mutatedCached = mutated; if (mutated) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "mutated-calc-cb-mnmerkleroot"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "mutated-calc-cb-mnmerkleroot"); } return true; } catch (const std::exception& e) { LogPrintf("%s -- failed: %s\n", __func__, e.what()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-calc-cb-mnmerkleroot"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "failed-calc-cb-mnmerkleroot"); } } @@ -223,7 +223,7 @@ auto CalcHashCountFromQCHashes(const QcHashMap& qcHashes) return hash_count; } -bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, CValidationState& state) +bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, BlockValidationState& state) { static int64_t nTimeMined = 0; static int64_t nTimeLoop = 0; @@ -233,7 +233,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre auto retVal = CachedGetQcHashesQcIndexedHashes(pindexPrev, quorum_block_processor); if (!retVal) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "commitment-not-found"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "commitment-not-found"); } // The returned quorums are in reversed order, so the most recent one is at index 0 auto [qcHashes, qcIndexedHashes] = retVal.value(); @@ -249,7 +249,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre if (tx->nVersion == 3 && tx->nType == TRANSACTION_QUORUM_COMMITMENT) { llmq::CFinalCommitmentTxPayload qc; if (!GetTxPayload(*tx, qc)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload-calc-cbtx-quorummerkleroot"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-payload-calc-cbtx-quorummerkleroot"); } if (qc.commitment.IsNull()) { // having null commitments is ok but we don't use them here, move to the next tx @@ -257,7 +257,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre } const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType); if (!llmq_params_opt.has_value()) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot"); } const auto& llmq_params = llmq_params_opt.value(); auto qcHash = ::SerializeHash(qc.commitment); @@ -291,7 +291,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType); assert(llmq_params_opt.has_value()); if (vec_hashes.size() > size_t(llmq_params_opt->signingActiveQuorumCount)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "excess-quorums-calc-cbtx-quorummerkleroot"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "excess-quorums-calc-cbtx-quorummerkleroot"); } // Copy vec_hashes into vec_hashes_final std::copy(vec_hashes.begin(), vec_hashes.end(), std::back_inserter(vec_hashes_final)); @@ -308,7 +308,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre LogPrint(BCLog::BENCHMARK, " - ComputeMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkle * 0.000001); if (mutated) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "mutated-calc-cbtx-quorummerkleroot"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "mutated-calc-cbtx-quorummerkleroot"); } return true; diff --git a/src/evo/cbtx.h b/src/evo/cbtx.h index 90f42bf321..1b64ef2036 100644 --- a/src/evo/cbtx.h +++ b/src/evo/cbtx.h @@ -8,10 +8,11 @@ #include #include +class BlockValidationState; class CBlock; class CBlockIndex; class CCoinsViewCache; -class CValidationState; +class TxValidationState; namespace llmq { class CQuorumBlockProcessor; @@ -53,10 +54,10 @@ public: } }; -bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state); +bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state); -bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const llmq::CQuorumBlockProcessor& quorum_block_processor, CValidationState& state, const CCoinsViewCache& view); -bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state, const CCoinsViewCache& view); -bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, CValidationState& state); +bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, const llmq::CQuorumBlockProcessor& quorum_block_processor, BlockValidationState& state, const CCoinsViewCache& view); +bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, BlockValidationState& state, const CCoinsViewCache& view); +bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet, BlockValidationState& state); #endif // BITCOIN_EVO_CBTX_H diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 758b086d0e..6f20c5f7cb 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -654,7 +654,7 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash) mnInternalIdMap = mnInternalIdMap.erase(dmn->GetInternalId()); } -bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& _state, const CCoinsViewCache& view, bool fJustCheck) +bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck) { AssertLockHeld(cs_main); @@ -672,7 +672,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde try { LOCK(cs); - if (!BuildNewListFromBlock(block, pindex->pprev, _state, view, newList, true)) { + if (!BuildNewListFromBlock(block, pindex->pprev, state, view, newList, true)) { // pass the state returned by the function above return false; } @@ -710,7 +710,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde mnListDiffsCache.emplace(pindex->GetBlockHash(), diff); } catch (const std::exception& e) { LogPrintf("CDeterministicMNManager::%s -- internal error: %s\n", __func__, e.what()); - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-dmn-block"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "failed-dmn-block"); } // Don't hold cs while calling signals @@ -723,7 +723,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde if (!consensusParams.DIP0003EnforcementHash.IsNull() && consensusParams.DIP0003EnforcementHash != pindex->GetBlockHash()) { LogPrintf("CDeterministicMNManager::%s -- DIP3 enforcement block has wrong hash: hash=%s, expected=%s, nHeight=%d\n", __func__, pindex->GetBlockHash().ToString(), consensusParams.DIP0003EnforcementHash.ToString(), nHeight); - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-dip3-enf-block"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-dip3-enf-block"); } LogPrintf("CDeterministicMNManager::%s -- DIP3 is enforced now. nHeight=%d\n", __func__, nHeight); } @@ -775,7 +775,7 @@ void CDeterministicMNManager::UpdatedBlockTip(const CBlockIndex* pindex) tipIndex = pindex; } -bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, CValidationState& _state, const CCoinsViewCache& view, CDeterministicMNList& mnListRet, bool debugLogs) +bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, BlockValidationState& state, const CCoinsViewCache& view, CDeterministicMNList& mnListRet, bool debugLogs) { AssertLockHeld(cs); @@ -820,11 +820,11 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C if (tx.nType == TRANSACTION_PROVIDER_REGISTER) { CProRegTx proTx; if (!GetTxPayload(tx, proTx)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload"); } if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload"); } auto dmn = std::make_shared(newList.GetTotalRegisteredCount(), proTx.nType); @@ -842,7 +842,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C if (!proTx.collateralOutpoint.hash.IsNull() && (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral)) { // should actually never get to this point as CheckProRegTx should have handled this case. // We do this additional check nevertheless to be 100% sure - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-collateral"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-collateral"); } auto replacedDmn = newList.GetMNByCollateral(dmn->collateralOutpoint); @@ -858,10 +858,10 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C } if (newList.HasUniqueProperty(proTx.addr)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-dup-addr"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-addr"); } if (newList.HasUniqueProperty(proTx.keyIDOwner) || newList.HasUniqueProperty(proTx.pubKeyOperator)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-dup-key"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-key"); } dmn->nOperatorReward = proTx.nOperatorReward; @@ -883,26 +883,26 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) { CProUpServTx proTx; if (!GetTxPayload(tx, proTx)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload"); } if (proTx.nType == MnType::HighPerformance && !llmq::utils::IsV19Active(pindexPrev)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload"); } if (newList.HasUniqueProperty(proTx.addr) && newList.GetUniquePropertyMN(proTx.addr)->proTxHash != proTx.proTxHash) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-dup-addr"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-addr"); } CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash); if (!dmn) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-hash"); } if (proTx.nType != dmn->nType) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type-mismatch"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-type-mismatch"); } if (!IsValidMnType(proTx.nType)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-type"); } auto newState = std::make_shared(*dmn->pdmnState); @@ -932,12 +932,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REGISTRAR) { CProUpRegTx proTx; if (!GetTxPayload(tx, proTx)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload"); } CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash); if (!dmn) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-hash"); } auto newState = std::make_shared(*dmn->pdmnState); if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) { @@ -958,12 +958,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) { CProUpRevTx proTx; if (!GetTxPayload(tx, proTx)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload"); } CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash); if (!dmn) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-hash"); } auto newState = std::make_shared(*dmn->pdmnState); newState->ResetOperatorFields(); @@ -979,19 +979,19 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C } else if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) { llmq::CFinalCommitmentTxPayload qc; if (!GetTxPayload(tx, qc)) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-payload"); } if (!qc.commitment.IsNull()) { const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType); if (!llmq_params_opt.has_value()) { - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-commitment-type"); } int qcnHeight = int(qc.nHeight); int quorumHeight = qcnHeight - (qcnHeight % llmq_params_opt->dkgInterval) + int(qc.commitment.quorumIndex); auto pQuorumBaseBlockIndex = pindexPrev->GetAncestor(quorumHeight); if (!pQuorumBaseBlockIndex || pQuorumBaseBlockIndex->GetBlockHash() != qc.commitment.quorumHash) { // we should actually never get into this case as validation should have caught it...but let's be sure - return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-quorum-hash"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-quorum-hash"); } HandleQuorumCommitment(qc.commitment, pQuorumBaseBlockIndex, newList, debugLogs); @@ -1348,111 +1348,111 @@ bool CDeterministicMNManager::MigrateDBIfNeeded() } template -static bool CheckService(const ProTx& proTx, CValidationState& state) +static bool CheckService(const ProTx& proTx, TxValidationState& state) { if (!proTx.addr.IsValid()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr"); } if (Params().RequireRoutableExternalIP() && !proTx.addr.IsRoutable()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr"); } static int mainnetDefaultPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort(); if (Params().NetworkIDString() == CBaseChainParams::MAIN) { if (proTx.addr.GetPort() != mainnetDefaultPort) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr-port"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr-port"); } } else if (proTx.addr.GetPort() == mainnetDefaultPort) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr-port"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr-port"); } if (!proTx.addr.IsIPv4()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-ipaddr"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr"); } return true; } template -static bool CheckPlatformFields(const ProTx& proTx, CValidationState& state) +static bool CheckPlatformFields(const ProTx& proTx, TxValidationState& state) { if (proTx.platformNodeID.IsNull()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-nodeid"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-nodeid"); } static int mainnetPlatformP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformP2PPort(); if (Params().NetworkIDString() == CBaseChainParams::MAIN) { if (proTx.platformP2PPort != mainnetPlatformP2PPort) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-p2p-port"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-p2p-port"); } } static int mainnetPlatformHTTPPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPlatformHTTPPort(); if (Params().NetworkIDString() == CBaseChainParams::MAIN) { if (proTx.platformHTTPPort != mainnetPlatformHTTPPort) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-http-port"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-http-port"); } } static int mainnetDefaultP2PPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort(); if (proTx.platformP2PPort == mainnetDefaultP2PPort) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-p2p-port"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-p2p-port"); } if (proTx.platformHTTPPort == mainnetDefaultP2PPort) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-http-port"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-http-port"); } if (proTx.platformP2PPort == proTx.platformHTTPPort || proTx.platformP2PPort == proTx.addr.GetPort() || proTx.platformHTTPPort == proTx.addr.GetPort()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-platform-dup-ports"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-dup-ports"); } return true; } template -static bool CheckHashSig(const ProTx& proTx, const PKHash& pkhash, CValidationState& state) +static bool CheckHashSig(const ProTx& proTx, const PKHash& pkhash, TxValidationState& state) { std::string strError; if (!CHashSigner::VerifyHash(::SerializeHash(proTx), ToKeyID(pkhash), proTx.vchSig, strError)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig"); } return true; } template -static bool CheckStringSig(const ProTx& proTx, const PKHash& pkhash, CValidationState& state) +static bool CheckStringSig(const ProTx& proTx, const PKHash& pkhash, TxValidationState& state) { std::string strError; if (!CMessageSigner::VerifyMessage(ToKeyID(pkhash), proTx.vchSig, proTx.MakeSignString(), strError)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig"); } return true; } template -static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, CValidationState& state) +static bool CheckHashSig(const ProTx& proTx, const CBLSPublicKey& pubKey, TxValidationState& state) { if (!proTx.sig.VerifyInsecure(pubKey, ::SerializeHash(proTx))) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig"); } return true; } -bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) +bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs) { if (tx.nType != TRANSACTION_PROVIDER_REGISTER) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type"); } CProRegTx ptx; if (!GetTxPayload(tx, ptx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-payload"); } if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str)); } // It's allowed to set addr to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later @@ -1477,31 +1477,31 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid if (!ptx.collateralOutpoint.hash.IsNull()) { Coin coin; if (!view.GetCoin(ptx.collateralOutpoint, coin) || coin.IsSpent() || coin.out.nValue != expectedCollateral) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral"); } if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-dest"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-dest"); } // Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH. // Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx keyForPayloadSig = std::get_if(&collateralTxDest); if (!keyForPayloadSig) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-pkh"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-pkh"); } collateralOutpoint = ptx.collateralOutpoint; } else { if (ptx.collateralOutpoint.n >= tx.vout.size()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-index"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-index"); } if (tx.vout[ptx.collateralOutpoint.n].nValue != expectedCollateral) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral"); } if (!ExtractDestination(tx.vout[ptx.collateralOutpoint.n].scriptPubKey, collateralTxDest)) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-dest"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-dest"); } collateralOutpoint = COutPoint(tx.GetHash(), ptx.collateralOutpoint.n); @@ -1510,7 +1510,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid // don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server) // this check applies to internal and external collateral, but internal collaterals are not necessarily a P2PKH if (collateralTxDest == CTxDestination(PKHash(ptx.keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-reuse"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-reuse"); } if (pindexPrev) { @@ -1518,30 +1518,30 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid // only allow reusing of addresses when it's for the same collateral (which replaces the old MN) if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->collateralOutpoint != collateralOutpoint) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-addr"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-addr"); } // never allow duplicate keys, even if this ProTx would replace an existing MN if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.pubKeyOperator)) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-key"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-key"); } // never allow duplicate platformNodeIds for HPMNs if (ptx.nType == MnType::HighPerformance) { if (mnList.HasUniqueProperty(ptx.platformNodeID)) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-platformnodeid"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-platformnodeid"); } } if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) { if (ptx.keyIDOwner != ptx.keyIDVoting) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-key-not-same"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-not-same"); } } } if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str)); } if (keyForPayloadSig) { @@ -1553,26 +1553,26 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid } else { // collateral is part of this ProRegTx, so we know the collateral is owned by the issuer if (!ptx.vchSig.empty()) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-sig"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig"); } } return true; } -bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs) +bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs) { if (tx.nType != TRANSACTION_PROVIDER_UPDATE_SERVICE) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type"); } CProUpServTx ptx; if (!GetTxPayload(tx, ptx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-payload"); } if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str)); } if (!CheckService(ptx, state)) { @@ -1590,34 +1590,34 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); auto mn = mnList.GetMN(ptx.proTxHash); if (!mn) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-hash"); } // don't allow updating to addresses already used by other MNs if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->proTxHash != ptx.proTxHash) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-addr"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-addr"); } // don't allow updating to platformNodeIds already used by other HPMNs if (ptx.nType == MnType::HighPerformance) { if (mnList.HasUniqueProperty(ptx.platformNodeID) && mnList.GetUniquePropertyMN(ptx.platformNodeID)->proTxHash != ptx.proTxHash) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-platformnodeid"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-platformnodeid"); } } if (ptx.scriptOperatorPayout != CScript()) { if (mn->nOperatorReward == 0) { // don't allow setting operator reward payee in case no operatorReward was set - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-operator-payee"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-payee"); } if (!ptx.scriptOperatorPayout.IsPayToPublicKeyHash() && !ptx.scriptOperatorPayout.IsPayToScriptHash()) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-operator-payee"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-payee"); } } // we can only check the signature if pindexPrev != nullptr and the MN is known if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str)); } if (check_sigs && !CheckHashSig(ptx, mn->pdmnState->pubKeyOperator.Get(), state)) { // pass the state returned by the function above @@ -1628,69 +1628,69 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa return true; } -bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) +bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs) { if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type"); } CProUpRegTx ptx; if (!GetTxPayload(tx, ptx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-payload"); } if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str)); } CTxDestination payoutDest; if (!ExtractDestination(ptx.scriptPayout, payoutDest)) { // should not happen as we checked script types before - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-payee-dest"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-dest"); } if (pindexPrev) { auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); auto dmn = mnList.GetMN(ptx.proTxHash); if (!dmn) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-hash"); } // don't allow reuse of payee key for other keys (don't allow people to put the payee key onto an online server) if (payoutDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || payoutDest == CTxDestination(PKHash(ptx.keyIDVoting))) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-payee-reuse"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-reuse"); } Coin coin; if (!view.GetCoin(dmn->collateralOutpoint, coin) || coin.IsSpent()) { // this should never happen (there would be no dmn otherwise) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-collateral"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-collateral"); } // don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server) CTxDestination collateralTxDest; if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-collateral-dest"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-collateral-dest"); } if (collateralTxDest == CTxDestination(PKHash(dmn->pdmnState->keyIDOwner)) || collateralTxDest == CTxDestination(PKHash(ptx.keyIDVoting))) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-collateral-reuse"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-collateral-reuse"); } if (mnList.HasUniqueProperty(ptx.pubKeyOperator)) { auto otherDmn = mnList.GetUniquePropertyMN(ptx.pubKeyOperator); if (ptx.proTxHash != otherDmn->proTxHash) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-dup-key"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-key"); } } if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) { if (dmn->pdmnState->keyIDOwner != ptx.keyIDVoting) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-protx-key-not-same"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-not-same"); } } if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str)); } if (check_sigs && !CheckHashSig(ptx, PKHash(dmn->pdmnState->keyIDOwner), state)) { // pass the state returned by the function above @@ -1701,29 +1701,29 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal return true; } -bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs) +bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs) { if (tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-type"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type"); } CProUpRevTx ptx; if (!GetTxPayload(tx, ptx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-payload"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-payload"); } if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str)); } if (pindexPrev) { auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); auto dmn = mnList.GetMN(ptx.proTxHash); if (!dmn) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-protx-hash"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-hash"); if (auto maybe_err = CheckInputsHash(tx, ptx); maybe_err.did_err) { - return state.Invalid(maybe_err.reason, false, std::string(maybe_err.error_str)); + return state.Invalid(maybe_err.reason, std::string(maybe_err.error_str)); } if (check_sigs && !CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator.Get(), state)) { // pass the state returned by the function above diff --git a/src/evo/deterministicmns.h b/src/evo/deterministicmns.h index 103add8d19..a510289821 100644 --- a/src/evo/deterministicmns.h +++ b/src/evo/deterministicmns.h @@ -27,7 +27,7 @@ class CConnman; class CBlock; class CBlockIndex; -class CValidationState; +class TxValidationState; class CSimplifiedMNListDiff; extern CCriticalSection cs_main; @@ -563,14 +563,14 @@ public: m_evoDb(evoDb), connman(_connman) {} ~CDeterministicMNManager() = default; - bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state, + bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck) EXCLUSIVE_LOCKS_REQUIRED(cs_main) LOCKS_EXCLUDED(cs); bool UndoBlock(const CBlock& block, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs); void UpdatedBlockTip(const CBlockIndex* pindex) LOCKS_EXCLUDED(cs); // the returned list will not contain the correct block hash (we can't know it yet as the coinbase TX is not updated yet) - bool BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, + bool BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, BlockValidationState& state, const CCoinsViewCache& view, CDeterministicMNList& mnListRet, bool debugLogs) EXCLUSIVE_LOCKS_REQUIRED(cs); static void HandleQuorumCommitment(const llmq::CFinalCommitment& qc, const CBlockIndex* pQuorumBaseBlockIndex, CDeterministicMNList& mnList, bool debugLogs); static void DecreasePoSePenalties(CDeterministicMNList& mnList); @@ -595,10 +595,10 @@ private: CDeterministicMNList GetListForBlockInternal(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs); }; -bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs); -bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs); -bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs); -bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, bool check_sigs); +bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs); +bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs); +bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs); +bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs); extern std::unique_ptr deterministicMNManager; diff --git a/src/evo/mnhftx.cpp b/src/evo/mnhftx.cpp index e12ce03861..55394beaa4 100644 --- a/src/evo/mnhftx.cpp +++ b/src/evo/mnhftx.cpp @@ -34,33 +34,33 @@ bool MNHFTx::Verify(const CBlockIndex* pQuorumIndex) const llmq::CSigningManager::VerifyRecoveredSig(llmqType, *llmq::quorumManager, pQuorumIndex->nHeight, requestId, pQuorumIndex->GetBlockHash(), sig, signOffset); } -bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { MNHFTxPayload mnhfTx; if (!GetTxPayload(tx, mnhfTx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-payload"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-payload"); } if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-version"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-version"); } const CBlockIndex* pindexQuorum = g_chainman.m_blockman.LookupBlockIndex(mnhfTx.signal.quorumHash); if (!pindexQuorum) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-quorum-hash"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-quorum-hash"); } if (pindexQuorum != pindexPrev->GetAncestor(pindexQuorum->nHeight)) { // not part of active chain - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-quorum-hash"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-quorum-hash"); } if (!llmq::GetLLMQParams(Params().GetConsensus().llmqTypeMnhf).has_value()) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-type"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-type"); } if (!mnhfTx.signal.Verify(pindexQuorum)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-invalid"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-invalid"); } return true; diff --git a/src/evo/mnhftx.h b/src/evo/mnhftx.h index 90438e1bfd..61c14f6502 100644 --- a/src/evo/mnhftx.h +++ b/src/evo/mnhftx.h @@ -12,7 +12,7 @@ #include class CBlockIndex; -class CValidationState; +class TxValidationState; extern CCriticalSection cs_main; // mnhf signal special transaction @@ -72,6 +72,6 @@ public: } }; -bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); +bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); #endif // BITCOIN_EVO_MNHFTX_H diff --git a/src/evo/providertx.cpp b/src/evo/providertx.cpp index 26123cb63e..a58cbec75c 100644 --- a/src/evo/providertx.cpp +++ b/src/evo/providertx.cpp @@ -14,34 +14,34 @@ maybe_error CProRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const { if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) { - return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"}; + return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"}; } if (!IsValidMnType(nType)) { - return {ValidationInvalidReason::CONSENSUS, "bad-protx-type"}; + return {TxValidationResult::TX_CONSENSUS, "bad-protx-type"}; } if (nMode != 0) { - return {ValidationInvalidReason::CONSENSUS, "bad-protx-mode"}; + return {TxValidationResult::TX_CONSENSUS, "bad-protx-mode"}; } if (keyIDOwner.IsNull() || !pubKeyOperator.IsValid() || keyIDVoting.IsNull()) { - return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-key-null"}; + return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-null"}; } if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) { - return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee"}; + return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee"}; } CTxDestination payoutDest; if (!ExtractDestination(scriptPayout, payoutDest)) { // should not happen as we checked script types before - return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee-dest"}; + return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-dest"}; } // don't allow reuse of payout key for other keys (don't allow people to put the payee key onto an online server) if (payoutDest == CTxDestination(PKHash(keyIDOwner)) || payoutDest == CTxDestination(PKHash(keyIDVoting))) { - return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee-reuse"}; + return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-reuse"}; } if (nOperatorReward > 10000) { - return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-operator-reward"}; + return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-reward"}; } return {}; @@ -87,7 +87,7 @@ std::string CProRegTx::ToString() const maybe_error CProUpServTx::IsTriviallyValid(bool is_bls_legacy_scheme) const { if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) { - return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"}; + return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"}; } return {}; @@ -108,17 +108,17 @@ std::string CProUpServTx::ToString() const maybe_error CProUpRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const { if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) { - return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"}; + return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"}; } if (nMode != 0) { - return {ValidationInvalidReason::CONSENSUS, "bad-protx-mode"}; + return {TxValidationResult::TX_CONSENSUS, "bad-protx-mode"}; } if (!pubKeyOperator.IsValid() || keyIDVoting.IsNull()) { - return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-key-null"}; + return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-null"}; } if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) { - return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee"}; + return {TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee"}; } return {}; } @@ -138,13 +138,13 @@ std::string CProUpRegTx::ToString() const maybe_error CProUpRevTx::IsTriviallyValid(bool is_bls_legacy_scheme) const { if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) { - return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"}; + return {TxValidationResult::TX_CONSENSUS, "bad-protx-version"}; } // nReason < CProUpRevTx::REASON_NOT_SPECIFIED is always `false` since // nReason is unsigned and CProUpRevTx::REASON_NOT_SPECIFIED == 0 if (nReason > CProUpRevTx::REASON_LAST) { - return {ValidationInvalidReason::CONSENSUS, "bad-protx-reason"}; + return {TxValidationResult::TX_CONSENSUS, "bad-protx-reason"}; } return {}; } diff --git a/src/evo/providertx.h b/src/evo/providertx.h index e113911eab..17395bda3f 100644 --- a/src/evo/providertx.h +++ b/src/evo/providertx.h @@ -20,7 +20,7 @@ class CBlockIndex; class CCoinsViewCache; -class CValidationState; +class TxValidationState; class CProRegTx { @@ -329,7 +329,7 @@ template static maybe_error CheckInputsHash(const CTransaction& tx, const ProTx& proTx) { if (uint256 inputsHash = CalcTxInputsHash(tx); inputsHash != proTx.inputsHash) { - return {ValidationInvalidReason::CONSENSUS, "bad-protx-inputs-hash"}; + return {TxValidationResult::TX_CONSENSUS, "bad-protx-inputs-hash"}; } return {}; diff --git a/src/evo/specialtx.h b/src/evo/specialtx.h index 7eb1adaa1d..8eb755370c 100644 --- a/src/evo/specialtx.h +++ b/src/evo/specialtx.h @@ -17,11 +17,11 @@ struct maybe_error { bool did_err{false}; - ValidationInvalidReason reason{ValidationInvalidReason::CONSENSUS}; + TxValidationResult reason{TxValidationResult::TX_CONSENSUS}; std::string_view error_str; constexpr maybe_error() = default; - constexpr maybe_error(ValidationInvalidReason reasonIn, std::string_view err): did_err(true), reason(reasonIn), error_str(err) {}; + constexpr maybe_error(TxValidationResult reasonIn, std::string_view err): did_err(true), reason(reasonIn), error_str(err) {}; }; template diff --git a/src/evo/specialtxman.cpp b/src/evo/specialtxman.cpp index 0c2083d3f9..e3837c50f0 100644 --- a/src/evo/specialtxman.cpp +++ b/src/evo/specialtxman.cpp @@ -16,7 +16,7 @@ #include #include -bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) +bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs) { AssertLockHeld(cs_main); @@ -24,7 +24,7 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali return true; if (pindexPrev && pindexPrev->nHeight + 1 < Params().GetConsensus().DIP0003Height) { - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-tx-type"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-tx-type"); } try { @@ -46,13 +46,13 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali } } catch (const std::exception& e) { LogPrintf("%s -- failed: %s\n", __func__, e.what()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-check-special-tx"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "failed-check-special-tx"); } - return state.Invalid(ValidationInvalidReason::TX_BAD_SPECIAL, false, "bad-tx-type-check"); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-tx-type-check"); } -bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValidationState& state) +bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, TxValidationState& state) { if (tx.nVersion != 3 || tx.nType == TRANSACTION_NORMAL) { return true; @@ -72,7 +72,7 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida return true; // handled per block } - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-tx-type-proc"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-tx-type-proc"); } bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex) @@ -99,7 +99,7 @@ bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex) } bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor, - CValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots) + BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots) { AssertLockHeld(cs_main); @@ -112,13 +112,18 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, ll int64_t nTime1 = GetTimeMicros(); for (const auto& ptr_tx : block.vtx) { - if (!CheckSpecialTx(*ptr_tx, pindex->pprev, state, view, fCheckCbTxMerleRoots)) { - // pass the state returned by the function above - return false; + TxValidationState tx_state; + // At this moment CheckSpecialTx() and ProcessSpecialTx() may fail by 2 possible ways: + // consensus failures and "TX_BAD_SPECIAL" + if (!CheckSpecialTx(*ptr_tx, pindex->pprev, tx_state, view, fCheckCbTxMerleRoots)) { + assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS || tx_state.GetResult() == TxValidationResult::TX_BAD_SPECIAL); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, tx_state.GetRejectReason(), + strprintf("Special Transaction check failed (tx hash %s) %s", ptr_tx->GetHash().ToString(), tx_state.GetDebugMessage())); } - if (!ProcessSpecialTx(*ptr_tx, pindex, state)) { - // pass the state returned by the function above - return false; + if (!ProcessSpecialTx(*ptr_tx, pindex, tx_state)) { + assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS || tx_state.GetResult() == TxValidationResult::TX_BAD_SPECIAL); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, tx_state.GetRejectReason(), + strprintf("Process Special Transaction failed (tx hash %s) %s", ptr_tx->GetHash().ToString(), tx_state.GetDebugMessage())); } } @@ -154,7 +159,7 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, ll LogPrint(BCLog::BENCHMARK, " - CheckCbTxMerkleRoots: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeMerkle * 0.000001); } catch (const std::exception& e) { LogPrintf("%s -- failed: %s\n", __func__, e.what()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "failed-procspectxsinblock"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "failed-procspectxsinblock"); } return true; diff --git a/src/evo/specialtxman.h b/src/evo/specialtxman.h index e526a20a90..ed8d4b5c31 100644 --- a/src/evo/specialtxman.h +++ b/src/evo/specialtxman.h @@ -9,19 +9,20 @@ #include #include +class BlockValidationState; class CBlock; class CBlockIndex; class CCoinsViewCache; -class CValidationState; +class TxValidationState; namespace llmq { class CQuorumBlockProcessor; } // namespace llmq extern CCriticalSection cs_main; -bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, bool check_sigs) EXCLUSIVE_LOCKS_REQUIRED(cs_main); +bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor, - CValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor) EXCLUSIVE_LOCKS_REQUIRED(cs_main); #endif // BITCOIN_EVO_SPECIALTXMAN_H diff --git a/src/init.cpp b/src/init.cpp index fd758a1201..09d8e3d967 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -928,7 +928,7 @@ static void ThreadImport(ChainstateManager& chainman, std::vector vImp // the chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve // the relevant pointers before the ABC call. for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) { - CValidationState state; + BlockValidationState state; if (!chainstate->ActivateBestChain(state, chainparams, nullptr)) { LogPrintf("Failed to connect best block (%s)\n", FormatStateMessage(state)); StartShutdown(); diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 683d6c1955..98471db956 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -23,7 +23,6 @@ class CFeeRate; class CRPCCommand; class CScheduler; class CTxMemPool; -class CValidationState; class CFeeRate; class CBlockIndex; class Coin; diff --git a/src/llmq/blockprocessor.cpp b/src/llmq/blockprocessor.cpp index 86782e14e4..606ae15cf5 100644 --- a/src/llmq/blockprocessor.cpp +++ b/src/llmq/blockprocessor.cpp @@ -136,7 +136,7 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m AddMineableCommitment(qc); } -bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state, bool fJustCheck, bool fBLSChecks) +bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state, bool fJustCheck, bool fBLSChecks) { AssertLockHeld(cs_main); @@ -172,11 +172,11 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex* const auto numCommitmentsInNewBlock = qcs.count(params.type); if (numCommitmentsRequired < numCommitmentsInNewBlock) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-not-allowed"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-not-allowed"); } if (numCommitmentsRequired > numCommitmentsInNewBlock) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-missing"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-missing"); } if (llmq::utils::IsQuorumRotationEnabled(params, pindex)) { LogPrintf("[ProcessBlock] h[%d] numCommitmentsRequired[%d] numCommitmentsInNewBlock[%d]\n", pindex->nHeight, numCommitmentsRequired, numCommitmentsInNewBlock); @@ -210,7 +210,7 @@ static std::tuple BuildInversed return std::make_tuple(DB_MINED_COMMITMENT_BY_INVERSED_HEIGHT_Q_INDEXED, llmqType, quorumIndex, htobe32(std::numeric_limits::max() - nMinedHeight)); } -bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, CValidationState& state, bool fJustCheck, bool fBLSChecks) +bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, BlockValidationState& state, bool fJustCheck, bool fBLSChecks) { AssertLockHeld(cs_main); @@ -234,31 +234,31 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH if (quorumHash.IsNull()) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s quorumHash is null.\n", __func__, nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-block"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-block"); } if (quorumHash != qc.quorumHash) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, qc.quorumHash=%s signers=%s, validMembers=%d, quorumPublicKey=%s non equal quorumHash.\n", __func__, nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-block"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-block"); } if (qc.IsNull()) { if (!qc.VerifyNull()) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%dqc verifynull failed.\n", __func__, nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid-null"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-invalid-null"); } return true; } if (HasMinedCommitment(llmq_params.type, quorumHash)) { // should not happen as it's already handled in ProcessBlock - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-dup"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-dup"); } if (!IsMiningPhase(llmq_params, nHeight)) { // should not happen as it's already handled in ProcessBlock - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-height"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-height"); } const auto* pQuorumBaseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(qc.quorumHash); @@ -266,7 +266,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH if (!qc.Verify(pQuorumBaseBlockIndex, fBLSChecks)) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s qc verify failed.\n", __func__, nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-invalid"); } if (fJustCheck) { @@ -313,7 +313,7 @@ bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, const CBlockIndex* pi llmq::utils::PreComputeQuorumMembers(pindex, true); std::multimap qcs; - CValidationState dummy; + BlockValidationState dummy; if (!GetCommitmentsFromBlock(block, pindex, qcs, dummy)) { return false; } @@ -378,7 +378,7 @@ bool CQuorumBlockProcessor::UpgradeDB() assert(r); std::multimap qcs; - CValidationState dummyState; + BlockValidationState dummyState; GetCommitmentsFromBlock(block, pindex, qcs, dummyState); for (const auto& p : qcs) { @@ -407,7 +407,7 @@ bool CQuorumBlockProcessor::UpgradeDB() return true; } -bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap& ret, CValidationState& state) +bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap& ret, BlockValidationState& state) { AssertLockHeld(cs_main); @@ -421,19 +421,19 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C if (!GetTxPayload(*tx, qc)) { // should not happen as it was verified before processing the block LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d GetTxPayload fails\n", __func__, pindex->nHeight); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-payload"); } const auto& llmq_params_opt = GetLLMQParams(qc.commitment.llmqType); if (!llmq_params_opt.has_value()) { // should not happen as it was verified before processing the block - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-commitment-type"); } // only allow one commitment per type and per block (This was changed with rotation) if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) { if (ret.count(qc.commitment.llmqType) != 0) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-dup"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-dup"); } } @@ -442,7 +442,7 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C } if (pindex->nHeight < consensus.DIP0003Height && !ret.empty()) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-premature"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-premature"); } return true; diff --git a/src/llmq/blockprocessor.h b/src/llmq/blockprocessor.h index 529d24e009..a5a28fc535 100644 --- a/src/llmq/blockprocessor.h +++ b/src/llmq/blockprocessor.h @@ -16,9 +16,9 @@ #include +class BlockValidationState; class CNode; class CConnman; -class CValidationState; class CEvoDB; extern CCriticalSection cs_main; @@ -49,7 +49,7 @@ public: void ProcessMessage(const CNode& peer, std::string_view msg_type, CDataStream& vRecv); - bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool UndoBlock(const CBlock& block, const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void AddMineableCommitment(const CFinalCommitment& fqc); @@ -67,8 +67,8 @@ public: std::vector> GetLastMinedCommitmentsPerQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, size_t cycle) const; std::optional GetLastMinedCommitmentsByQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, int quorumIndex, size_t cycle) const; private: - static bool GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap& ret, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - bool ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, CValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + static bool GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::multimap& ret, BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, BlockValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main); static bool IsMiningPhase(const Consensus::LLMQParams& llmqParams, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_main); size_t GetNumCommitmentsRequired(const Consensus::LLMQParams& llmqParams, int nHeight) const EXCLUSIVE_LOCKS_REQUIRED(cs_main); static uint256 GetQuorumBlockHash(const Consensus::LLMQParams& llmqParams, int nHeight, int quorumIndex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); diff --git a/src/llmq/chainlocks.cpp b/src/llmq/chainlocks.cpp index 746a36de4f..7a73939daf 100644 --- a/src/llmq/chainlocks.cpp +++ b/src/llmq/chainlocks.cpp @@ -494,20 +494,20 @@ void CChainLocksHandler::EnforceBestChainLock() } } - CValidationState state; + BlockValidationState dummy_state; const auto ¶ms = Params(); // Go backwards through the chain referenced by clsig until we find a block that is part of the main chain. // For each of these blocks, check if there are children that are NOT part of the chain referenced by clsig // and mark all of them as conflicting. LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- enforcing block %s via CLSIG (%s)\n", __func__, pindex->GetBlockHash().ToString(), clsig->ToString()); - ::ChainstateActive().EnforceBlock(state, params, pindex); + ::ChainstateActive().EnforceBlock(dummy_state, params, pindex); bool activateNeeded = WITH_LOCK(::cs_main, return ::ChainActive().Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight)) != currentBestChainLockBlockIndex; if (activateNeeded) { - if (!::ChainstateActive().ActivateBestChain(state, params)) { - LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(state)); + if (!::ChainstateActive().ActivateBestChain(dummy_state, params)) { + LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(dummy_state)); return; } LOCK(cs_main); diff --git a/src/llmq/commitment.cpp b/src/llmq/commitment.cpp index 730d1814ea..78ff897e10 100644 --- a/src/llmq/commitment.cpp +++ b/src/llmq/commitment.cpp @@ -176,18 +176,18 @@ bool CFinalCommitment::VerifySizes(const Consensus::LLMQParams& params) const return true; } -bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) +bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state) { CFinalCommitmentTxPayload qcTx; if (!GetTxPayload(tx, qcTx)) { LogPrintfFinalCommitment("h[%d] GetTxPayload failed\n", pindexPrev->nHeight); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-payload"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-payload"); } const auto& llmq_params_opt = GetLLMQParams(qcTx.commitment.llmqType); if (!llmq_params_opt.has_value()) { LogPrintfFinalCommitment("h[%d] GetLLMQParams failed for llmqType[%d]\n", pindexPrev->nHeight, ToUnderlying(qcTx.commitment.llmqType)); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-commitment-type"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-commitment-type"); } if (LogAcceptCategory(BCLog::LLMQ)) { @@ -201,36 +201,36 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, if (qcTx.nVersion == 0 || qcTx.nVersion > CFinalCommitmentTxPayload::CURRENT_VERSION) { LogPrintfFinalCommitment("h[%d] invalid qcTx.nVersion[%d]\n", pindexPrev->nHeight, qcTx.nVersion); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-version"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-version"); } if (qcTx.nHeight != uint32_t(pindexPrev->nHeight + 1)) { LogPrintfFinalCommitment("h[%d] invalid qcTx.nHeight[%d]\n", pindexPrev->nHeight, qcTx.nHeight); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-height"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-height"); } const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash)); if (pQuorumBaseBlockIndex == nullptr) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-quorum-hash"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-quorum-hash"); } if (pQuorumBaseBlockIndex != pindexPrev->GetAncestor(pQuorumBaseBlockIndex->nHeight)) { // not part of active chain - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-quorum-hash"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-quorum-hash"); } if (qcTx.commitment.IsNull()) { if (!qcTx.commitment.VerifyNull()) { LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid-null"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-invalid-null"); } return true; } if (!qcTx.commitment.Verify(pQuorumBaseBlockIndex, false)) { LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] Verify failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString()); - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-qc-invalid"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-invalid"); } LogPrintfFinalCommitment("h[%d] CheckLLMQCommitment VALID\n", pindexPrev->nHeight); diff --git a/src/llmq/commitment.h b/src/llmq/commitment.h index 8021ae550e..1a3cd84950 100644 --- a/src/llmq/commitment.h +++ b/src/llmq/commitment.h @@ -15,7 +15,7 @@ #include class CBlockIndex; -class CValidationState; +class TxValidationState; namespace llmq { @@ -168,7 +168,7 @@ public: } }; -bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state); +bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state); } // namespace llmq diff --git a/src/llmq/instantsend.cpp b/src/llmq/instantsend.cpp index d39fb1db88..8e453ead4b 100644 --- a/src/llmq/instantsend.cpp +++ b/src/llmq/instantsend.cpp @@ -1477,7 +1477,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const LogPrintf("CInstantSendManager::%s -- invalidating block %s\n", __func__, pindex->GetBlockHash().ToString()); - CValidationState state; + BlockValidationState state; // need non-const pointer auto pindex2 = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(pindex->GetBlockHash())); if (!::ChainstateActive().InvalidateBlock(state, Params(), pindex2)) { @@ -1495,7 +1495,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const } if (activateBestChain) { - CValidationState state; + BlockValidationState state; if (!::ChainstateActive().ActivateBestChain(state, Params())) { LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(state)); // This should not have happened and we are in a state were it's not safe to continue anymore diff --git a/src/miner.cpp b/src/miner.cpp index 3e4b4171ec..9673c8a2bc 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -205,7 +205,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(CChainState& chai cbTx.nHeight = nHeight; - CValidationState state; + BlockValidationState state; if (!CalcCbTxMerkleRootMNList(*pblock, pindexPrev, cbTx.merkleRootMNList, state, ::ChainstateActive().CoinsTip())) { throw std::runtime_error(strprintf("%s: CalcCbTxMerkleRootMNList failed: %s", __func__, FormatStateMessage(state))); } @@ -233,8 +233,8 @@ std::unique_ptr BlockAssembler::CreateNewBlock(CChainState& chai pblocktemplate->nPrevBits = pindexPrev->nBits; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]); - CValidationState state; assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate)); + BlockValidationState state; if (!TestBlockValidity(state, m_clhandler, m_evoDb, chainparams, chainstate, *pblock, pindexPrev, false, false)) { throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); } diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 152bd572e4..dfe8442226 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1222,7 +1222,7 @@ bool IsBanned(NodeId pnode) } /** - * Potentially mark a node discouraged based on the contents of a CValidationState object + * Potentially mark a node discouraged based on the contents of a BlockValidationState object * * @param[in] via_compact_block this bool is passed in because net_processing should * punish peers differently depending on whether the data was provided in a compact @@ -1231,20 +1231,20 @@ bool IsBanned(NodeId pnode) * * @return Returns true if the peer was punished (probably disconnected) */ -static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool via_compact_block, const std::string& message = "") +static bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, bool via_compact_block, const std::string& message = "") { - switch (state.GetReason()) { - case ValidationInvalidReason::NONE: + switch (state.GetResult()) { + case BlockValidationResult::BLOCK_RESULT_UNSET: break; // The node is providing invalid data: - case ValidationInvalidReason::CONSENSUS: - case ValidationInvalidReason::BLOCK_MUTATED: + case BlockValidationResult::BLOCK_CONSENSUS: + case BlockValidationResult::BLOCK_MUTATED: if (!via_compact_block) { Misbehaving(nodeid, 100, message); return true; } break; - case ValidationInvalidReason::CACHED_INVALID: + case BlockValidationResult::BLOCK_CACHED_INVALID: { LOCK(cs_main); CNodeState *node_state = State(nodeid); @@ -1260,25 +1260,18 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v } break; } - case ValidationInvalidReason::BLOCK_INVALID_HEADER: - case ValidationInvalidReason::BLOCK_CHECKPOINT: - case ValidationInvalidReason::BLOCK_INVALID_PREV: + case BlockValidationResult::BLOCK_INVALID_HEADER: + case BlockValidationResult::BLOCK_CHECKPOINT: + case BlockValidationResult::BLOCK_INVALID_PREV: Misbehaving(nodeid, 100, message); return true; // Conflicting (but not necessarily invalid) data or different policy: - case ValidationInvalidReason::BLOCK_MISSING_PREV: - case ValidationInvalidReason::BLOCK_CHAINLOCK: - case ValidationInvalidReason::TX_BAD_SPECIAL: - case ValidationInvalidReason::TX_CONFLICT_LOCK: + case BlockValidationResult::BLOCK_MISSING_PREV: + case BlockValidationResult::BLOCK_CHAINLOCK: Misbehaving(nodeid, 10, message); return true; - case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE: - case ValidationInvalidReason::BLOCK_TIME_FUTURE: - case ValidationInvalidReason::TX_NOT_STANDARD: - case ValidationInvalidReason::TX_MISSING_INPUTS: - case ValidationInvalidReason::TX_PREMATURE_SPEND: - case ValidationInvalidReason::TX_CONFLICT: - case ValidationInvalidReason::TX_MEMPOOL_POLICY: + case BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE: + case BlockValidationResult::BLOCK_TIME_FUTURE: break; } if (message != "") { @@ -1287,6 +1280,41 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v return false; } +/** + * Potentially ban a node based on the contents of a TxValidationState object + * + * @return Returns true if the peer was punished (probably disconnected) + * + * Changes here may need to be reflected in TxRelayMayResultInDisconnect(). + */ +static bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "") { + switch (state.GetResult()) { + case TxValidationResult::TX_RESULT_UNSET: + break; + // The node is providing invalid data: + case TxValidationResult::TX_CONSENSUS: + { + LOCK(cs_main); + Misbehaving(nodeid, 100, message); + return true; + } + // Conflicting (but not necessarily invalid) data or different policy: + case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE: + case TxValidationResult::TX_NOT_STANDARD: + case TxValidationResult::TX_MISSING_INPUTS: + case TxValidationResult::TX_PREMATURE_SPEND: + case TxValidationResult::TX_CONFLICT: + case TxValidationResult::TX_MEMPOOL_POLICY: + // moved from BLOCK + case TxValidationResult::TX_BAD_SPECIAL: + case TxValidationResult::TX_CONFLICT_LOCK: + break; + } + if (message != "") { + LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message); + } + return false; +} ////////////////////////////////////////////////////////////////////////////// // @@ -1507,7 +1535,7 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB * Handle invalid block rejection and consequent peer discouragement, maintain which * peers announce compact blocks. */ -void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationState& state) { +void PeerLogicValidation::BlockChecked(const CBlock& block, const BlockValidationState& state) { LOCK(cs_main); const uint256 hash(block.GetHash()); @@ -1518,7 +1546,7 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta if (state.IsInvalid() && it != mapBlockSource.end() && State(it->second.first)) { - MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second); + MaybePunishNodeForBlock(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second); } // Check that: // 1. The block is valid @@ -1711,7 +1739,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c } } // release cs_main before calling ActivateBestChain if (need_activate_chain) { - CValidationState state; + BlockValidationState state; if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) { LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state)); } @@ -2127,11 +2155,10 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan } } - CValidationState state; - CBlockHeader first_invalid_header; - if (!chainman.ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) { + BlockValidationState state; + if (!chainman.ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) { if (state.IsInvalid()) { - MaybePunishNode(pfrom.GetId(), state, via_compact_block, "invalid header received"); + MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received"); return; } } @@ -2266,14 +2293,13 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::setsecond.tx; const CTransaction& orphanTx = *porphanTx; NodeId fromPeer = orphan_it->second.fromPeer; - bool fMissingInputs2 = false; - // Use a new CValidationState because orphans come from different peers (and we call - // MaybePunishNode based on the source peer from the orphan map, not based on the peer + // Use a new TxValidationState because orphans come from different peers (and we call + // MaybePunishNodeForTx based on the source peer from the orphan map, not based on the peer // that relayed the previous transaction). - CValidationState orphan_state; + TxValidationState orphan_state; if (setMisbehaving.count(fromPeer)) continue; - if (AcceptToMemoryPool(::ChainstateActive(), mempool, orphan_state, porphanTx, &fMissingInputs2 /* pfMissingInputs */, + if (AcceptToMemoryPool(::ChainstateActive(), mempool, orphan_state, porphanTx, false /* bypass_limits */, 0 /* nAbsurdFee */)) { LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString()); RelayTransaction(orphanTx.GetHash(), connman); @@ -2287,10 +2313,10 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::setinsert(orphanHash); EraseOrphanTx(orphanHash); @@ -3130,7 +3155,7 @@ void PeerLogicValidation::ProcessMessage( LOCK(cs_most_recent_block); a_recent_block = most_recent_block; } - CValidationState state; + BlockValidationState state; if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) { LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state)); } @@ -3346,10 +3371,9 @@ void PeerLogicValidation::ProcessMessage( LOCK2(cs_main, g_cs_orphans); - bool fMissingInputs = false; - CValidationState state; + TxValidationState state; - if (!AlreadyHave(inv, m_mempool, *m_llmq_ctx) && AcceptToMemoryPool(::ChainstateActive(), m_mempool, state, ptx, &fMissingInputs /* pfMissingInputs */, + if (!AlreadyHave(inv, m_mempool, *m_llmq_ctx) && AcceptToMemoryPool(::ChainstateActive(), m_mempool, state, ptx, false /* bypass_limits */, 0 /* nAbsurdFee */)) { // Process custom txes, this changes AlreadyHave to "true" if (nInvType == MSG_DSTX) { @@ -3380,7 +3404,7 @@ void PeerLogicValidation::ProcessMessage( // Recursively process any orphan transactions that depended on this one ProcessOrphanTx(m_connman, m_mempool, pfrom.orphan_work_set); } - else if (fMissingInputs) + else if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected for (const CTxIn& txin : tx.vin) { @@ -3417,7 +3441,6 @@ void PeerLogicValidation::ProcessMessage( m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx); } } else { - assert(IsTransactionReason(state.GetReason())); assert(recentRejects); recentRejects->insert(tx.GetHash()); if (RecursiveDynamicUsage(*ptx) < 100000) { @@ -3460,7 +3483,7 @@ void PeerLogicValidation::ProcessMessage( LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(), pfrom.GetId(), FormatStateMessage(state)); - MaybePunishNode(pfrom.GetId(), state, /*via_compact_block*/ false); + MaybePunishNodeForTx(pfrom.GetId(), state); m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx); } return; @@ -3495,10 +3518,10 @@ void PeerLogicValidation::ProcessMessage( } const CBlockIndex *pindex = nullptr; - CValidationState state; + BlockValidationState state; if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) { if (state.IsInvalid()) { - MaybePunishNode(pfrom.GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock"); + MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock"); return; } } diff --git a/src/net_processing.h b/src/net_processing.h index 2f94dae0b2..4932f9267d 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -52,7 +52,7 @@ public: /** * Overridden from CValidationInterface. */ - void BlockChecked(const CBlock& block, const CValidationState& state) override; + void BlockChecked(const CBlock& block, const BlockValidationState& state) override; /** * Overridden from CValidationInterface. */ diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp index 21d762c51d..82f42ccc44 100644 --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -39,18 +39,16 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t } if (!node.mempool->exists(hashTx)) { // Transaction is not already in the mempool. Submit it. - CValidationState state; - bool fMissingInputs; - if (!AcceptToMemoryPool(::ChainstateActive(), *node.mempool, state, std::move(tx), &fMissingInputs, + TxValidationState state; + if (!AcceptToMemoryPool(::ChainstateActive(), *node.mempool, state, std::move(tx), bypass_limits, max_tx_fee)) { + err_string = FormatStateMessage(state); if (state.IsInvalid()) { - err_string = FormatStateMessage(state); - return TransactionError::MEMPOOL_REJECTED; - } else { - if (fMissingInputs) { + if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { return TransactionError::MISSING_INPUTS; } - err_string = FormatStateMessage(state); + return TransactionError::MEMPOOL_REJECTED; + } else { return TransactionError::MEMPOOL_ERROR; } } diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 3a9101bbc5..732e89066e 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1811,7 +1811,7 @@ static UniValue preciousblock(const JSONRPCRequest& request) } } - CValidationState state; + BlockValidationState state; ::ChainstateActive().PreciousBlock(state, Params(), pblockindex); if (!state.IsValid()) { @@ -1836,7 +1836,7 @@ static UniValue invalidateblock(const JSONRPCRequest& request) }.Check(request); uint256 hash(ParseHashV(request.params[0], "blockhash")); - CValidationState state; + BlockValidationState state; CBlockIndex* pblockindex; { @@ -1886,7 +1886,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request) ::ChainstateActive().ResetBlockFailureFlags(pblockindex); } - CValidationState state; + BlockValidationState state; ::ChainstateActive().ActivateBestChain(state, Params()); if (!state.IsValid()) { diff --git a/src/rpc/evo.cpp b/src/rpc/evo.cpp index 58dff88ebc..66420c8708 100644 --- a/src/rpc/evo.cpp +++ b/src/rpc/evo.cpp @@ -326,7 +326,7 @@ static std::string SignAndSendSpecialTx(const JSONRPCRequest& request, const CMu { LOCK(cs_main); - CValidationState state; + TxValidationState state; if (!CheckSpecialTx(CTransaction(tx), ::ChainActive().Tip(), state, ::ChainstateActive().CoinsTip(), true)) { throw std::runtime_error(FormatStateMessage(state)); } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 6e540ee417..f7463c1a32 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -380,7 +380,7 @@ static UniValue generateblock(const JSONRPCRequest& request) { LOCK(cs_main); - CValidationState state; + BlockValidationState state; if (!TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, chainparams, ::ChainstateActive(), block, g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) { throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.GetRejectReason())); } @@ -483,7 +483,7 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request) // NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller -static UniValue BIP22ValidationResult(const CValidationState& state) +static UniValue BIP22ValidationResult(const BlockValidationState& state) { if (state.IsValid()) return NullUniValue; @@ -670,7 +670,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) // TestBlockValidity only supports blocks built on the current Tip if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; - CValidationState state; + BlockValidationState state; TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, Params(), ::ChainstateActive(), block, pindexPrev, false, true); return BIP22ValidationResult(state); } @@ -951,12 +951,12 @@ class submitblock_StateCatcher : public CValidationInterface public: uint256 hash; bool found; - CValidationState state; + BlockValidationState state; explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {} protected: - void BlockChecked(const CBlock& block, const CValidationState& stateIn) override { + void BlockChecked(const CBlock& block, const BlockValidationState& stateIn) override { if (block.GetHash() != hash) return; found = true; @@ -1046,8 +1046,8 @@ static UniValue submitheader(const JSONRPCRequest& request) } } - CValidationState state; - EnsureChainman(request.context).ProcessNewBlockHeaders({h}, state, Params(), /* ppindex */ nullptr, /* first_invalid */ nullptr); + BlockValidationState state; + EnsureChainman(request.context).ProcessNewBlockHeaders({h}, state, Params()); if (state.IsValid()) return NullUniValue; if (state.IsError()) { throw JSONRPCError(RPC_VERIFY_ERROR, FormatStateMessage(state)); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 0392695503..31f43579f6 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -918,20 +918,21 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) UniValue result_0(UniValue::VOBJ); result_0.pushKV("txid", tx_hash.GetHex()); - CValidationState state; - bool missing_inputs; + TxValidationState state; bool test_accept_res; { LOCK(cs_main); - test_accept_res = AcceptToMemoryPool(::ChainstateActive(), mempool, state, std::move(tx), &missing_inputs, + test_accept_res = AcceptToMemoryPool(::ChainstateActive(), mempool, state, std::move(tx), false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true); } result_0.pushKV("allowed", test_accept_res); if (!test_accept_res) { if (state.IsInvalid()) { - result_0.pushKV("reject-reason", strprintf("%s", state.GetRejectReason())); - } else if (missing_inputs) { - result_0.pushKV("reject-reason", "missing-inputs"); + if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { + result_0.pushKV("reject-reason", "missing-inputs"); + } else { + result_0.pushKV("reject-reason", strprintf("%s", state.GetRejectReason())); + } } else { result_0.pushKV("reject-reason", state.GetRejectReason()); } diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index 63fb2e39a2..a208a0e6a0 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -100,8 +100,8 @@ bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex, block = std::make_shared(CreateBlock(pindex, no_txns, coinbase_script_pub_key)); CBlockHeader header = block->GetBlockHeader(); - CValidationState state; - if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, state, Params(), &pindex, nullptr)) { + BlockValidationState state; + if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, state, Params(), &pindex)) { return false; } } diff --git a/src/test/evo_deterministicmns_tests.cpp b/src/test/evo_deterministicmns_tests.cpp index ba1a293db4..95f7f11550 100644 --- a/src/test/evo_deterministicmns_tests.cpp +++ b/src/test/evo_deterministicmns_tests.cpp @@ -294,12 +294,12 @@ void FuncDIP3Protx(TestChainSetup& setup) // payload itself. This means, we need to rely on script verification, which takes the hash of the extra payload // into account auto tx2 = MalleateProTxPayout(tx); - CValidationState dummyState; + TxValidationState dummy_state; // Technically, the payload is still valid... { LOCK(cs_main); - BOOST_ASSERT(CheckProRegTx(CTransaction(tx), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true)); - BOOST_ASSERT(CheckProRegTx(CTransaction(tx2), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true)); + BOOST_ASSERT(CheckProRegTx(CTransaction(tx), ::ChainActive().Tip(), dummy_state, ::ChainstateActive().CoinsTip(), true)); + BOOST_ASSERT(CheckProRegTx(CTransaction(tx2), ::ChainActive().Tip(), dummy_state, ::ChainstateActive().CoinsTip(), true)); } // But the signature should not verify anymore BOOST_ASSERT(CheckTransactionSignature(*(setup.m_node.mempool), tx)); @@ -401,11 +401,11 @@ void FuncDIP3Protx(TestChainSetup& setup) tx = CreateProUpRegTx(*(setup.m_node.mempool), utxos, dmnHashes[0], ownerKeys[dmnHashes[0]], newOperatorKey.GetPublicKey(), ownerKeys[dmnHashes[0]].GetPubKey().GetID(), dmn->pdmnState->scriptPayout, setup.coinbaseKey); // check malleability protection again, but this time by also relying on the signature inside the ProUpRegTx auto tx2 = MalleateProTxPayout(tx); - CValidationState dummyState; + TxValidationState dummy_state; { LOCK(cs_main); - BOOST_ASSERT(CheckProUpRegTx(CTransaction(tx), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true)); - BOOST_ASSERT(!CheckProUpRegTx(CTransaction(tx2), ::ChainActive().Tip(), dummyState, ::ChainstateActive().CoinsTip(), true)); + BOOST_ASSERT(CheckProUpRegTx(CTransaction(tx), ::ChainActive().Tip(), dummy_state, ::ChainstateActive().CoinsTip(), true)); + BOOST_ASSERT(!CheckProUpRegTx(CTransaction(tx2), ::ChainActive().Tip(), dummy_state, ::ChainstateActive().CoinsTip(), true)); } BOOST_ASSERT(CheckTransactionSignature(*(setup.m_node.mempool), tx)); BOOST_ASSERT(!CheckTransactionSignature(*(setup.m_node.mempool), tx2)); diff --git a/src/test/fuzz/block.cpp b/src/test/fuzz/block.cpp index 218d6c5e2b..3304ef2090 100644 --- a/src/test/fuzz/block.cpp +++ b/src/test/fuzz/block.cpp @@ -36,17 +36,17 @@ FUZZ_TARGET_INIT(block, initialize_block) return; } const Consensus::Params& consensus_params = Params().GetConsensus(); - CValidationState validation_state_pow_and_merkle; + BlockValidationState validation_state_pow_and_merkle; const bool valid_incl_pow_and_merkle = CheckBlock(block, validation_state_pow_and_merkle, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ true); assert(validation_state_pow_and_merkle.IsValid() || validation_state_pow_and_merkle.IsInvalid() || validation_state_pow_and_merkle.IsError()); (void)validation_state_pow_and_merkle.Error(""); - CValidationState validation_state_pow; + BlockValidationState validation_state_pow; const bool valid_incl_pow = CheckBlock(block, validation_state_pow, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ false); assert(validation_state_pow.IsValid() || validation_state_pow.IsInvalid() || validation_state_pow.IsError()); - CValidationState validation_state_merkle; + BlockValidationState validation_state_merkle; const bool valid_incl_merkle = CheckBlock(block, validation_state_merkle, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ true); assert(validation_state_merkle.IsValid() || validation_state_merkle.IsInvalid() || validation_state_merkle.IsError()); - CValidationState validation_state_none; + BlockValidationState validation_state_none; const bool valid_incl_none = CheckBlock(block, validation_state_none, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ false); assert(validation_state_none.IsValid() || validation_state_none.IsInvalid() || validation_state_none.IsError()); if (valid_incl_pow_and_merkle) { diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index 748c4c29a7..69bcfb97c9 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -223,12 +223,12 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view) (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache); }, [&] { - CValidationState state; + TxValidationState state; CAmount tx_fee_out; const CTransaction transaction{random_mutable_transaction}; if (ContainsSpentInput(transaction, coins_view_cache)) { // Avoid: - // consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, CValidationState &, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed. + // consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, TxValidationState&, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed. return; } try { diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp index 1366df9313..160a5369f2 100644 --- a/src/test/fuzz/transaction.cpp +++ b/src/test/fuzz/transaction.cpp @@ -60,7 +60,7 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction) return; } - CValidationState state_with_dupe_check; + TxValidationState state_with_dupe_check; (void)CheckTransaction(tx, state_with_dupe_check); std::string reason; diff --git a/src/test/interfaces_tests.cpp b/src/test/interfaces_tests.cpp index 97231003bb..a60f4c4629 100644 --- a/src/test/interfaces_tests.cpp +++ b/src/test/interfaces_tests.cpp @@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE(findCommonAncestor) const CChain& active = Assert(m_node.chainman)->ActiveChain(); auto* orig_tip = active.Tip(); for (int i = 0; i < 10; ++i) { - CValidationState state; + BlockValidationState state; ChainstateActive().InvalidateBlock(state, Params(), active.Tip()); } BOOST_CHECK_EQUAL(active.Height(), orig_tip->nHeight - 10); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 91f3a10613..dacf12688d 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -536,7 +536,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U); } // unlock cs_main while calling InvalidateBlock - CValidationState state; + BlockValidationState state; ::ChainstateActive().InvalidateBlock(state, chainparams, WITH_LOCK(cs_main, return ::ChainActive().Tip())); SetMockTime(0); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 5c4b0f4433..3ecf337964 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -187,7 +187,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data) CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION); stream >> tx; - CValidationState state; + TxValidationState state; BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest); BOOST_CHECK(state.IsValid()); diff --git a/src/test/specialtx_tests.cpp b/src/test/specialtx_tests.cpp index 773d1a47cd..04dc3329af 100644 --- a/src/test/specialtx_tests.cpp +++ b/src/test/specialtx_tests.cpp @@ -18,15 +18,15 @@ #include -bool VerifyMNHFTx(const CTransaction& tx, CValidationState& state) +bool VerifyMNHFTx(const CTransaction& tx, TxValidationState& state) { MNHFTxPayload mnhfTx; if (!GetTxPayload(tx, mnhfTx)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-payload"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-payload"); } if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-mnhf-version"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-version"); } return true; @@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(verify_mnhf_specialtx_tests) BOOST_CHECK(sig.VerifyInsecure(ag_pk, verHash)); const CMutableTransaction tx = CreateMNHFTx(hash, sig, ver); - CValidationState state; + TxValidationState state; BOOST_CHECK(VerifyMNHFTx(CTransaction(tx), state)); } diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index ee54b792da..d130f5cc37 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -137,7 +137,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION); CTransaction tx(deserialize, stream); - CValidationState state; + TxValidationState state; BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest); BOOST_CHECK(state.IsValid()); @@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION); CTransaction tx(deserialize, stream); - CValidationState state; + TxValidationState state; fValid = CheckTransaction(tx, state) && state.IsValid(); PrecomputedTransactionData txdata(tx); @@ -245,7 +245,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests) CDataStream stream(vch, SER_DISK, CLIENT_VERSION); CMutableTransaction tx; stream >> tx; - CValidationState state; + TxValidationState state; BOOST_CHECK_MESSAGE(CheckTransaction(CTransaction(tx), state) && state.IsValid(), "Simple deserialized transaction should be valid."); // Check that duplicate txins fail diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp index fdb2b4a8c0..58fdbfd134 100644 --- a/src/test/txvalidation_tests.cpp +++ b/src/test/txvalidation_tests.cpp @@ -30,7 +30,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup) BOOST_CHECK(CTransaction(coinbaseTx).IsCoinBase()); - CValidationState state; + TxValidationState state; LOCK(cs_main); @@ -39,7 +39,6 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup) BOOST_CHECK_EQUAL( false, AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, state, MakeTransactionRef(coinbaseTx), - nullptr /* pfMissingInputs */, true /* bypass_limits */, 0 /* nAbsurdFee */)); @@ -49,7 +48,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup) // Check that the validation state reflects the unsuccessful attempt. BOOST_CHECK(state.IsInvalid()); BOOST_CHECK_EQUAL(state.GetRejectReason(), "coinbase"); - BOOST_CHECK(state.GetReason() == ValidationInvalidReason::CONSENSUS); + BOOST_CHECK(state.GetResult() == TxValidationResult::TX_CONSENSUS); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 39f74e4acf..f794180876 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -12,7 +12,7 @@ #include -bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks); +bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks); BOOST_AUTO_TEST_SUITE(txvalidationcache_tests) @@ -27,8 +27,8 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) const auto ToMemPool = [this](const CMutableTransaction& tx) { LOCK(cs_main); - CValidationState state; - return AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, state, MakeTransactionRef(tx), nullptr /* pfMissingInputs */, + TxValidationState validationState; + return AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, validationState, MakeTransactionRef(tx), true /* bypass_limits */, 0 /* nAbsurdFee */); }; @@ -111,7 +111,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail // If we add many more flags, this loop can get too expensive, but we can // rewrite in the future to randomly pick a set of flags to evaluate. for (uint32_t test_flags=0; test_flags < (1U << 16); test_flags += 1) { - CValidationState state; + TxValidationState state; // Filter out incompatible flag choices if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) { // CLEANSTACK requires P2SH, see VerifyScript() in @@ -193,7 +193,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) { LOCK(cs_main); - CValidationState state; + TxValidationState state; PrecomputedTransactionData ptd_spend_tx; BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr)); @@ -262,7 +262,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Make it valid, and check again invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100; - CValidationState state; + TxValidationState state; PrecomputedTransactionData txdata; BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr)); } @@ -290,7 +290,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Make it valid, and check again invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100; - CValidationState state; + TxValidationState state; PrecomputedTransactionData txdata; BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr)); } diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 36f7156f12..ecda0359c0 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -253,7 +253,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vectorInit(options); } - CValidationState state; + BlockValidationState state; if (!::ChainstateActive().ActivateBestChain(state, chainparams)) { throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", FormatStateMessage(state))); } @@ -338,7 +338,7 @@ CBlock TestChainSetup::CreateBlock(const std::vector& txns, if (!GetTxPayload(*block.vtx[0], cbTx)) { BOOST_ASSERT(false); } - CValidationState state; + BlockValidationState state; if (!CalcCbTxMerkleRootMNList(block, ::ChainActive().Tip(), cbTx.merkleRootMNList, state, ::ChainstateActive().CoinsTip())) { BOOST_ASSERT(false); } diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index becce21a2b..d8949833e2 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering) } bool ignored; - CValidationState state; + BlockValidationState state; std::vector headers; std::transform(blocks.begin(), blocks.end(), std::back_inserter(headers), [](std::shared_ptr b) { return b->GetBlockHeader(); }); @@ -296,14 +296,13 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg) // Add the txs to the tx pool { LOCK(cs_main); - CValidationState state; + TxValidationState state; for (const auto& tx : txs) { BOOST_REQUIRE(AcceptToMemoryPool( ::ChainstateActive(), *m_node.mempool, state, tx, - /* pfMissingInputs */ &ignored, /* bypass_limits */ false, /* nAbsurdFee */ 0)); } diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index 069fdaf229..22b97d9e5e 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -67,8 +67,8 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) WITH_LOCK(::cs_main, c2.InitCoinsCache(1 << 23)); // Unlike c1, which doesn't have any blocks. Gets us different tip, height. c2.LoadGenesisBlock(chainparams); - CValidationState _; - BOOST_CHECK(c2.ActivateBestChain(_, chainparams, nullptr)); + BlockValidationState dummy_state; + BOOST_CHECK(c2.ActivateBestChain(dummy_state, chainparams, nullptr)); BOOST_CHECK(manager.IsSnapshotActive()); BOOST_CHECK(!manager.IsSnapshotValidated()); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index d8a1e21d01..cf106b6b2a 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1023,9 +1023,9 @@ void CTxMemPool::clear() static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& mempoolDuplicate, const int64_t spendheight) { - CValidationState state; + TxValidationState dummy_state; // Not used. CheckTxInputs() should always pass CAmount txfee = 0; - bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, txfee); + bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, txfee); assert(fCheckResult); UpdateCoins(tx, mempoolDuplicate, std::numeric_limits::max()); } diff --git a/src/util/validation.cpp b/src/util/validation.cpp index 0992ca658f..8c0bf9bb88 100644 --- a/src/util/validation.cpp +++ b/src/util/validation.cpp @@ -8,8 +8,8 @@ #include #include -/** Convert CValidationState to a human-readable message for logging */ -std::string FormatStateMessage(const CValidationState &state) +/** Convert ValidationState to a human-readable message for logging */ +std::string FormatStateMessage(const ValidationState &state) { return strprintf("%s%s", state.GetRejectReason(), diff --git a/src/util/validation.h b/src/util/validation.h index 986d582d1f..5ee260a055 100644 --- a/src/util/validation.h +++ b/src/util/validation.h @@ -8,9 +8,9 @@ #include -class CValidationState; +class ValidationState; -/** Convert CValidationState to a human-readable message for logging */ -std::string FormatStateMessage(const CValidationState &state); +/** Convert ValidationState to a human-readable message for logging */ +std::string FormatStateMessage(const ValidationState &state); #endif // BITCOIN_UTIL_VALIDATION_H diff --git a/src/validation.cpp b/src/validation.cpp index 79c555efd0..a29d59b286 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -200,7 +200,7 @@ CBlockIndex* BlockManager::FindForkInGlobalIndex(const CChain& chain, const CBlo std::unique_ptr pblocktree; -bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks = nullptr); +bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks = nullptr); static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false); static FlatFileSeq BlockFileSeq(); static FlatFileSeq UndoFileSeq(); @@ -361,8 +361,7 @@ int GetUTXOConfirmations(const COutPoint& outpoint) return (nPrevoutHeight > -1 && ::ChainActive().Tip()) ? ::ChainActive().Height() - nPrevoutHeight + 1 : -1; } - -bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) +static bool ContextualCheckTransaction(const CTransaction& tx, TxValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) { int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1; bool fDIP0001Active_context = nHeight >= consensusParams.DIP0001Height; @@ -379,18 +378,18 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, tx.nType != TRANSACTION_COINBASE && tx.nType != TRANSACTION_QUORUM_COMMITMENT && tx.nType != TRANSACTION_MNHF_SIGNAL) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-type"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-type"); } if (tx.IsCoinBase() && tx.nType != TRANSACTION_COINBASE) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-cb-type"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-cb-type"); } else if (tx.nType != TRANSACTION_NORMAL) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-type"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-type"); } } // Size limits if (fDIP0001Active_context && ::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_STANDARD_TX_SIZE) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-oversize"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-oversize"); return true; } @@ -454,9 +453,9 @@ static void UpdateMempoolForReorg(CChainState& active_chainstate, CTxMemPool& me auto it = disconnectpool.queuedTx.get().rbegin(); while (it != disconnectpool.queuedTx.get().rend()) { // ignore validation errors in resurrected transactions - CValidationState stateDummy; + TxValidationState stateDummy; if (!fAddToMempool || (*it)->IsCoinBase() || - !AcceptToMemoryPool(active_chainstate, mempool, stateDummy, *it, nullptr /* pfMissingInputs */, + !AcceptToMemoryPool(active_chainstate, mempool, stateDummy, *it, true /* bypass_limits */, 0 /* nAbsurdFee */)) { // If the transaction doesn't make it in to the mempool, remove any // transactions that depend on it (which would now be orphans). @@ -482,7 +481,7 @@ static void UpdateMempoolForReorg(CChainState& active_chainstate, CTxMemPool& me // Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool // were somehow broken and returning the wrong scriptPubKeys -static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationState& state, +static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& view, const CTxMemPool& pool, unsigned int flags, PrecomputedTransactionData& txdata, CCoinsViewCache& coins_tip) EXCLUSIVE_LOCKS_REQUIRED(cs_main) @@ -538,8 +537,7 @@ public: // around easier. struct ATMPArgs { const CChainParams& m_chainparams; - CValidationState &m_state; - bool* m_missing_inputs; + TxValidationState &m_state; const int64_t m_accept_time; const bool m_bypass_limits; const CAmount& m_absurd_fee; @@ -593,15 +591,15 @@ private: bool Finalize(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); // Compare a package's feerate against minimum allowed. - bool CheckFeeRate(size_t package_size, CAmount package_fee, CValidationState& state) + bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) { CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size); if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) { - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee)); + return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee)); } if (package_fee < ::minRelayTxFee.GetFee(package_size)) { - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size))); + return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size))); } return true; } @@ -630,8 +628,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // Copy/alias what we need out of args const CChainParams& chainparams = args.m_chainparams; - CValidationState &state = args.m_state; - bool* pfMissingInputs = args.m_missing_inputs; + TxValidationState &state = args.m_state; const int64_t nAcceptTime = args.m_accept_time; const bool bypass_limits = args.m_bypass_limits; const CAmount& nAbsurdFee = args.m_absurd_fee; @@ -642,10 +639,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) std::unique_ptr& entry = ws.m_entry; CAmount& nModifiedFees = ws.m_modified_fees; - if (pfMissingInputs) { - *pfMissingInputs = false; - } - if (!CheckTransaction(tx, state)) return false; // state filled in by CheckTransaction @@ -655,35 +648,35 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) if (tx.nVersion == 3 && tx.nType == TRANSACTION_QUORUM_COMMITMENT) { // quorum commitment is not allowed outside of blocks - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "qc-not-allowed"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "qc-not-allowed"); } // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "coinbase"); + return state.Invalid(TxValidationResult::TX_CONSENSUS, "coinbase"); // Rather not work on nonstandard transactions (unless -testnet/-regtest) std::string reason; if (fRequireStandard && !IsStandardTx(tx, reason)) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, reason); + return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason); // Do not work on transactions that are too small. // A transaction with 1 empty scriptSig input and 1 P2SH output has size of 83 bytes. // Transactions smaller than this are not relayed to mitigate CVE-2017-12842 by not relaying // 64-byte transactions. if (::GetSerializeSize(tx, PROTOCOL_VERSION) < MIN_STANDARD_TX_SIZE) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "tx-size-small"); + return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "tx-size-small"); // Only accept nLockTime-using transactions that can be mined in the next // block; we don't want our mempool filled up with transactions that can't // be mined yet. if (!CheckFinalTx(m_active_chainstate.m_chain.Tip(), tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) - return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "non-final"); + return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-final"); // is it already in the memory pool? if (m_pool.exists(hash)) { statsClient.inc("transactions.duplicate", 1.0f); - return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-already-in-mempool"); + return state.Invalid(TxValidationResult::TX_CONFLICT, "txn-already-in-mempool"); } llmq::CInstantSendLockPtr conflictLock = llmq::quorumInstantSendManager->GetConflictingLock(tx); @@ -693,7 +686,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) if (txConflict) { GetMainSignals().NotifyInstantSendDoubleSpendAttempt(ptx, txConflict); } - return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("AcceptToMemoryPool : Transaction %s conflicts with locked TX %s", hash.ToString(), conflictLock->txid.ToString()), "tx-txlock-conflict"); + LogPrintf("ERROR: AcceptToMemoryPool : Transaction %s conflicts with locked TX %s\n", hash.ToString(), conflictLock->txid.ToString()); + return state.Invalid(TxValidationResult::TX_CONFLICT_LOCK, "tx-txlock-conflict"); } if (llmq::quorumInstantSendManager->IsWaitingForTx(hash)) { @@ -707,7 +701,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) if (ptxConflicting) { // Transaction conflicts with mempool and RBF doesn't exist in Dash - return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-mempool-conflict"); + return state.Invalid(TxValidationResult::TX_CONFLICT, "txn-mempool-conflict"); } } } @@ -731,14 +725,11 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) for (size_t out = 0; out < tx.vout.size(); out++) { // Optimistically just do efficient check of cache for outputs if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) { - return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-already-known"); + return state.Invalid(TxValidationResult::TX_CONFLICT, "txn-already-known"); } } // Otherwise assume this might be an orphan tx for which we just haven't seen parents yet - if (pfMissingInputs) { - *pfMissingInputs = true; - } - return false; // fMissingInputs and !state.IsInvalid() is used to detect this condition, don't set state.Invalid() + return state.Invalid(TxValidationResult::TX_MISSING_INPUTS, "bad-txns-inputs-missingorspent"); } } @@ -757,7 +748,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // CoinsViewCache instead of create its own assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate)); if (!CheckSequenceLocks(m_active_chainstate, m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) - return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "non-BIP68-final"); + return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-BIP68-final"); assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_active_chainstate.m_blockman)); CAmount nFees = 0; @@ -767,7 +758,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // Check for non-standard pay-to-script-hash in inputs if (fRequireStandard && !AreInputsStandard(tx, m_view)) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "bad-txns-nonstandard-inputs"); + return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-nonstandard-inputs"); unsigned int nSigOps = GetTransactionSigOpCount(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS); @@ -792,7 +783,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) unsigned int nSize = entry->GetTxSize(); if (nSigOps > MAX_STANDARD_TX_SIGOPS) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "bad-txns-too-many-sigops", + return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops", strprintf("%d", nSigOps)); // No transactions are allowed below minRelayTxFee except from disconnected @@ -800,7 +791,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) if (!bypass_limits && !CheckFeeRate(nSize, nModifiedFees, state)) return false; if (nAbsurdFee && nFees > nAbsurdFee) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, + return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee)); // Calculate in-mempool ancestors, up to a limit. @@ -821,7 +812,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || !m_pool.CalculateMemPoolAncestors(*entry, setAncestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) { - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "too-long-mempool-chain", errString); + return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", errString); } } @@ -833,7 +824,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) return false; if (m_pool.existsProviderTxConflict(tx)) { - return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "protx-dup"); + return state.Invalid(TxValidationResult::TX_CONFLICT, "protx-dup"); } return true; @@ -843,14 +834,13 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute { const CTransaction& tx = *ws.m_ptx; - CValidationState &state = args.m_state; + TxValidationState &state = args.m_state; constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS; // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. if (!CheckInputs(tx, state, m_view, scriptVerifyFlags, true, false, txdata)) { - assert(IsTransactionReason(state.GetReason())); return false; // state filled in by CheckInputs } @@ -862,7 +852,7 @@ bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, Precomp const CTransaction& tx = *ws.m_ptx; const uint256& hash = ws.m_hash; - CValidationState &state = args.m_state; + TxValidationState &state = args.m_state; const CChainParams& chainparams = args.m_chainparams; // Check again against the current block tip's script verification @@ -894,7 +884,7 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws) { const CTransaction& tx = *ws.m_ptx; const uint256& hash = ws.m_hash; - CValidationState &state = args.m_state; + TxValidationState &state = args.m_state; const bool bypass_limits = args.m_bypass_limits; CTxMemPool::setEntries& setAncestors = ws.m_ancestors; @@ -934,7 +924,7 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws) assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(m_active_chainstate.CoinsTip())); LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip(), gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); if (!m_pool.exists(hash)) - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "mempool full"); + return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full"); } return true; } @@ -981,12 +971,12 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs } // anon namespace /** (try to) add transaction to memory pool with a specified acceptance time **/ -static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, CChainState& active_chainstate, CValidationState &state, const CTransactionRef &tx, - bool* pfMissingInputs, int64_t nAcceptTime, bool bypass_limits, +static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, CChainState& active_chainstate, TxValidationState &state, const CTransactionRef &tx, + int64_t nAcceptTime, bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { std::vector coins_to_uncache; - MemPoolAccept::ATMPArgs args { chainparams, state, pfMissingInputs, nAcceptTime, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept }; + MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept }; assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); bool res = MemPoolAccept(pool, active_chainstate).AcceptSingleTransaction(tx, args); @@ -1002,17 +992,17 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo active_chainstate.CoinsTip().Uncache(hashTx); } // After we've (potentially) uncached entries, ensure our coins cache is still within its size limits - CValidationState stateDummy; - active_chainstate.FlushStateToDisk(chainparams, stateDummy, FlushStateMode::PERIODIC); + BlockValidationState state_dummy; + active_chainstate.FlushStateToDisk(chainparams, state_dummy, FlushStateMode::PERIODIC); return res; } -bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, - bool* pfMissingInputs, bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) +bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx, + bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) { const CChainParams& chainparams = Params(); assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); - return AcceptToMemoryPoolWithTime(chainparams, pool, active_chainstate, state, tx, pfMissingInputs, GetTime(), bypass_limits, nAbsurdFee, test_accept); + return AcceptToMemoryPoolWithTime(chainparams, pool, active_chainstate, state, tx, GetTime(), bypass_limits, nAbsurdFee, test_accept); } bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector &hashes) @@ -1451,9 +1441,9 @@ void CChainState::ConflictingChainFound(CBlockIndex* pindexNew) // Same as InvalidChainFound, above, except not called directly from InvalidateBlock, // which does its own setBlockIndexCandidates manageent. -void CChainState::InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) { +void CChainState::InvalidBlockFound(CBlockIndex *pindex, const BlockValidationState &state) { statsClient.inc("warnings.InvalidBlockFound", 1.0f); - if (state.GetReason() != ValidationInvalidReason::BLOCK_MUTATED) { + if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { pindex->nStatus |= BLOCK_FAILED_VALID; m_blockman.m_failed_blocks.insert(pindex); setDirtyBlockIndex.insert(pindex); @@ -1534,7 +1524,7 @@ void InitScriptExecutionCache() { * * Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp */ -bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time(); if (tx.IsCoinBase()) return true; @@ -1592,10 +1582,10 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi CScriptCheck check2(coin.out, tx, i, (flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS) | SCRIPT_ENABLE_DIP0020_OPCODES, cacheSigStore, &txdata); if (check2()) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); + return state.Invalid(TxValidationResult::TX_NOT_STANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); } // MANDATORY flag failures correspond to - // ValidationInvalidReason::CONSENSUS. Because CONSENSUS + // TxValidationResult::TX_CONSENSUS. Because CONSENSUS // failures are the most serious case of validation // failures, we may need to consider using // RECENT_CONSENSUS_CHANGE for any script failure that @@ -1603,7 +1593,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // support, to avoid splitting the network (but this // depends on the details of how net_processing handles // such errors). - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); + return state.Invalid(TxValidationResult::TX_CONSENSUS, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); } } @@ -1690,7 +1680,7 @@ static bool AbortNode(const std::string& strMessage, bilingual_str user_message return false; } -static bool AbortNode(CValidationState& state, const std::string& strMessage, const bilingual_str& userMessage = bilingual_str()) +static bool AbortNode(BlockValidationState& state, const std::string& strMessage, const bilingual_str& userMessage = bilingual_str()) { AbortNode(strMessage, userMessage); return state.Error(strMessage); @@ -1929,9 +1919,9 @@ static void FlushBlockFile(bool fFinalize = false, bool finalize_undo = false) if (!fFinalize || finalize_undo) FlushUndoFile(nLastBlockFile, finalize_undo); } -static bool FindUndoPos(CValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize); +static bool FindUndoPos(BlockValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize); -static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, CValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams) +static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams) { // Write undo information to disk if (pindex->GetUndoPos().IsNull()) { @@ -2085,7 +2075,7 @@ static int64_t nBlocksTotal = 0; /** Apply the effects of this block (with given index) on the UTXO set represented by coins. * Validity checks that depend on the UTXO set are also done; ConnectBlock() * can fail if those validity checks fail (among other reasons). */ -bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, +bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck) { boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time(); @@ -2115,7 +2105,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl // re-enforce that rule here (at least until we make it impossible for // GetAdjustedTime() to go backward). if (!CheckBlock(block, state, chainparams.GetConsensus(), !fJustCheck, !fJustCheck)) { - if (state.GetReason() == ValidationInvalidReason::BLOCK_MUTATED) { + if (state.GetResult() == BlockValidationResult::BLOCK_MUTATED) { // We don't write down blocks to disk if they may have been // corrupted, so this should be impossible unless we're having hardware // problems. @@ -2125,7 +2115,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl } if (pindex->pprev && pindex->phashBlock && m_clhandler->HasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) { - return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: conflicting with chainlock", __func__), "bad-chainlock"); + LogPrintf("ERROR: %s: conflicting with chainlock\n", __func__); + return state.Invalid(BlockValidationResult::BLOCK_CHAINLOCK, "bad-chainlock"); } // verify that the view's current state corresponds to the previous block @@ -2213,7 +2204,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl for (const auto& tx : block.vtx) { for (size_t o = 0; o < tx->vout.size(); o++) { if (view.HaveCoin(COutPoint(tx->GetHash(), o))) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"), "bad-txns-BIP30"); + LogPrintf("ERROR: ConnectBlock(): tried to overwrite transaction\n"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-BIP30"); } } } @@ -2225,7 +2217,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl if (pindex->nHeight == chainparams.GetConsensus().nSuperblockStartBlock && chainparams.GetConsensus().nSuperblockStartHash != uint256() && block_hash != chainparams.GetConsensus().nSuperblockStartHash) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): invalid superblock start"), "bad-sb-start"); + LogPrintf("ERROR: ConnectBlock(): invalid superblock start\n"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-sb-start"); } /// END DASH @@ -2281,21 +2274,17 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl if (!tx.IsCoinBase()) { CAmount txfee = 0; - if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, txfee)) { - if (!IsBlockReason(state.GetReason())) { - // CheckTxInputs may return MISSING_INPUTS or - // PREMATURE_SPEND but we can't return that, as it's not - // defined for a block, so we reset the reason flag to - // CONSENSUS here. - state.Invalid(ValidationInvalidReason::CONSENSUS, false, - state.GetRejectReason(), state.GetDebugMessage()); - } - return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state)); + TxValidationState tx_state; + if (!Consensus::CheckTxInputs(tx, tx_state, view, pindex->nHeight, txfee)) { + // Any transaction validation failure in ConnectBlock is a block consensus failure + LogPrintf("ERROR: %s: Consensus::CheckTxInputs: %s, %s\n", __func__, tx.GetHash().ToString(), FormatStateMessage(state)); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, + tx_state.GetRejectReason(), tx_state.GetDebugMessage()); } nFees += txfee; if (!MoneyRange(nFees)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: accumulated fee in the block out of range.", __func__), - "bad-txns-accumulated-fee-outofrange"); + LogPrintf("ERROR: %s: accumulated fee in the block out of range.\n", __func__); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-accumulated-fee-outofrange"); } // Check that transaction is BIP68 final @@ -2307,8 +2296,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl } if (!SequenceLocks(tx, nLockTimeFlags, prevheights, *pindex)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: contains a non-BIP68-final transaction", __func__), - "bad-txns-nonfinal"); + LogPrintf("ERROR: %s: contains a non-BIP68-final transaction\n", __func__); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-nonfinal"); } if (fAddressIndex || fSpentIndex) @@ -2358,8 +2347,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl // * p2sh (when P2SH enabled in flags and excludes coinbase) nSigOps += GetTransactionSigOpCount(tx, view, flags); if (nSigOps > MaxBlockSigOps(fDIP0001Active_context)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): too many sigops"), - "bad-blk-sigops"); + LogPrintf("ERROR: ConnectBlock(): too many sigops\n"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-blk-sigops"); } if (!tx.IsCoinBase()) @@ -2367,19 +2356,14 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl std::vector vChecks; bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ - if (fScriptChecks && !CheckInputs(tx, state, view, flags, fCacheResults, fCacheResults, txsdata[i], g_parallel_script_checks ? &vChecks : nullptr)) { - if (state.GetReason() == ValidationInvalidReason::TX_NOT_STANDARD) { - // CheckInputs may return NOT_STANDARD for extra flags we passed, - // but we can't return that, as it's not defined for a block, so - // we reset the reason flag to CONSENSUS here. - // In the event of a future soft-fork, we may need to - // consider whether rewriting to CONSENSUS or - // RECENT_CONSENSUS_CHANGE would be more appropriate. - state.Invalid(ValidationInvalidReason::CONSENSUS, false, - state.GetRejectReason(), state.GetDebugMessage()); - } - return error("ConnectBlock(): CheckInputs on %s failed with %s", + TxValidationState tx_state; + if (fScriptChecks && !CheckInputs(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], g_parallel_script_checks ? &vChecks : nullptr)) { + // Any transaction validation failure in ConnectBlock is a block consensus failure + state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, + tx_state.GetRejectReason(), tx_state.GetDebugMessage()); + LogPrintf("ERROR: ConnectBlock(): CheckInputs on %s failed with %s\n", tx.GetHash().ToString(), FormatStateMessage(state)); + return false; } control.Add(vChecks); } @@ -2426,8 +2410,11 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2; LogPrint(BCLog::BENCHMARK, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal); - if (!control.Wait()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: CheckQueue failed", __func__), "block-validation-failed"); + + if (!control.Wait()) { + LogPrintf("ERROR: %s: CheckQueue failed\n", __func__); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "block-validation-failed"); + } int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; LogPrint(BCLog::BENCHMARK, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal); @@ -2455,7 +2442,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl } else { // The node which relayed this should switch to correct chain. // TODO: relay instantsend data/proof. - return state.Invalid(ValidationInvalidReason::TX_CONFLICT_LOCK, error("ConnectBlock(DASH): transaction %s conflicts with transaction lock %s", tx->GetHash().ToString(), conflictLock->txid.ToString()), "conflict-tx-lock"); + LogPrintf("ERROR: ConnectBlock(DASH): transaction %s conflicts with transaction lock %s\n", tx->GetHash().ToString(), conflictLock->txid.ToString()); + return state.Invalid(BlockValidationResult::BLOCK_CHAINLOCK, "conflict-tx-lock"); } } } @@ -2475,7 +2463,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl if (!IsBlockValueValid(*sporkManager, *governance, *::masternodeSync, block, pindex->nHeight, blockReward, strError)) { // NOTE: Do not punish, the node might be missing governance data - return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): %s", strError), "bad-cb-amount"); + LogPrintf("ERROR: ConnectBlock(DASH): %s\n", strError); + return state.Invalid(BlockValidationResult::BLOCK_RESULT_UNSET, "bad-cb-amount"); } int64_t nTime5_3 = GetTimeMicros(); nTimeValueValid += nTime5_3 - nTime5_2; @@ -2483,7 +2472,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl if (!IsBlockPayeeValid(*sporkManager, *governance, *block.vtx[0], pindex->nHeight, blockReward)) { // NOTE: Do not punish, the node might be missing governance data - return state.Invalid(ValidationInvalidReason::NONE, error("ConnectBlock(DASH): couldn't find masternode or superblock payments"), "bad-cb-payee"); + LogPrintf("ERROR: ConnectBlock(DASH): couldn't find masternode or superblock payments\n"); + return state.Invalid(BlockValidationResult::BLOCK_RESULT_UNSET, "bad-cb-payee"); } int64_t nTime5_4 = GetTimeMicros(); nTimePayeeValid += nTime5_4 - nTime5_3; @@ -2581,7 +2571,7 @@ CoinsCacheSizeState CChainState::GetCoinsCacheSizeState( bool CChainState::FlushStateToDisk( const CChainParams& chainparams, - CValidationState &state, + BlockValidationState &state, FlushStateMode mode, int nManualPruneHeight) { @@ -2716,7 +2706,7 @@ bool CChainState::FlushStateToDisk( } void CChainState::ForceFlushStateToDisk() { - CValidationState state; + BlockValidationState state; const CChainParams& chainparams = Params(); if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) { LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state)); @@ -2724,7 +2714,7 @@ void CChainState::ForceFlushStateToDisk() { } void CChainState::PruneAndFlush() { - CValidationState state; + BlockValidationState state; fCheckForPruning = true; const CChainParams& chainparams = Params(); @@ -2812,7 +2802,7 @@ static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const C * disconnectpool (note that the caller is responsible for mempool consistency * in any case). */ -bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) +bool CChainState::DisconnectTip(BlockValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) { AssertLockHeld(cs_main); AssertLockHeld(m_mempool.cs); @@ -2916,7 +2906,7 @@ public: * * The block is added to connectTrace if connection succeeds. */ -bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) +bool CChainState::ConnectTip(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) { boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time(); AssertLockHeld(cs_main); @@ -3064,7 +3054,7 @@ void CChainState::PruneBlockIndexCandidates() { * * @returns true unless a system error occurred */ -bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) +bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) { AssertLockHeld(cs_main); AssertLockHeld(m_mempool.cs); @@ -3113,10 +3103,10 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr(), connectTrace, disconnectpool)) { if (state.IsInvalid()) { // The block violates a consensus rule. - if (state.GetReason() != ValidationInvalidReason::BLOCK_MUTATED) { + if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { InvalidChainFound(vpindexToConnect.front()); } - state = CValidationState(); + state = BlockValidationState(); fInvalidFound = true; fContinue = false; break; @@ -3182,7 +3172,7 @@ static void LimitValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main) { } } -bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr pblock) { +bool CChainState::ActivateBestChain(BlockValidationState &state, const CChainParams& chainparams, std::shared_ptr pblock) { // Note that while we're often called here from ProcessNewBlock, this is // far from a guarantee. Things in the P2P/RPC will often end up calling // us in the middle of ProcessNewBlock - do not assume pblock is set @@ -3287,7 +3277,7 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& return true; } -bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) +bool CChainState::PreciousBlock(BlockValidationState& state, const CChainParams& params, CBlockIndex *pindex) { { LOCK(cs_main); @@ -3316,7 +3306,7 @@ bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& par return ActivateBestChain(state, params, std::shared_ptr()); } -bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) +bool CChainState::InvalidateBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) { // Genesis block can't be invalidated assert(pindex); @@ -3470,7 +3460,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c return true; } -void CChainState::EnforceBlock(CValidationState& state, const CChainParams& chainparams, const CBlockIndex *pindex) +void CChainState::EnforceBlock(BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex *pindex) { AssertLockNotHeld(::cs_main); @@ -3502,7 +3492,7 @@ void CChainState::EnforceBlock(CValidationState& state, const CChainParams& chai } } -bool CChainState::MarkConflictingBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) +bool CChainState::MarkConflictingBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) { AssertLockHeld(cs_main); assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); @@ -3782,7 +3772,7 @@ static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int n return true; } -static bool FindUndoPos(CValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize) +static bool FindUndoPos(BlockValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize) { pos.nFile = nFile; @@ -3804,23 +3794,24 @@ static bool FindUndoPos(CValidationState &state, int nFile, FlatFilePos &pos, un return true; } -static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true) +static bool CheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true) { // Check proof of work matches claimed amount if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "high-hash", "proof of work failed"); + return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "high-hash", "proof of work failed"); // Check DevNet if (!consensusParams.hashDevnetGenesisBlock.IsNull() && block.hashPrevBlock == consensusParams.hashGenesisBlock && block.GetHash() != consensusParams.hashDevnetGenesisBlock) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, error("CheckBlockHeader(): wrong devnet genesis"), "devnet-genesis"); + LogPrintf("ERROR: CheckBlockHeader(): wrong devnet genesis\n"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "devnet-genesis"); } return true; } -bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot) +bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot) { // These are checks that are independent of context. @@ -3839,13 +3830,13 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P bool mutated; uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated); if (block.hashMerkleRoot != hashMerkleRoot2) - return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "bad-txnmrklroot", "hashMerkleRoot mismatch"); + return state.Invalid(BlockValidationResult::BLOCK_MUTATED, "bad-txnmrklroot", "hashMerkleRoot mismatch"); // Check for merkle tree malleability (CVE-2012-2459): repeating sequences // of transactions in a block without affecting the merkle root of a block, // while still invalidating it. if (mutated) - return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "bad-txns-duplicate", "duplicate transaction"); + return state.Invalid(BlockValidationResult::BLOCK_MUTATED, "bad-txns-duplicate", "duplicate transaction"); } // All potential-corruption validation must be done before we do any @@ -3854,21 +3845,27 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P // Size limits (relaxed) if (block.vtx.empty() || block.vtx.size() > MaxBlockSize() || ::GetSerializeSize(block, PROTOCOL_VERSION) > MaxBlockSize()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-length", "size limits failed"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-blk-length", "size limits failed"); // First transaction must be coinbase, the rest must not be if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-missing", "first tx is not coinbase"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-missing", "first tx is not coinbase"); for (unsigned int i = 1; i < block.vtx.size(); i++) if (block.vtx[i]->IsCoinBase()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-multiple", "more than one coinbase"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-multiple", "more than one coinbase"); // Check transactions - for (const auto& tx : block.vtx) - if (!CheckTransaction(*tx, state)) - return state.Invalid(state.GetReason(), false, state.GetRejectReason(), - strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage())); - + // Must check for duplicate inputs (see CVE-2018-17144) + for (const auto& tx : block.vtx) { + TxValidationState tx_state; + if (!CheckTransaction(*tx, tx_state)) { + // CheckBlock() does context-free validation checks. The only + // possible failures are consensus failures. + assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, tx_state.GetRejectReason(), + strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), tx_state.GetDebugMessage())); + } + } unsigned int nSigOps = 0; for (const auto& tx : block.vtx) { @@ -3876,7 +3873,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P } // sigops limits (relaxed) if (nSigOps > MaxBlockSigOps()) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-sigops", "out-of-bounds SigOpCount"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-blk-sigops", "out-of-bounds SigOpCount"); if (fCheckPOW && fCheckMerkleRoot) block.fChecked = true; @@ -3913,7 +3910,7 @@ CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data) * in ConnectBlock(). * Note that -reindex-chainstate skips the validation that happens here! */ -static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, BlockManager& blockman, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { assert(pindexPrev != nullptr); const int nHeight = pindexPrev->nHeight + 1; @@ -3926,12 +3923,13 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta double n1 = ConvertBitsToDouble(block.nBits); double n2 = ConvertBitsToDouble(nBitsNext); - if (abs(n1-n2) > n1*0.5) - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, error("%s : incorrect proof of work (DGW pre-fork) - %f %f %f at %d", __func__, abs(n1-n2), n1, n2, nHeight), - "bad-diffbits"); + if (abs(n1-n2) > n1*0.5) { + LogPrintf("ERROR: %s : incorrect proof of work (DGW pre-fork) - %f %f %f at %d\n", __func__, abs(n1-n2), n1, n2, nHeight); + return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "bad-diffbits"); + } } else { if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "bad-diffbits", strprintf("incorrect proof of work at %d", nHeight)); + return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "bad-diffbits", strprintf("incorrect proof of work at %d", nHeight)); } // Check against checkpoints @@ -3941,23 +3939,25 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta // BlockIndex(). assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman)); CBlockIndex* pcheckpoint = blockman.GetLastCheckpoint(params.Checkpoints()); - if (pcheckpoint && nHeight < pcheckpoint->nHeight) - return state.Invalid(ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), "bad-fork-prior-to-checkpoint"); + if (pcheckpoint && nHeight < pcheckpoint->nHeight) { + LogPrintf("ERROR: %s: forked chain older than last checkpoint (height %d)\n", __func__, nHeight); + return state.Invalid(BlockValidationResult::BLOCK_CHECKPOINT, "bad-fork-prior-to-checkpoint"); + } } // Check timestamp against prev if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "time-too-old", strprintf("block's timestamp is too early %d %d", block.GetBlockTime(), pindexPrev->GetMedianTimePast())); + return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "time-too-old", strprintf("block's timestamp is too early %d %d", block.GetBlockTime(), pindexPrev->GetMedianTimePast())); // Check timestamp if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME) - return state.Invalid(ValidationInvalidReason::BLOCK_TIME_FUTURE, false, "time-too-new", strprintf("block timestamp too far in the future %d %d", block.GetBlockTime(), nAdjustedTime + 2 * 60 * 60)); + return state.Invalid(BlockValidationResult::BLOCK_TIME_FUTURE, "time-too-new", strprintf("block timestamp too far in the future %d %d", block.GetBlockTime(), nAdjustedTime + 2 * 60 * 60)); // check for version 2, 3 and 4 upgrades if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) || (block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) || (block.nVersion < 4 && nHeight >= consensusParams.BIP65Height)) - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, strprintf("bad-version(0x%08x)", block.nVersion), + return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, strprintf("bad-version(0x%08x)", block.nVersion), strprintf("rejected nVersion=0x%08x block", block.nVersion)); return true; @@ -3969,7 +3969,7 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta * in ConnectBlock(). * Note that -reindex-chainstate skips the validation that happens here! */ -static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) +static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) { AssertLockHeld(cs_main); const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1; @@ -3991,24 +3991,29 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c // Size limits unsigned int nMaxBlockSize = MaxBlockSize(fDIP0001Active_context); if (block.vtx.empty() || block.vtx.size() > nMaxBlockSize || ::GetSerializeSize(block, PROTOCOL_VERSION) > nMaxBlockSize) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-length", "size limits failed"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-blk-length", "size limits failed"); // Check that all transactions are finalized and not over-sized // Also count sigops unsigned int nSigOps = 0; for (const auto& tx : block.vtx) { if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-nonfinal", "non-final transaction"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-nonfinal", "non-final transaction"); } - if (!ContextualCheckTransaction(*tx, state, consensusParams, pindexPrev)) { - return false; + TxValidationState tx_state; + if (!ContextualCheckTransaction(*tx, tx_state, consensusParams, pindexPrev)) { + // ContextCheckTransaction() does validation checks than only should + // fails as consensus failures. + assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, tx_state.GetRejectReason(), + strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), tx_state.GetDebugMessage())); } nSigOps += GetLegacySigOpCount(*tx); } // Check sigops if (nSigOps > MaxBlockSigOps(fDIP0001Active_context)) - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-sigops", "out-of-bounds SigOpCount"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-blk-sigops", "out-of-bounds SigOpCount"); // Enforce rule that the coinbase starts with serialized block height // After DIP3/DIP4 activation, we don't enforce the height in the input script anymore. @@ -4018,20 +4023,20 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c CScript expect = CScript() << nHeight; if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() || !std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-height", "block height mismatch in coinbase"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-height", "block height mismatch in coinbase"); } } if (fDIP0003Active_context) { if (block.vtx[0]->nType != TRANSACTION_COINBASE) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-type", "coinbase is not a CbTx"); + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-type", "coinbase is not a CbTx"); } } return true; } -bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) +bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) { AssertLockHeld(cs_main); // Check for duplicate @@ -4046,10 +4051,14 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState pindex = miSelf->second; if (ppindex) *ppindex = pindex; - if (pindex->nStatus & BLOCK_FAILED_MASK) - return state.Invalid(ValidationInvalidReason::CACHED_INVALID, error("%s: block %s is marked invalid", __func__, hash.ToString()), "duplicate"); - if (pindex->nStatus & BLOCK_CONFLICT_CHAINLOCK) - return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: block %s is marked conflicting", __func__, hash.ToString()), "duplicate"); + if (pindex->nStatus & BLOCK_FAILED_MASK) { + LogPrintf("ERROR: %s: block %s is marked invalid\n", __func__, hash.ToString()); + return state.Invalid(BlockValidationResult::BLOCK_CACHED_INVALID, "duplicate"); + } + if (pindex->nStatus & BLOCK_CONFLICT_CHAINLOCK) { + LogPrintf("ERROR: %s: block %s is marked conflicting\n", __func__, hash.ToString()); + return state.Invalid(BlockValidationResult::BLOCK_CHAINLOCK, "duplicate"); + } return true; } @@ -4059,17 +4068,23 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState // Get prev block index CBlockIndex* pindexPrev = nullptr; BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock); - if (mi == m_block_index.end()) - return state.Invalid(ValidationInvalidReason::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), "prev-blk-not-found"); + if (mi == m_block_index.end()) { + LogPrintf("ERROR: %s: prev block not found\n", __func__); + return state.Invalid(BlockValidationResult::BLOCK_MISSING_PREV, "prev-blk-not-found"); + } pindexPrev = (*mi).second; assert(pindexPrev); - if (pindexPrev->nStatus & BLOCK_FAILED_MASK) - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk"); + if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { + LogPrintf("ERROR: %s: prev block invalid\n", __func__); + return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk"); + } - if (pindexPrev->nStatus & BLOCK_CONFLICT_CHAINLOCK) + if (pindexPrev->nStatus & BLOCK_CONFLICT_CHAINLOCK) { // it's ok-ish, the other node is probably missing the latest chainlock - return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: prev block %s conflicts with chainlock", __func__, block.hashPrevBlock.ToString()), "bad-prevblk-chainlock"); + LogPrintf("ERROR: %s: prev block %s conflicts with chainlock\n", __func__, block.hashPrevBlock.ToString()); + return state.Invalid(BlockValidationResult::BLOCK_CHAINLOCK, "bad-prevblk-chainlock"); + } if (!ContextualCheckBlockHeader(block, state, *this, chainparams, pindexPrev, GetAdjustedTime())) return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); @@ -4107,7 +4122,8 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState setDirtyBlockIndex.insert(invalid_walk); invalid_walk = invalid_walk->pprev; } - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk"); + LogPrintf("ERROR: %s: prev block invalid\n", __func__); + return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk"); } } } @@ -4116,7 +4132,8 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState if (pindex == nullptr) { AddToBlockIndex(block, BLOCK_CONFLICT_CHAINLOCK); } - return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: header %s conflicts with chainlock", __func__, hash.ToString()), "bad-chainlock"); + LogPrintf("ERROR: %s: header %s conflicts with chainlock\n", __func__, hash.ToString()); + return state.Invalid(BlockValidationResult::BLOCK_CHAINLOCK, "bad-chainlock"); } } if (pindex == nullptr) @@ -4132,11 +4149,10 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState } // Exposed wrapper for AcceptBlockHeader -bool ChainstateManager::ProcessNewBlockHeaders(const std::vector& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex, CBlockHeader *first_invalid) +bool ChainstateManager::ProcessNewBlockHeaders(const std::vector& headers, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex) { assert(std::addressof(::ChainstateActive()) == std::addressof(ActiveChainstate())); AssertLockNotHeld(cs_main); - if (first_invalid != nullptr) first_invalid->SetNull(); { LOCK(cs_main); for (const CBlockHeader& header : headers) { @@ -4146,7 +4162,6 @@ bool ChainstateManager::ProcessNewBlockHeaders(const std::vector& ActiveChainstate().CheckBlockIndex(chainparams.GetConsensus()); if (!accepted) { - if (first_invalid) *first_invalid = header; return false; } if (ppindex) { @@ -4182,7 +4197,7 @@ static FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& act } /** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */ -bool CChainState::AcceptBlock(const std::shared_ptr& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) +bool CChainState::AcceptBlock(const std::shared_ptr& pblock, BlockValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) { boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time(); @@ -4234,8 +4249,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr& pblock, CVali if (!CheckBlock(block, state, chainparams.GetConsensus()) || !ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindex->pprev)) { - assert(IsBlockReason(state.GetReason())); - if (state.IsInvalid() && state.GetReason() != ValidationInvalidReason::BLOCK_MUTATED) { + if (state.IsInvalid() && state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { pindex->nStatus |= BLOCK_FAILED_VALID; setDirtyBlockIndex.insert(pindex); } @@ -4282,7 +4296,7 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s { CBlockIndex *pindex = nullptr; if (fNewBlock) *fNewBlock = false; - CValidationState state; + BlockValidationState state; // CheckBlock() does not support multi-threaded block validation because CBlock::fChecked can cause data race. // Therefore, the following critical section must include the CheckBlock() call as well. @@ -4303,7 +4317,7 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s NotifyHeaderTip(ActiveChainstate()); - CValidationState state; // Only used to report errors, not invalidity - ignore it + BlockValidationState state; // Only used to report errors, not invalidity - ignore it if (!ActiveChainstate().ActivateBestChain(state, chainparams, pblock)) return error("%s: ActivateBestChain failed: %s", __func__, FormatStateMessage(state)); @@ -4311,7 +4325,7 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s return true; } -bool TestBlockValidity(CValidationState& state, +bool TestBlockValidity(BlockValidationState& state, llmq::CChainLocksHandler& clhandler, CEvoDB& evoDb, const CChainParams& chainparams, @@ -4327,7 +4341,8 @@ bool TestBlockValidity(CValidationState& state, uint256 hash = block.GetHash(); if (clhandler.HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) { - return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: conflicting with chainlock", __func__), "bad-chainlock"); + LogPrintf("ERROR: %s: conflicting with chainlock\n", __func__); + return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-chainlock"); } CCoinsViewCache viewNew(&chainstate.CoinsTip()); @@ -4442,7 +4457,7 @@ void BlockManager::FindFilesToPruneManual(std::set& setFilesToPrune, int nM /* This function is called from the RPC code for pruneblockchain */ void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight) { - CValidationState state; + BlockValidationState state; const CChainParams& chainparams = Params(); assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); if (!active_chainstate.FlushStateToDisk( @@ -4766,7 +4781,7 @@ bool CVerifyDB::VerifyDB( CBlockIndex* pindex; CBlockIndex* pindexFailure = nullptr; int nGoodTransactions = 0; - CValidationState state; + BlockValidationState state; int reportDone = 0; LogPrintf("[0%%]..."); /* Continued */ @@ -4867,7 +4882,7 @@ bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& i } // MUST process special txes before updating UTXO to ensure consistency between mempool and block processing - CValidationState state; + BlockValidationState state; if (!ProcessSpecialTxsInBlock(block, pindex, *m_quorum_block_processor, state, inputs, false /*fJustCheck*/, false /*fScriptChecks*/)) { return error("RollforwardBlock(DASH): ProcessSpecialTxsInBlock for block %s failed with %s", pindex->GetBlockHash().ToString(), FormatStateMessage(state)); @@ -5022,7 +5037,7 @@ bool ChainstateManager::LoadBlockIndex(const CChainParams& chainparams) return true; } -bool CChainState::AddGenesisBlock(const CChainParams& chainparams, const CBlock& block, CValidationState& state) +bool CChainState::AddGenesisBlock(const CChainParams& chainparams, const CBlock& block, BlockValidationState& state) { assert(std::addressof(::ChainActive()) == std::addressof(m_chain)); FlatFilePos blockPos = SaveBlockToDisk(block, 0, m_chain, chainparams, nullptr); @@ -5045,7 +5060,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams) return true; try { - CValidationState state; + BlockValidationState state; if (!AddGenesisBlock(chainparams, chainparams.GenesisBlock(), state)) return false; @@ -5129,7 +5144,7 @@ void CChainState::LoadExternalBlockFile(const CChainParams& chainparams, FILE* f assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_blockman)); CBlockIndex* pindex = m_blockman.LookupBlockIndex(hash); if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) { - CValidationState state; + BlockValidationState state; assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); if (AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) { nLoaded++; @@ -5144,8 +5159,8 @@ void CChainState::LoadExternalBlockFile(const CChainParams& chainparams, FILE* f // Activate the genesis block so normal node progress can continue if (hash == chainparams.GetConsensus().hashGenesisBlock) { - CValidationState state; assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); + BlockValidationState state; if (!ActivateBestChain(state, chainparams, nullptr)) { break; } @@ -5169,8 +5184,8 @@ void CChainState::LoadExternalBlockFile(const CChainParams& chainparams, FILE* f LogPrint(BCLog::REINDEX, "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(), head.ToString()); LOCK(cs_main); - CValidationState dummy; assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); + BlockValidationState dummy; if (AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr)) { nLoaded++; @@ -5409,7 +5424,7 @@ bool CChainState::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size) LogPrintf("[%s] resized coinstip cache to %.1f MiB\n", this->ToString(), coinstip_size * (1.0 / 1024 / 1024)); - CValidationState state; + BlockValidationState state; const CChainParams& chainparams = Params(); bool ret; @@ -5477,11 +5492,11 @@ bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate) if (amountdelta) { pool.PrioritiseTransaction(tx->GetHash(), amountdelta); } - CValidationState state; + TxValidationState state; if (nTime + nExpiryTimeout > nNow) { LOCK(cs_main); assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); - AcceptToMemoryPoolWithTime(chainparams, pool, active_chainstate, state, tx, nullptr /* pfMissingInputs */, nTime, + AcceptToMemoryPoolWithTime(chainparams, pool, active_chainstate, state, tx, nTime, false /* bypass_limits */, 0 /* nAbsurdFee */, false /* test_accept */); if (state.IsValid()) { ++count; diff --git a/src/validation.h b/src/validation.h index f2028d7a41..1976bfa773 100644 --- a/src/validation.h +++ b/src/validation.h @@ -43,6 +43,7 @@ class CQuorumBlockProcessor; class CEvoDB; class CChainState; +class BlockValidationState; class CBlockIndex; class CBlockTreeDB; class CBlockUndo; @@ -52,7 +53,7 @@ class CInv; class CConnman; class CScriptCheck; class CTxMemPool; -class CValidationState; +class TxValidationState; class ChainstateManager; struct PrecomputedTransactionData; struct ChainTxData; @@ -215,8 +216,8 @@ void UnlinkPrunedFiles(const std::set& setFilesToPrune); void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight); /** (try to) add transaction to memory pool */ -bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, - bool* pfMissingInputs, bool bypass_limits, +bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx, + bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool GetUTXOCoin(const COutPoint& outpoint, Coin& coin); @@ -315,10 +316,10 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex); /** Functions for validating blocks and updating the block tree */ /** Context-independent validity checks */ -bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true); +bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true); /** Check a block is completely valid from start to finish (only works on top of our current best block) */ -bool TestBlockValidity(CValidationState& state, +bool TestBlockValidity(BlockValidationState& state, llmq::CChainLocksHandler& clhandler, CEvoDB& evoDb, const CChainParams& chainparams, @@ -454,7 +455,7 @@ public: */ bool AcceptBlockHeader( const CBlockHeader& block, - CValidationState& state, + BlockValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -681,7 +682,7 @@ public: */ bool FlushStateToDisk( const CChainParams& chainparams, - CValidationState &state, + BlockValidationState &state, FlushStateMode mode, int nManualPruneHeight = 0); @@ -708,29 +709,29 @@ public: * @returns true unless a system error occurred */ bool ActivateBestChain( - CValidationState& state, + BlockValidationState& state, const CChainParams& chainparams, std::shared_ptr pblock = nullptr) LOCKS_EXCLUDED(cs_main); - bool AcceptBlock(const std::shared_ptr& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool AcceptBlock(const std::shared_ptr& pblock, BlockValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main); // Block (dis)connection on a given view: DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); // Apply the effects of a block disconnection on the UTXO set. - bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); + bool DisconnectTip(BlockValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); // Manual block validity manipulation: /** Mark a block as precious and reorganize. * * May not be called in a validationinterface callback. */ - bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); + bool PreciousBlock(BlockValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); /** Mark a block as invalid. */ - bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); + bool InvalidateBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); /** Enforce a block marking all the other chains as conflicting. */ - void EnforceBlock(CValidationState& state, const CChainParams& chainparams, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); + void EnforceBlock(BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); /** Remove invalidity status from a block and its descendants. */ void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -738,7 +739,7 @@ public: bool ReplayBlocks(const CChainParams& params); /** Ensures we have a genesis block in the block tree, possibly writing one to disk. */ bool LoadGenesisBlock(const CChainParams& chainparams); - bool AddGenesisBlock(const CChainParams& chainparams, const CBlock& block, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool AddGenesisBlock(const CChainParams& chainparams, const CBlock& block, BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void PruneBlockIndexCandidates(); @@ -774,10 +775,10 @@ public: std::string ToString() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); private: - bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); - bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); + bool ActivateBestChainStep(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); + bool ConnectTip(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); - void InvalidBlockFound(CBlockIndex* pindex, const CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + void InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main); void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -785,7 +786,7 @@ private: bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main); //! Mark a block as conflicting - bool MarkConflictingBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool MarkConflictingBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); //! Mark a block as not having block data void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -990,7 +991,7 @@ public: * @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers * @param[out] first_invalid First header that fails validation, if one exists */ - bool ProcessNewBlockHeaders(const std::vector& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr, CBlockHeader* first_invalid = nullptr) LOCKS_EXCLUDED(cs_main); + bool ProcessNewBlockHeaders(const std::vector& block, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main); //! Load the block tree and coins database from disk, initializing state if we're running with -reindex bool LoadBlockIndex(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main); diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 8a33f76469..585c81961b 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -44,7 +44,7 @@ struct MainSignalsInstance { boost::signals2::signal&, const CBlockIndex* pindex)> BlockDisconnected; boost::signals2::signal TransactionRemovedFromMempool; boost::signals2::signal ChainStateFlushed; - boost::signals2::signal BlockChecked; + boost::signals2::signal BlockChecked; boost::signals2::signal&)> NewPoWValidBlock; boost::signals2::signalAcceptedBlockHeader; boost::signals2::signalNotifyHeaderTip; @@ -198,7 +198,7 @@ void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) { }); } -void CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) { +void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) { m_internals->BlockChecked(block, state); } diff --git a/src/validationinterface.h b/src/validationinterface.h index 0790d846f1..cc96d6a04c 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -13,12 +13,12 @@ #include extern CCriticalSection cs_main; +class BlockValidationState; class CBlock; class CBlockIndex; struct CBlockLocator; class CConnman; class CValidationInterface; -class CValidationState; class CGovernanceVote; class CGovernanceObject; class CDeterministicMNList; @@ -185,11 +185,11 @@ protected: virtual void ChainStateFlushed(const CBlockLocator &locator) {} /** * Notifies listeners of a block validation result. - * If the provided CValidationState IsValid, the provided block + * If the provided BlockValidationState IsValid, the provided block * is guaranteed to be the current best block at the time the * callback was generated (not necessarily now) */ - virtual void BlockChecked(const CBlock&, const CValidationState&) {} + virtual void BlockChecked(const CBlock&, const BlockValidationState&) {} /** * Notifies listeners that a block which builds directly on our current tip * has been received and connected to the headers tree, though not validated yet */ @@ -236,7 +236,7 @@ public: void NotifyRecoveredSig(const std::shared_ptr &sig); void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman); void ChainStateFlushed(const CBlockLocator &); - void BlockChecked(const CBlock&, const CValidationState&); + void BlockChecked(const CBlock&, const BlockValidationState&); void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr&); }; diff --git a/test/functional/feature_llmq_is_cl_conflicts.py b/test/functional/feature_llmq_is_cl_conflicts.py index 415b4f57be..9616cd32a2 100755 --- a/test/functional/feature_llmq_is_cl_conflicts.py +++ b/test/functional/feature_llmq_is_cl_conflicts.py @@ -232,7 +232,7 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework): # Assert that the conflicting tx got mined and the locked TX is not valid assert self.nodes[0].getrawtransaction(rawtx1_txid, True)['confirmations'] > 0 - assert_raises_rpc_error(-25, "Missing inputs", self.nodes[0].sendrawtransaction, rawtx2) + assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", self.nodes[0].sendrawtransaction, rawtx2) # Create the block and the corresponding clsig but do not relay clsig yet cl_block = self.create_block(self.nodes[0]) diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index df59bee924..a14678125e 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -151,7 +151,7 @@ class RawTransactionsTest(BitcoinTestFramework): rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx) # This will raise an exception since there are missing inputs - assert_raises_rpc_error(-25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex']) + assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", self.nodes[2].sendrawtransaction, rawtx['hex']) ##################################### # getrawtransaction with block hash # From 27ecb07c8a7177c1755ba8c180cbeb2afeaa614d Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 28 Nov 2019 12:58:29 +0100 Subject: [PATCH 8/9] =?UTF-8?q?Merge=20#17624:=20net:=20Fix=20an=20uniniti?= =?UTF-8?q?alized=20read=20in=20ProcessMessage(=E2=80=A6,=20"tx",=20?= =?UTF-8?q?=E2=80=A6)=20when=20receiving=20a=20transaction=20we=20already?= =?UTF-8?q?=20have?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 73b96c94cb6c2afdee7f151768a96944ecaf9d9b net: Fix uninitialized read in ProcessMessage(...) (practicalswift) Pull request description: Fix an uninitialized read in `ProcessMessage(…, "tx", …)` when receiving a transaction we already have. The uninitialized value is read and used on [L2526 in the case of `AlreadyHave(inv) == true`](https://github.com/bitcoin/bitcoin/blob/d8a66626d63135fd245d5afc524b88b9a94d208b/src/net_processing.cpp#L2494-L2526). Proof of concept being run against a `bitcoind` built with MemorySanitizer (`-fsanitize=memory`): ``` $ ./p2p-uninit-read-in-conditional-poc.py Usage: ./p2p-uninit-read-in-conditional-poc.py $ bitcoind -regtest & $ ./p2p-uninit-read-in-conditional-poc.py 127.0.0.1 18444 regtest SUMMARY: MemorySanitizer: use-of-uninitialized-value [1]+ Exit 77 bitcoind -regtest $ ``` Proof of concept being run against a `bitcoind` running under Valgrind (`valgrind --exit-on-first-error`): ``` $ valgrind -q --exit-on-first-error=yes --error-exitcode=1 bitcoind -regtest & $ ./p2p-uninit-read-in-conditional-poc.py 127.0.0.1 18444 regtest ==27351== Conditional jump or move depends on uninitialised value(s) [1]+ Exit 1 valgrind -q --exit-on-first-error=yes --error-exitcode=1 bitcoind -regtest $ ``` Proof of concept script: ``` #!/usr/bin/env python3 import sys from test_framework.mininode import NetworkThread from test_framework.mininode import P2PDataStore from test_framework.messages import CTransaction, CTxIn, CTxOut, msg_tx def send_duplicate_tx(dstaddr="127.0.0.1", dstport=18444, net="regtest"): network_thread = NetworkThread() network_thread.start() node = P2PDataStore() node.peer_connect(dstaddr=dstaddr, dstport=dstport, net=net)() node.wait_for_verack() tx = CTransaction() tx.vin.append(CTxIn()) tx.vout.append(CTxOut()) node.send_message(msg_tx(tx)) node.send_message(msg_tx(tx)) node.peer_disconnect() network_thread.close() if __name__ == "__main__": if len(sys.argv) != 4: print("Usage: {} ".format(sys.argv[0])) sys.exit(0) send_duplicate_tx(sys.argv[1], int(sys.argv[2]), sys.argv[3]) ``` Note that the transaction in the proof of concept is the simplest possible, but really any transaction can be used. It does not have to be a valid transaction. This bug was introduced in #15921 ("validation: Tidy up ValidationState interface") which was merged in to `master` 28 days ago. Luckily this bug was caught before being part of any Bitcoin Core release :) ACKs for top commit: jnewbery: utACK 73b96c94cb6c2afdee7f151768a96944ecaf9d9b laanwj: ACK 73b96c94cb6c2afdee7f151768a96944ecaf9d9b, thanks for discovering and reporting this before it ended up in a release. Tree-SHA512: 7ce6b8f260bcdd9b2ec4ff4b941a891bbef578acf4456df33b7a8d42b248237ec4949e65e2445b24851d1639b10681c701ad500b1c0b776ff050ef8c3812c795 --- src/consensus/validation.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/consensus/validation.h b/src/consensus/validation.h index 86efba5dfa..8d7c8e3854 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -103,7 +103,7 @@ inline ValidationState::~ValidationState() {}; class TxValidationState : public ValidationState { private: - TxValidationResult m_result; + TxValidationResult m_result = TxValidationResult::TX_RESULT_UNSET; public: bool Invalid(TxValidationResult result, const std::string &reject_reason="", @@ -118,7 +118,7 @@ public: class BlockValidationState : public ValidationState { private: - BlockValidationResult m_result; + BlockValidationResult m_result = BlockValidationResult::BLOCK_RESULT_UNSET; public: bool Invalid(BlockValidationResult result, const std::string &reject_reason="", From e2d11714230adf524aa07d6cc36c40f852f26ac1 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 24 Oct 2019 17:25:00 -0400 Subject: [PATCH 9/9] partial Merge #17212: refactor: Remove unused CExt{Pub,}Key (de)serialization methods 5b44a75493a1a098404d5e21dc384e74eae1892e refactor: Remove unused CExt{Pub,}Key (de)serialization methods (Sebastian Falbesoner) Pull request description: As pointed out in issue #17130, the serialization/deserialization methods for the classes `CExtKey` and `CExtPubKey` are only used in the BIP32 unit tests and hence can be removed (see comments https://github.com/bitcoin/bitcoin/issues/17130#issuecomment-543750290, https://github.com/bitcoin/bitcoin/issues/17130#issuecomment-543794408 and https://github.com/bitcoin/bitcoin/issues/17130#issuecomment-543814727). ACKs for top commit: practicalswift: ACK 5b44a75493a1a098404d5e21dc384e74eae1892e -- -60 LOC diff looks correct :) promag: ACK 5b44a75493a1a098404d5e21dc384e74eae1892e. MarcoFalke: unsigned ACK 5b44a75493a1a098404d5e21dc384e74eae1892e fjahr: ACK 5b44a75 jonatack: Light ACK 5b44a75493a1a098404d5e21dc384e74eae1892e. Built, ran tests and bitcoind. `git blame` shows most of the last changes are from commit 90604f16af63ec066d6561337f476ccd8acec326 in 2015 to add bip32 pubkey serialization. Tree-SHA512: 6887573b76b9e54e117a076557407b6f7908719b2202fb9eea498522baf9f30198b3f78b87a62efcd17ad1ab0886196f099239992ce7cbbaee79979ffe9e5f2c --- src/key.h | 19 ------------------- src/test/bip32_tests.cpp | 16 ---------------- 2 files changed, 35 deletions(-) diff --git a/src/key.h b/src/key.h index 2c01cd131e..f1b3099b2f 100644 --- a/src/key.h +++ b/src/key.h @@ -161,25 +161,6 @@ struct CExtKey { bool Derive(CExtKey& out, unsigned int nChild) const; CExtPubKey Neuter() const; void SetSeed(const unsigned char* seed, unsigned int nSeedLen); - template - void Serialize(Stream& s) const - { - unsigned int len = BIP32_EXTKEY_SIZE; - ::WriteCompactSize(s, len); - unsigned char code[BIP32_EXTKEY_SIZE]; - Encode(code); - s.write((const char *)&code[0], len); - } - template - void Unserialize(Stream& s) - { - unsigned int len = ::ReadCompactSize(s); - unsigned char code[BIP32_EXTKEY_SIZE]; - if (len != BIP32_EXTKEY_SIZE) - throw std::runtime_error("Invalid extended key size\n"); - s.read((char *)&code[0], len); - Decode(code); - } }; /** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */ diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index b66f297375..2d3a987c69 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -118,22 +118,6 @@ static void RunTest(const TestVector &test) { } key = keyNew; pubkey = pubkeyNew; - - CDataStream ssPub(SER_DISK, CLIENT_VERSION); - ssPub << pubkeyNew; - BOOST_CHECK(ssPub.size() == 75); - - CDataStream ssPriv(SER_DISK, CLIENT_VERSION); - ssPriv << keyNew; - BOOST_CHECK(ssPriv.size() == 75); - - CExtPubKey pubCheck; - CExtKey privCheck; - ssPub >> pubCheck; - ssPriv >> privCheck; - - BOOST_CHECK(pubCheck == pubkeyNew); - BOOST_CHECK(privCheck == keyNew); } }