diff --git a/doc/release-notes-6296.md b/doc/release-notes-6296.md new file mode 100644 index 0000000000000..e3838f990cd2f --- /dev/null +++ b/doc/release-notes-6296.md @@ -0,0 +1,6 @@ +Updated settings +---------------- + +- `-maxuploadtarget` now allows human readable byte units [k|K|m|M|g|G|t|T]. + E.g. `-maxuploadtarget=500g`. No whitespace, +- or fractions allowed. + Default is `M` if no suffix provided. diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 92e2f086ffe9a..839224e9a1c3c 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -150,8 +150,9 @@ BITCOIN_TESTS =\ test/script_p2sh_tests.cpp \ test/script_p2pk_tests.cpp \ test/script_p2pkh_tests.cpp \ - test/script_tests.cpp \ + test/script_parse_tests.cpp \ test/script_standard_tests.cpp \ + test/script_tests.cpp \ test/scriptnum_tests.cpp \ test/serfloat_tests.cpp \ test/serialize_tests.cpp \ diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp index a23b9e8ac6433..56afa0132f3c2 100644 --- a/src/bench/block_assemble.cpp +++ b/src/bench/block_assemble.cpp @@ -39,10 +39,10 @@ static void AssembleBlock(benchmark::Bench& bench) txs.at(b) = MakeTransactionRef(tx); } { - LOCK(::cs_main); // Required for ::AcceptToMemoryPool. + LOCK(::cs_main); for (const auto& txr : txs) { - const MempoolAcceptResult res = ::AcceptToMemoryPool(test_setup->m_node.chainman->ActiveChainstate(), *test_setup->m_node.mempool, txr, false /* bypass_limits */); + const MempoolAcceptResult res = test_setup->m_node.chainman->ProcessTransaction(txr); assert(res.m_result_type == MempoolAcceptResult::ResultType::VALID); } } diff --git a/src/bench/mempool_stress.cpp b/src/bench/mempool_stress.cpp index 29a835ad219b6..3837a1427d97c 100644 --- a/src/bench/mempool_stress.cpp +++ b/src/bench/mempool_stress.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -26,14 +27,8 @@ struct Available { Available(CTransactionRef& ref, size_t tx_count) : ref(ref), tx_count(tx_count){} }; -static void ComplexMemPool(benchmark::Bench& bench) +static std::vector CreateOrderedCoins(FastRandomContext& det_rand, int childTxs, int min_ancestors) { - int childTxs = 800; - if (bench.complexityN() > 1) { - childTxs = static_cast(bench.complexityN()); - } - - FastRandomContext det_rand{true}; std::vector available_coins; std::vector ordered_coins; // Create some base transactions @@ -57,8 +52,10 @@ static void ComplexMemPool(benchmark::Bench& bench) size_t idx = det_rand.randrange(available_coins.size()); Available coin = available_coins[idx]; uint256 hash = coin.ref->GetHash(); - // biased towards taking just one ancestor, but maybe more - size_t n_to_take = det_rand.randrange(2) == 0 ? 1 : 1+det_rand.randrange(coin.ref->vout.size() - coin.vin_left); + // biased towards taking min_ancestors parents, but maybe more + size_t n_to_take = det_rand.randrange(2) == 0 ? + min_ancestors : + min_ancestors + det_rand.randrange(coin.ref->vout.size() - coin.vin_left); for (size_t i = 0; i < n_to_take; ++i) { tx.vin.emplace_back(); tx.vin.back().prevout = COutPoint(hash, coin.vin_left++); @@ -77,6 +74,17 @@ static void ComplexMemPool(benchmark::Bench& bench) ordered_coins.emplace_back(MakeTransactionRef(tx)); available_coins.emplace_back(ordered_coins.back(), tx_counter++); } + return ordered_coins; +} + +static void ComplexMemPool(benchmark::Bench& bench) +{ + FastRandomContext det_rand{true}; + int childTxs = 800; + if (bench.complexityN() > 1) { + childTxs = static_cast(bench.complexityN()); + } + std::vector ordered_coins = CreateOrderedCoins(det_rand, childTxs, /* min_ancestors */ 1); const auto testing_setup = MakeNoLogFileContext(CBaseChainParams::MAIN); CTxMemPool pool; LOCK2(cs_main, pool.cs); @@ -89,4 +97,21 @@ static void ComplexMemPool(benchmark::Bench& bench) }); } +static void MempoolCheck(benchmark::Bench& bench) +{ + FastRandomContext det_rand{true}; + const int childTxs = bench.complexityN() > 1 ? static_cast(bench.complexityN()) : 2000; + const std::vector ordered_coins = CreateOrderedCoins(det_rand, childTxs, /* min_ancestors */ 5); + const auto testing_setup = MakeNoLogFileContext(CBaseChainParams::MAIN, {"-checkmempool=1"}); + CTxMemPool pool; + LOCK2(cs_main, pool.cs); + const CCoinsViewCache& coins_tip = testing_setup.get()->m_node.chainman->ActiveChainstate().CoinsTip(); + for (auto& tx : ordered_coins) AddTx(tx, pool); + + bench.run([&]() NO_THREAD_SAFETY_ANALYSIS { + pool.check(coins_tip, /* spendheight */ 2); + }); +} + BENCHMARK(ComplexMemPool); +BENCHMARK(MempoolCheck); diff --git a/src/coinjoin/client.cpp b/src/coinjoin/client.cpp index 86dce7a10bcc4..9739727243ed2 100644 --- a/src/coinjoin/client.cpp +++ b/src/coinjoin/client.cpp @@ -793,7 +793,8 @@ bool CCoinJoinClientManager::CheckAutomaticBackup() // // Passively run mixing in the background to mix funds based on the given configuration. // -bool CCoinJoinClientSession::DoAutomaticDenominating(CChainState& active_chainstate, CConnman& connman, CTxMemPool& mempool, bool fDryRun) +bool CCoinJoinClientSession::DoAutomaticDenominating(ChainstateManager& chainman, CConnman& connman, + const CTxMemPool& mempool, bool fDryRun) { if (m_is_masternode) return false; // no client-side mixing on masternodes if (nState != POOL_STATE_IDLE) return false; @@ -946,7 +947,7 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(CChainState& active_chainst return false; } } else { - if (!CoinJoin::IsCollateralValid(active_chainstate, mempool, CTransaction(txMyCollateral))) { + if (!CoinJoin::IsCollateralValid(chainman, mempool, CTransaction(txMyCollateral))) { WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::DoAutomaticDenominating -- invalid collateral, recreating...\n"); if (!CreateCollateralTransaction(txMyCollateral, strReason)) { WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::DoAutomaticDenominating -- create collateral error: %s\n", strReason); @@ -973,7 +974,8 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(CChainState& active_chainst return false; } -bool CCoinJoinClientManager::DoAutomaticDenominating(CChainState& active_chainstate, CConnman& connman, CTxMemPool& mempool, bool fDryRun) +bool CCoinJoinClientManager::DoAutomaticDenominating(ChainstateManager& chainman, CConnman& connman, + const CTxMemPool& mempool, bool fDryRun) { if (m_is_masternode) return false; // no client-side mixing on masternodes if (!CCoinJoinClientOptions::IsEnabled() || !IsMixing()) return false; @@ -1016,7 +1018,7 @@ bool CCoinJoinClientManager::DoAutomaticDenominating(CChainState& active_chainst return false; } - fResult &= session.DoAutomaticDenominating(active_chainstate, connman, mempool, fDryRun); + fResult &= session.DoAutomaticDenominating(chainman, connman, mempool, fDryRun); } return fResult; @@ -1864,7 +1866,7 @@ void CCoinJoinClientQueueManager::DoMaintenance() CheckQueue(); } -void CCoinJoinClientManager::DoMaintenance(CChainState& active_chainstate, CConnman& connman, CTxMemPool& mempool) +void CCoinJoinClientManager::DoMaintenance(ChainstateManager& chainman, CConnman& connman, const CTxMemPool& mempool) { if (!CCoinJoinClientOptions::IsEnabled()) return; if (m_is_masternode) return; // no client-side mixing on masternodes @@ -1878,7 +1880,7 @@ void CCoinJoinClientManager::DoMaintenance(CChainState& active_chainstate, CConn CheckTimeout(); ProcessPendingDsaRequest(connman); if (nDoAutoNextRun == nTick) { - DoAutomaticDenominating(active_chainstate, connman, mempool); + DoAutomaticDenominating(chainman, connman, mempool); nDoAutoNextRun = nTick + COINJOIN_AUTO_TIMEOUT_MIN + GetRandInt(COINJOIN_AUTO_TIMEOUT_MAX - COINJOIN_AUTO_TIMEOUT_MIN); } } @@ -1930,7 +1932,7 @@ void CoinJoinWalletManager::DoMaintenance() { LOCK(cs_wallet_manager_map); for (auto& [_, clientman] : m_wallet_manager_map) { - clientman->DoMaintenance(m_chainstate, m_connman, m_mempool); + clientman->DoMaintenance(m_chainman, m_connman, m_mempool); } } diff --git a/src/coinjoin/client.h b/src/coinjoin/client.h index 5a615a6ce9deb..a0deebdbd24b3 100644 --- a/src/coinjoin/client.h +++ b/src/coinjoin/client.h @@ -22,9 +22,10 @@ class CCoinJoinClientQueueManager; class CConnman; class CDeterministicMN; class CDeterministicMNManager; -class CNode; +class ChainstateManager; class CMasternodeMetaMan; class CMasternodeSync; +class CNode; class CoinJoinWalletManager; class CTxMemPool; @@ -74,10 +75,17 @@ class CoinJoinWalletManager { using wallet_name_cjman_map = std::map>; public: - CoinJoinWalletManager(CChainState& chainstate, CConnman& connman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, CTxMemPool& mempool, - const CMasternodeSync& mn_sync, const std::unique_ptr& queueman, bool is_masternode) - : m_chainstate(chainstate), m_connman(connman), m_dmnman(dmnman), m_mn_metaman(mn_metaman), m_mempool(mempool), m_mn_sync(mn_sync), - m_queueman(queueman), m_is_masternode{is_masternode} + CoinJoinWalletManager(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, + CMasternodeMetaMan& mn_metaman, const CTxMemPool& mempool, const CMasternodeSync& mn_sync, + const std::unique_ptr& queueman, bool is_masternode) : + m_chainman(chainman), + m_connman(connman), + m_dmnman(dmnman), + m_mn_metaman(mn_metaman), + m_mempool(mempool), + m_mn_sync(mn_sync), + m_queueman(queueman), + m_is_masternode{is_masternode} {} ~CoinJoinWalletManager() { @@ -112,11 +120,11 @@ class CoinJoinWalletManager { }; private: - CChainState& m_chainstate; + ChainstateManager& m_chainman; CConnman& m_connman; CDeterministicMNManager& m_dmnman; CMasternodeMetaMan& m_mn_metaman; - CTxMemPool& m_mempool; + const CTxMemPool& m_mempool; const CMasternodeSync& m_mn_sync; const std::unique_ptr& m_queueman; @@ -202,7 +210,8 @@ class CCoinJoinClientSession : public CCoinJoinBaseSession bool GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const; /// Passively run mixing in the background according to the configuration in settings - bool DoAutomaticDenominating(CChainState& active_chainstate, CConnman& connman, CTxMemPool& mempool, bool fDryRun = false) EXCLUSIVE_LOCKS_REQUIRED(!cs_coinjoin); + bool DoAutomaticDenominating(ChainstateManager& chainman, CConnman& connman, const CTxMemPool& mempool, + bool fDryRun = false) EXCLUSIVE_LOCKS_REQUIRED(!cs_coinjoin); /// As a client, submit part of a future mixing transaction to a Masternode to start the process bool SubmitDenominate(CConnman& connman); @@ -310,7 +319,8 @@ class CCoinJoinClientManager bool GetMixingMasternodesInfo(std::vector& vecDmnsRet) const EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); /// Passively run mixing in the background according to the configuration in settings - bool DoAutomaticDenominating(CChainState& active_chainstate, CConnman& connman, CTxMemPool& mempool, bool fDryRun = false) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); + bool DoAutomaticDenominating(ChainstateManager& chainman, CConnman& connman, const CTxMemPool& mempool, + bool fDryRun = false) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); bool TrySubmitDenominate(const CService& mnAddr, CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); bool MarkAlreadyJoinedQueueAsTried(CCoinJoinQueue& dsq) const EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); @@ -326,7 +336,8 @@ class CCoinJoinClientManager void UpdatedBlockTip(const CBlockIndex* pindex); - void DoMaintenance(CChainState& active_chainstate, CConnman& connman, CTxMemPool& mempool) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); + void DoMaintenance(ChainstateManager& chainman, CConnman& connman, const CTxMemPool& mempool) + EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); void GetJsonInfo(UniValue& obj) const EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); }; diff --git a/src/coinjoin/coinjoin.cpp b/src/coinjoin/coinjoin.cpp index c081df92861ac..338b4cf054c42 100644 --- a/src/coinjoin/coinjoin.cpp +++ b/src/coinjoin/coinjoin.cpp @@ -308,10 +308,11 @@ bool CCoinJoinBaseSession::IsValidInOuts(CChainState& active_chainstate, const C // Responsibility for checking fee sanity is moved from the mempool to the client (BroadcastTransaction) // but CoinJoin still requires ATMP with fee sanity checks so we need to implement them separately -bool ATMPIfSaneFee(CChainState& active_chainstate, CTxMemPool& pool, const CTransactionRef &tx, bool test_accept) { +bool ATMPIfSaneFee(ChainstateManager& chainman, const CTransactionRef& tx, bool test_accept) +{ AssertLockHeld(cs_main); - const MempoolAcceptResult result = AcceptToMemoryPool(active_chainstate, pool, tx, /* bypass_limits */ false, /* test_accept */ true); + const MempoolAcceptResult result = chainman.ProcessTransaction(tx, /*test_accept=*/true); if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { /* Fetch fee and fast-fail if ATMP fails regardless */ return false; @@ -322,11 +323,11 @@ bool ATMPIfSaneFee(CChainState& active_chainstate, CTxMemPool& pool, const CTran /* Don't re-run ATMP if only doing test run */ return true; } - return AcceptToMemoryPool(active_chainstate, pool, tx, /* bypass_limits */ false, test_accept).m_result_type == MempoolAcceptResult::ResultType::VALID; + return chainman.ProcessTransaction(tx, test_accept).m_result_type == MempoolAcceptResult::ResultType::VALID; } // check to make sure the collateral provided by the client is valid -bool CoinJoin::IsCollateralValid(CChainState& active_chainstate, CTxMemPool& mempool, const CTransaction& txCollateral) +bool CoinJoin::IsCollateralValid(ChainstateManager& chainman, const CTxMemPool& mempool, const CTransaction& txCollateral) { if (txCollateral.vout.empty()) return false; if (txCollateral.nLockTime != 0) return false; @@ -352,7 +353,7 @@ bool CoinJoin::IsCollateralValid(CChainState& active_chainstate, CTxMemPool& mem return false; } nValueIn += mempoolTx->vout[txin.prevout.n].nValue; - } else if (GetUTXOCoin(active_chainstate, txin.prevout, coin)) { + } else if (GetUTXOCoin(chainman.ActiveChainstate(), txin.prevout, coin)) { nValueIn += coin.out.nValue; } else { LogPrint(BCLog::COINJOIN, "CoinJoin::IsCollateralValid -- Unknown inputs in collateral transaction, txCollateral=%s", txCollateral.ToString()); /* Continued */ @@ -370,8 +371,8 @@ bool CoinJoin::IsCollateralValid(CChainState& active_chainstate, CTxMemPool& mem { LOCK(cs_main); - if (!ATMPIfSaneFee(active_chainstate, mempool, MakeTransactionRef(txCollateral), /*test_accept=*/true)) { - LogPrint(BCLog::COINJOIN, "CoinJoin::IsCollateralValid -- didn't pass AcceptToMemoryPool()\n"); + if (!ATMPIfSaneFee(chainman, MakeTransactionRef(txCollateral), /*test_accept=*/true)) { + LogPrint(BCLog::COINJOIN, "CoinJoin::IsCollateralValid -- didn't pass ATMPIfSaneFee()\n"); return false; } } diff --git a/src/coinjoin/coinjoin.h b/src/coinjoin/coinjoin.h index 8bbab7a4e534e..6bf8e93e112b3 100644 --- a/src/coinjoin/coinjoin.h +++ b/src/coinjoin/coinjoin.h @@ -27,6 +27,7 @@ class CChainState; class CConnman; class CBLSPublicKey; class CBlockIndex; +class ChainstateManager; class CMasternodeSync; class CTxMemPool; class TxValidationState; @@ -368,8 +369,7 @@ namespace CoinJoin constexpr CAmount GetMaxPoolAmount() { return COINJOIN_ENTRY_MAX_SIZE * vecStandardDenominations.front(); } /// If the collateral is valid given by a client - bool IsCollateralValid(CChainState& active_chainstate, CTxMemPool& mempool, const CTransaction& txCollateral); - + bool IsCollateralValid(ChainstateManager& chainman, const CTxMemPool& mempool, const CTransaction& txCollateral); } class CDSTXManager @@ -402,7 +402,7 @@ class CDSTXManager }; -bool ATMPIfSaneFee(CChainState& active_chainstate, CTxMemPool& pool, - const CTransactionRef &tx, bool test_accept = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); +bool ATMPIfSaneFee(ChainstateManager& chainman, const CTransactionRef& tx, bool test_accept = false) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); #endif // BITCOIN_COINJOIN_COINJOIN_H diff --git a/src/coinjoin/context.cpp b/src/coinjoin/context.cpp index 6e3beb7980603..8ce72e3b97fa6 100644 --- a/src/coinjoin/context.cpp +++ b/src/coinjoin/context.cpp @@ -9,20 +9,20 @@ #endif // ENABLE_WALLET #include -CJContext::CJContext(CChainState& chainstate, CConnman& connman, CDeterministicMNManager& dmnman, +CJContext::CJContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, CTxMemPool& mempool, const CActiveMasternodeManager* const mn_activeman, const CMasternodeSync& mn_sync, std::unique_ptr& peerman, bool relay_txes) : dstxman{std::make_unique()}, #ifdef ENABLE_WALLET - walletman{std::make_unique(chainstate, connman, dmnman, mn_metaman, mempool, mn_sync, - queueman, /* is_masternode = */ mn_activeman != nullptr)}, + walletman{std::make_unique(chainman, connman, dmnman, mn_metaman, mempool, mn_sync, queueman, + /* is_masternode = */ mn_activeman != nullptr)}, queueman{relay_txes ? std::make_unique(connman, peerman, *walletman, dmnman, mn_metaman, mn_sync, /* is_masternode = */ mn_activeman != nullptr) : nullptr}, #endif // ENABLE_WALLET - server{std::make_unique(chainstate, connman, dmnman, *dstxman, mn_metaman, mempool, mn_activeman, + server{std::make_unique(chainman, connman, dmnman, *dstxman, mn_metaman, mempool, mn_activeman, mn_sync, peerman)} {} diff --git a/src/coinjoin/context.h b/src/coinjoin/context.h index 08cb67801b0a8..b4e8c6a47f557 100644 --- a/src/coinjoin/context.h +++ b/src/coinjoin/context.h @@ -13,11 +13,11 @@ class CActiveMasternodeManager; class CBlockPolicyEstimator; -class CChainState; class CCoinJoinServer; class CConnman; class CDeterministicMNManager; class CDSTXManager; +class ChainstateManager; class CMasternodeMetaMan; class CMasternodeSync; class CTxMemPool; @@ -31,7 +31,7 @@ class CoinJoinWalletManager; struct CJContext { CJContext() = delete; CJContext(const CJContext&) = delete; - CJContext(CChainState& chainstate, CConnman& connman, CDeterministicMNManager& dmnman, + CJContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, CTxMemPool& mempool, const CActiveMasternodeManager* const mn_activeman, const CMasternodeSync& mn_sync, std::unique_ptr& peerman, bool relay_txes); ~CJContext(); diff --git a/src/coinjoin/server.cpp b/src/coinjoin/server.cpp index 0f3425532150c..856cf5fc7ed5e 100644 --- a/src/coinjoin/server.cpp +++ b/src/coinjoin/server.cpp @@ -331,8 +331,8 @@ void CCoinJoinServer::CommitFinalTransaction() // See if the transaction is valid TRY_LOCK(cs_main, lockMain); mempool.PrioritiseTransaction(hashTx, 0.1 * COIN); - if (!lockMain || !ATMPIfSaneFee(m_chainstate, mempool, finalTransaction)) { - LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n"); + if (!lockMain || !ATMPIfSaneFee(m_chainman, finalTransaction)) { + LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CommitFinalTransaction -- ATMPIfSaneFee() error: Transaction not valid\n"); WITH_LOCK(cs_coinjoin, SetNull()); // not much we can do in this case, just notify clients RelayCompletedTransaction(ERR_INVALID_TX); @@ -463,8 +463,8 @@ void CCoinJoinServer::ChargeRandomFees() const void CCoinJoinServer::ConsumeCollateral(const CTransactionRef& txref) const { LOCK(cs_main); - if (!ATMPIfSaneFee(m_chainstate, mempool, txref, false /* bypass_limits */)) { - LogPrint(BCLog::COINJOIN, "%s -- AcceptToMemoryPool failed\n", __func__); + if (!ATMPIfSaneFee(m_chainman, txref)) { + LogPrint(BCLog::COINJOIN, "%s -- ATMPIfSaneFee failed\n", __func__); } else { Assert(m_peerman)->RelayTransaction(txref->GetHash()); LogPrint(BCLog::COINJOIN, "%s -- Collateral was consumed\n", __func__); @@ -582,7 +582,7 @@ bool CCoinJoinServer::AddEntry(const CCoinJoinEntry& entry, PoolMessage& nMessag return false; } - if (!CoinJoin::IsCollateralValid(m_chainstate, mempool, *entry.txCollateral)) { + if (!CoinJoin::IsCollateralValid(m_chainman, mempool, *entry.txCollateral)) { LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- ERROR: collateral not valid!\n", __func__); nMessageIDRet = ERR_INVALID_COLLATERAL; return false; @@ -616,7 +616,7 @@ bool CCoinJoinServer::AddEntry(const CCoinJoinEntry& entry, PoolMessage& nMessag } bool fConsumeCollateral{false}; - if (!IsValidInOuts(m_chainstate, mempool, vin, entry.vecTxOut, nMessageIDRet, &fConsumeCollateral)) { + if (!IsValidInOuts(m_chainman.ActiveChainstate(), mempool, vin, entry.vecTxOut, nMessageIDRet, &fConsumeCollateral)) { LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- ERROR! IsValidInOuts() failed: %s\n", __func__, CoinJoin::GetMessageByID(nMessageIDRet).translated); if (fConsumeCollateral) { ConsumeCollateral(entry.txCollateral); @@ -693,7 +693,7 @@ bool CCoinJoinServer::IsAcceptableDSA(const CCoinJoinAccept& dsa, PoolMessage& n } // check collateral - if (!fUnitTest && !CoinJoin::IsCollateralValid(m_chainstate, mempool, CTransaction(dsa.txCollateral))) { + if (!fUnitTest && !CoinJoin::IsCollateralValid(m_chainman, mempool, CTransaction(dsa.txCollateral))) { LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- collateral not valid!\n", __func__); nMessageIDRet = ERR_INVALID_COLLATERAL; return false; diff --git a/src/coinjoin/server.h b/src/coinjoin/server.h index 5f528a2bfbfc4..43530ff601109 100644 --- a/src/coinjoin/server.h +++ b/src/coinjoin/server.h @@ -10,11 +10,11 @@ #include class CActiveMasternodeManager; -class CChainState; class CCoinJoinServer; class CDataStream; class CDeterministicMNManager; class CDSTXManager; +class ChainstateManager; class CMasternodeMetaMan; class CNode; class CTxMemPool; @@ -27,7 +27,7 @@ class UniValue; class CCoinJoinServer : public CCoinJoinBaseSession, public CCoinJoinBaseManager { private: - CChainState& m_chainstate; + ChainstateManager& m_chainman; CConnman& connman; CDeterministicMNManager& m_dmnman; CDSTXManager& m_dstxman; @@ -90,11 +90,11 @@ class CCoinJoinServer : public CCoinJoinBaseSession, public CCoinJoinBaseManager void SetNull() override EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin); public: - explicit CCoinJoinServer(CChainState& chainstate, CConnman& _connman, CDeterministicMNManager& dmnman, + explicit CCoinJoinServer(ChainstateManager& chainman, CConnman& _connman, CDeterministicMNManager& dmnman, CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, CTxMemPool& mempool, const CActiveMasternodeManager* const mn_activeman, const CMasternodeSync& mn_sync, std::unique_ptr& peerman) : - m_chainstate(chainstate), + m_chainman(chainman), connman(_connman), m_dmnman(dmnman), m_dstxman(dstxman), diff --git a/src/consensus/validation.h b/src/consensus/validation.h index b06f3c8c83b5f..d4b0c92886ece 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -31,6 +31,7 @@ enum class TxValidationResult { TX_CONFLICT, TX_CONFLICT_LOCK, //!< conflicts with InstantSend lock TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/etc limits + TX_NO_MEMPOOL, //!< this node does not have a mempool so can't validate the transaction }; /** A "reason" why a block was invalid, suitable for determining whether the diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 00a130e7d1d48..2553181eb09ed 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/src/governance/vote.cpp b/src/governance/vote.cpp index 2c1b9f1a0414a..0e4647566a5c1 100644 --- a/src/governance/vote.cpp +++ b/src/governance/vote.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/src/index/base.h b/src/index/base.h index cac28172873ba..403c8c87b1b26 100644 --- a/src/index/base.h +++ b/src/index/base.h @@ -6,13 +6,12 @@ #define BITCOIN_INDEX_BASE_H #include -#include -#include #include #include #include +class CBlock; class CBlockIndex; class CChainState; diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index c7df4be5bae59..eebec0c47b9fe 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -2,18 +2,14 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include #include + +#include #include -#include -#include #include -#include #include -constexpr uint8_t DB_BEST_BLOCK{'B'}; constexpr uint8_t DB_TXINDEX{'t'}; -constexpr uint8_t DB_TXINDEX_BLOCK{'T'}; std::unique_ptr g_txindex; @@ -30,10 +26,6 @@ class TxIndex::DB : public BaseIndex::DB /// Write a batch of transaction positions to the DB. bool WriteTxs(const std::vector>& v_pos); - - /// Migrate txindex data from the block tree DB, where it may be for older nodes that have not - /// been upgraded yet to the new database. - bool MigrateData(CBlockTreeDB& block_tree_db, const CBlockLocator& best_locator); }; TxIndex::DB::DB(size_t n_cache_size, bool f_memory, bool f_wipe) : @@ -54,163 +46,12 @@ bool TxIndex::DB::WriteTxs(const std::vector>& v_ return WriteBatch(batch); } -/* - * Safely persist a transfer of data from the old txindex database to the new one, and compact the - * range of keys updated. This is used internally by MigrateData. - */ -static void WriteTxIndexMigrationBatches(CDBWrapper& newdb, CDBWrapper& olddb, - CDBBatch& batch_newdb, CDBBatch& batch_olddb, - const std::pair& begin_key, - const std::pair& end_key) -{ - // Sync new DB changes to disk before deleting from old DB. - newdb.WriteBatch(batch_newdb, /*fSync=*/ true); - olddb.WriteBatch(batch_olddb); - olddb.CompactRange(begin_key, end_key); - - batch_newdb.Clear(); - batch_olddb.Clear(); -} - -bool TxIndex::DB::MigrateData(CBlockTreeDB& block_tree_db, const CBlockLocator& best_locator) -{ - // The prior implementation of txindex was always in sync with block index - // and presence was indicated with a boolean DB flag. If the flag is set, - // this means the txindex from a previous version is valid and in sync with - // the chain tip. The first step of the migration is to unset the flag and - // write the chain hash to a separate key, DB_TXINDEX_BLOCK. After that, the - // index entries are copied over in batches to the new database. Finally, - // DB_TXINDEX_BLOCK is erased from the old database and the block hash is - // written to the new database. - // - // Unsetting the boolean flag ensures that if the node is downgraded to a - // previous version, it will not see a corrupted, partially migrated index - // -- it will see that the txindex is disabled. When the node is upgraded - // again, the migration will pick up where it left off and sync to the block - // with hash DB_TXINDEX_BLOCK. - bool f_legacy_flag = false; - block_tree_db.ReadFlag("txindex", f_legacy_flag); - if (f_legacy_flag) { - if (!block_tree_db.Write(DB_TXINDEX_BLOCK, best_locator)) { - return error("%s: cannot write block indicator", __func__); - } - if (!block_tree_db.WriteFlag("txindex", false)) { - return error("%s: cannot write block index db flag", __func__); - } - } - - CBlockLocator locator; - if (!block_tree_db.Read(DB_TXINDEX_BLOCK, locator)) { - return true; - } - - int64_t count = 0; - LogPrintf("Upgrading txindex database... [0%%]\n"); - uiInterface.ShowProgress(_("Upgrading txindex database").translated, 0, true); - int report_done = 0; - const size_t batch_size = 1 << 24; // 16 MiB - - CDBBatch batch_newdb(*this); - CDBBatch batch_olddb(block_tree_db); - - std::pair key; - std::pair begin_key{DB_TXINDEX, uint256()}; - std::pair prev_key = begin_key; - - bool interrupted = false; - std::unique_ptr cursor(block_tree_db.NewIterator()); - for (cursor->Seek(begin_key); cursor->Valid(); cursor->Next()) { - if (ShutdownRequested()) { - interrupted = true; - break; - } - - if (!cursor->GetKey(key)) { - return error("%s: cannot get key from valid cursor", __func__); - } - if (key.first != DB_TXINDEX) { - break; - } - - // Log progress every 10%. - if (++count % 256 == 0) { - // Since txids are uniformly random and traversed in increasing order, the high 16 bits - // of the hash can be used to estimate the current progress. - const uint256& txid = key.second; - uint32_t high_nibble = - (static_cast(*(txid.begin() + 0)) << 8) + - (static_cast(*(txid.begin() + 1)) << 0); - int percentage_done = (int)(high_nibble * 100.0 / 65536.0 + 0.5); - - uiInterface.ShowProgress(_("Upgrading txindex database").translated, percentage_done, true); - if (report_done < percentage_done/10) { - LogPrintf("Upgrading txindex database... [%d%%]\n", percentage_done); - report_done = percentage_done/10; - } - } - - CDiskTxPos value; - if (!cursor->GetValue(value)) { - return error("%s: cannot parse txindex record", __func__); - } - batch_newdb.Write(key, value); - batch_olddb.Erase(key); - - if (batch_newdb.SizeEstimate() > batch_size || batch_olddb.SizeEstimate() > batch_size) { - // NOTE: it's OK to delete the key pointed at by the current DB cursor while iterating - // because LevelDB iterators are guaranteed to provide a consistent view of the - // underlying data, like a lightweight snapshot. - WriteTxIndexMigrationBatches(*this, block_tree_db, - batch_newdb, batch_olddb, - prev_key, key); - prev_key = key; - } - } - - // If these final DB batches complete the migration, write the best block - // hash marker to the new database and delete from the old one. This signals - // that the former is fully caught up to that point in the blockchain and - // that all txindex entries have been removed from the latter. - if (!interrupted) { - batch_olddb.Erase(DB_TXINDEX_BLOCK); - batch_newdb.Write(DB_BEST_BLOCK, locator); - } - - WriteTxIndexMigrationBatches(*this, block_tree_db, - batch_newdb, batch_olddb, - begin_key, key); - - if (interrupted) { - LogPrintf("[CANCELLED].\n"); - return false; - } - - uiInterface.ShowProgress("", 100, false); - - LogPrintf("[DONE].\n"); - return true; -} - TxIndex::TxIndex(size_t n_cache_size, bool f_memory, bool f_wipe) : m_db(std::make_unique(n_cache_size, f_memory, f_wipe)) {} TxIndex::~TxIndex() {} -bool TxIndex::Init() -{ - LOCK(cs_main); - - // Attempt to migrate txindex from the old database to the new one. Even if - // chain_tip is null, the node could be reindexing and we still want to - // delete txindex records in the old database. - if (!m_db->MigrateData(*m_chainstate->m_blockman.m_block_tree_db, m_chainstate->m_chain.GetLocator())) { - return false; - } - - return BaseIndex::Init(); -} - bool TxIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex) { // Exclude genesis block transaction because outputs are not spendable. diff --git a/src/index/txindex.h b/src/index/txindex.h index 2924b78dc14df..23a1aef1e4a03 100644 --- a/src/index/txindex.h +++ b/src/index/txindex.h @@ -5,9 +5,7 @@ #ifndef BITCOIN_INDEX_TXINDEX_H #define BITCOIN_INDEX_TXINDEX_H -#include #include -#include /** * TxIndex is used to look up transactions included in the blockchain by hash. @@ -23,9 +21,6 @@ class TxIndex final : public BaseIndex const std::unique_ptr m_db; protected: - /// Override base class init to migrate from old database. - bool Init() override; - bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override; BaseIndex::DB& GetDB() const override; diff --git a/src/init.cpp b/src/init.cpp index 86429fe62b834..09aea533c5cd2 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -583,7 +583,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-maxreceivebuffer=", strprintf("Maximum per-connection receive buffer, *1000 bytes (default: %u)", DEFAULT_MAXRECEIVEBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-maxsendbuffer=", strprintf("Maximum per-connection memory usage for the send buffer, *1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-maxtimeadjustment", strprintf("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)", DEFAULT_MAX_TIME_ADJUSTMENT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-maxuploadtarget=", strprintf("Tries to keep outbound traffic under the given target (in MiB per 24h). Limit does not apply to peers with 'download' permission. 0 = no limit (default: %d)", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + argsman.AddArg("-maxuploadtarget=", strprintf("Tries to keep outbound traffic under the given target per 24h. Limit does not apply to peers with 'download' permission or blocks created within past week. 0 = no limit (default: %s). Optional suffix units [k|K|m|M|g|G|t|T] (default: M). Lowercase is 1000 base while uppercase is 1024 base", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-onion=", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-i2psam=", "I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-i2pacceptincoming", strprintf("Whether to accept inbound I2P connections (default: %i). Ignored if -i2psam is not set. Listening for inbound I2P connections is done through the SAM proxy, not by binding to a local address and port.", DEFAULT_I2P_ACCEPT_INCOMING), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -1440,6 +1440,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) { const ArgsManager& args = *Assert(node.args); const CChainParams& chainparams = Params(); + + auto opt_max_upload = ParseByteUnits(args.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET), ByteUnit::M); + if (!opt_max_upload) { + return InitError(strprintf(_("Unable to parse -maxuploadtarget: '%s' (possible integer overflow?)"), args.GetArg("-maxuploadtarget", ""))); + } + // ********************************************************* Step 4a: application initialization if (!CreatePidFile(args)) { // Detailed error printed inside CreatePidFile(). @@ -1891,7 +1897,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.llmq_ctx->Stop(); } node.llmq_ctx.reset(); - node.llmq_ctx = std::make_unique(chainman.ActiveChainstate(), *node.connman, *node.dmnman, *node.evodb, *node.mn_metaman, *node.mnhf_manager, *node.sporkman, + node.llmq_ctx = std::make_unique(chainman, *node.connman, *node.dmnman, *node.evodb, *node.mn_metaman, *node.mnhf_manager, *node.sporkman, *node.mempool, node.mn_activeman.get(), *node.mn_sync, node.peerman, /* unit_tests = */ false, /* wipe = */ fReset || fReindexChainState); // Enable CMNHFManager::{Process, Undo}Block node.mnhf_manager->ConnectManagers(node.chainman.get(), node.llmq_ctx->qman.get()); @@ -2050,7 +2056,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) const CBlockIndex* tip = chainstate->m_chain.Tip(); RPCNotifyBlockChange(tip); - if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) { + if (tip && tip->nTime > GetTime() + MAX_FUTURE_BLOCK_TIME) { strLoadError = _("The block database contains a block which appears to be from the future. " "This may be due to your computer's date and time being set incorrectly. " "Only rebuild the block database if you are sure that your computer's date and time are correct"); @@ -2153,7 +2159,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 7c: Setup CoinJoin - node.cj_ctx = std::make_unique(chainman.ActiveChainstate(), *node.connman, *node.dmnman, *node.mn_metaman, *node.mempool, + node.cj_ctx = std::make_unique(chainman, *node.connman, *node.dmnman, *node.mn_metaman, *node.mempool, node.mn_activeman.get(), *node.mn_sync, node.peerman, !ignores_incoming_txs); #ifdef ENABLE_WALLET @@ -2193,6 +2199,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 8: start indexers if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { + LOCK(::cs_main); + if (const auto error{CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db))}) { + return InitError(*error); + } + g_txindex = std::make_unique(nTxIndexCache, false, fReindex); if (!g_txindex->Start(chainman.ActiveChainstate())) { return false; @@ -2388,7 +2399,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) connOptions.nSendBufferMaxSize = 1000 * args.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); connOptions.nReceiveFloodSize = 1000 * args.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); connOptions.m_added_nodes = args.GetArgs("-addnode"); - connOptions.nMaxOutboundLimit = 1024 * 1024 * args.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET); + connOptions.nMaxOutboundLimit = *opt_max_upload; connOptions.m_peer_connect_timeout = peer_connect_timeout; // Port to bind to if `-bind=addr` is provided without a `:port` suffix. diff --git a/src/llmq/context.cpp b/src/llmq/context.cpp index 2c6c11446eb41..94da64087ca36 100644 --- a/src/llmq/context.cpp +++ b/src/llmq/context.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -17,36 +18,41 @@ #include #include -LLMQContext::LLMQContext(CChainState& chainstate, CConnman& connman, CDeterministicMNManager& dmnman, CEvoDB& evo_db, - CMasternodeMetaMan& mn_metaman, CMNHFManager& mnhfman, CSporkManager& sporkman, +LLMQContext::LLMQContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, + CEvoDB& evo_db, CMasternodeMetaMan& mn_metaman, CMNHFManager& mnhfman, CSporkManager& sporkman, CTxMemPool& mempool, const CActiveMasternodeManager* const mn_activeman, const CMasternodeSync& mn_sync, const std::unique_ptr& peerman, bool unit_tests, bool wipe) : is_masternode{mn_activeman != nullptr}, bls_worker{std::make_shared()}, dkg_debugman{std::make_unique()}, - quorum_block_processor{std::make_unique(chainstate, dmnman, evo_db)}, - qdkgsman{std::make_unique(*bls_worker, chainstate, connman, dmnman, *dkg_debugman, - mn_metaman, *quorum_block_processor, mn_activeman, sporkman, - peerman, unit_tests, wipe)}, - qman{std::make_unique(*bls_worker, chainstate, connman, dmnman, *qdkgsman, evo_db, - *quorum_block_processor, mn_activeman, mn_sync, sporkman, unit_tests, - wipe)}, - sigman{std::make_unique(connman, mn_activeman, chainstate, *qman, peerman, unit_tests, wipe)}, + quorum_block_processor{std::make_unique(chainman.ActiveChainstate(), dmnman, evo_db)}, + qdkgsman{std::make_unique(*bls_worker, chainman.ActiveChainstate(), connman, dmnman, + *dkg_debugman, mn_metaman, *quorum_block_processor, + mn_activeman, sporkman, peerman, unit_tests, wipe)}, + qman{std::make_unique(*bls_worker, chainman.ActiveChainstate(), connman, dmnman, *qdkgsman, + evo_db, *quorum_block_processor, mn_activeman, mn_sync, sporkman, + unit_tests, wipe)}, + sigman{std::make_unique(connman, mn_activeman, chainman.ActiveChainstate(), *qman, peerman, + unit_tests, wipe)}, shareman{std::make_unique(connman, *sigman, mn_activeman, *qman, sporkman, peerman)}, clhandler{[&]() -> llmq::CChainLocksHandler* const { assert(llmq::chainLocksHandler == nullptr); - llmq::chainLocksHandler = std::make_unique(chainstate, *qman, *sigman, *shareman, - sporkman, mempool, mn_sync, is_masternode); + llmq::chainLocksHandler = std::make_unique(chainman.ActiveChainstate(), *qman, + *sigman, *shareman, sporkman, mempool, + mn_sync, is_masternode); return llmq::chainLocksHandler.get(); }()}, isman{[&]() -> llmq::CInstantSendManager* const { assert(llmq::quorumInstantSendManager == nullptr); - llmq::quorumInstantSendManager = std::make_unique(*llmq::chainLocksHandler, chainstate, connman, *qman, *sigman, *shareman, sporkman, mempool, mn_sync, peerman, is_masternode, unit_tests, wipe); + llmq::quorumInstantSendManager = std::make_unique(*llmq::chainLocksHandler, + chainman.ActiveChainstate(), + connman, *qman, *sigman, *shareman, + sporkman, mempool, mn_sync, peerman, + is_masternode, unit_tests, wipe); return llmq::quorumInstantSendManager.get(); }()}, - ehfSignalsHandler{ - std::make_unique(chainstate, mnhfman, *sigman, *shareman, mempool, *qman)} + ehfSignalsHandler{std::make_unique(chainman, mnhfman, *sigman, *shareman, *qman)} { } diff --git a/src/llmq/context.h b/src/llmq/context.h index 7d41111c4a3df..a42d748621c49 100644 --- a/src/llmq/context.h +++ b/src/llmq/context.h @@ -9,8 +9,8 @@ class CActiveMasternodeManager; class CBLSWorker; -class CChainState; class CConnman; +class ChainstateManager; class CDeterministicMNManager; class CDBWrapper; class CEvoDB; @@ -40,7 +40,7 @@ struct LLMQContext { public: LLMQContext() = delete; LLMQContext(const LLMQContext&) = delete; - LLMQContext(CChainState& chainstate, CConnman& connman, CDeterministicMNManager& dmnman, CEvoDB& evo_db, + LLMQContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, CEvoDB& evo_db, CMasternodeMetaMan& mn_metaman, CMNHFManager& mnhfman, CSporkManager& sporkman, CTxMemPool& mempool, const CActiveMasternodeManager* const mn_activeman, const CMasternodeSync& mn_sync, const std::unique_ptr& peerman, bool unit_tests, bool wipe); diff --git a/src/llmq/ehf_signals.cpp b/src/llmq/ehf_signals.cpp index 3ea7bf8677dbb..c5388e46dd5e0 100644 --- a/src/llmq/ehf_signals.cpp +++ b/src/llmq/ehf_signals.cpp @@ -15,19 +15,17 @@ #include #include // g_txindex #include -#include #include namespace llmq { -CEHFSignalsHandler::CEHFSignalsHandler(CChainState& chainstate, CMNHFManager& mnhfman, CSigningManager& sigman, - CSigSharesManager& shareman, CTxMemPool& mempool, const CQuorumManager& qman) : - chainstate(chainstate), +CEHFSignalsHandler::CEHFSignalsHandler(ChainstateManager& chainman, CMNHFManager& mnhfman, CSigningManager& sigman, + CSigSharesManager& shareman, const CQuorumManager& qman) : + m_chainman(chainman), mnhfman(mnhfman), sigman(sigman), shareman(shareman), - mempool(mempool), qman(qman) { sigman.RegisterRecoveredSigsListener(this); @@ -77,7 +75,7 @@ void CEHFSignalsHandler::trySignEHFSignal(int bit, const CBlockIndex* const pind return; } - const auto quorum = llmq::SelectQuorumForSigning(llmq_params_opt.value(), chainstate.m_chain, qman, requestId); + const auto quorum = llmq::SelectQuorumForSigning(llmq_params_opt.value(), m_chainman.ActiveChain(), qman, requestId); if (!quorum) { LogPrintf("CEHFSignalsHandler::trySignEHFSignal no quorum for id=%s\n", requestId.ToString()); return; @@ -103,7 +101,7 @@ MessageProcessingResult CEHFSignalsHandler::HandleNewRecoveredSig(const CRecover } MessageProcessingResult ret; - const auto ehfSignals = mnhfman.GetSignalsStage(WITH_LOCK(cs_main, return chainstate.m_chain.Tip())); + const auto ehfSignals = mnhfman.GetSignalsStage(WITH_LOCK(cs_main, return m_chainman.ActiveTip())); MNHFTxPayload mnhfPayload; for (const auto& deployment : Params().GetConsensus().vDeployments) { // skip deployments that do not use dip0023 or that have already been mined @@ -126,7 +124,7 @@ MessageProcessingResult CEHFSignalsHandler::HandleNewRecoveredSig(const CRecover CTransactionRef tx_to_sent = MakeTransactionRef(std::move(tx)); LogPrintf("CEHFSignalsHandler::HandleNewRecoveredSig Special EHF TX is created hash=%s\n", tx_to_sent->GetHash().ToString()); LOCK(cs_main); - const MempoolAcceptResult result = AcceptToMemoryPool(chainstate, mempool, tx_to_sent, /* bypass_limits */ false); + const MempoolAcceptResult result = m_chainman.ProcessTransaction(tx_to_sent); if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) { ret.m_transactions.push_back(tx_to_sent->GetHash()); } else { diff --git a/src/llmq/ehf_signals.h b/src/llmq/ehf_signals.h index 41f888d48de85..7798180e770ec 100644 --- a/src/llmq/ehf_signals.h +++ b/src/llmq/ehf_signals.h @@ -10,9 +10,8 @@ #include class CBlockIndex; -class CChainState; +class ChainstateManager; class CMNHFManager; -class CTxMemPool; namespace llmq { @@ -23,11 +22,10 @@ class CSigningManager; class CEHFSignalsHandler : public CRecoveredSigsListener { private: - CChainState& chainstate; + ChainstateManager& m_chainman; CMNHFManager& mnhfman; CSigningManager& sigman; CSigSharesManager& shareman; - CTxMemPool& mempool; const CQuorumManager& qman; /** @@ -36,8 +34,8 @@ class CEHFSignalsHandler : public CRecoveredSigsListener mutable Mutex cs; std::set ids GUARDED_BY(cs); public: - explicit CEHFSignalsHandler(CChainState& chainstate, CMNHFManager& mnhfman, CSigningManager& sigman, - CSigSharesManager& shareman, CTxMemPool& mempool, const CQuorumManager& qman); + explicit CEHFSignalsHandler(ChainstateManager& chainman, CMNHFManager& mnhfman, CSigningManager& sigman, + CSigSharesManager& shareman, const CQuorumManager& qman); ~CEHFSignalsHandler(); diff --git a/src/net.cpp b/src/net.cpp index 579ab7b923d92..474fbec3e7010 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/src/net.h b/src/net.h index 23988dd1d2c38..248a8a6b04016 100644 --- a/src/net.h +++ b/src/net.h @@ -6,7 +6,6 @@ #ifndef BITCOIN_NET_H #define BITCOIN_NET_H -#include #include #include #include @@ -50,14 +49,15 @@ #include #include +class AddrMan; +class BanMan; class CConnman; class CDeterministicMNList; class CDeterministicMNManager; class CMasternodeMetaMan; class CMasternodeSync; -class CScheduler; class CNode; -class BanMan; +class CScheduler; struct bilingual_str; /** Default for -whitelistrelay. */ @@ -100,7 +100,7 @@ static const bool DEFAULT_LISTEN = true; */ static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125; /** The default for -maxuploadtarget. 0 = Unlimited */ -static constexpr uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0; +static const std::string DEFAULT_MAX_UPLOAD_TARGET{"0M"}; /** Default for blocks only*/ static const bool DEFAULT_BLOCKSONLY = false; /** -peertimeout default */ diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 5fa577ce05a2f..9536b8fd07b61 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -856,9 +856,9 @@ class PeerManagerImpl final : public PeerManager EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_recent_confirmed_transactions_mutex); /** - * Filter for transactions that were recently rejected by - * AcceptToMemoryPool. These are not rerequested until the chain tip - * changes, at which point the entire filter is reset. + * Filter for transactions that were recently rejected by the mempool. + * These are not rerequested until the chain tip changes, at which point + * the entire filter is reset. * * Without this filter we'd be re-requesting txs from each of our peers, * increasing bandwidth consumption considerably. For instance, with 100 @@ -1816,6 +1816,7 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat case TxValidationResult::TX_PREMATURE_SPEND: case TxValidationResult::TX_CONFLICT: case TxValidationResult::TX_MEMPOOL_POLICY: + case TxValidationResult::TX_NO_MEMPOOL: // moved from BLOCK case TxValidationResult::TX_BAD_SPECIAL: case TxValidationResult::TX_CONFLICT_LOCK: @@ -3039,7 +3040,7 @@ void PeerManagerImpl::ProcessOrphanTx(std::set& orphan_work_set) const auto [porphanTx, from_peer] = m_orphanage.GetTx(orphanHash); if (porphanTx == nullptr) continue; - const MempoolAcceptResult result = AcceptToMemoryPool(m_chainman.ActiveChainstate(), m_mempool, porphanTx, false /* bypass_limits */); + const MempoolAcceptResult result = m_chainman.ProcessTransaction(porphanTx); const TxValidationState& state = result.m_state; if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) { @@ -3065,7 +3066,6 @@ void PeerManagerImpl::ProcessOrphanTx(std::set& orphan_work_set) break; } } - m_mempool.check(m_chainman.ActiveChainstate()); } bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer, @@ -4223,7 +4223,7 @@ void PeerManagerImpl::ProcessMessage( return; } - const MempoolAcceptResult result = AcceptToMemoryPool(m_chainman.ActiveChainstate(), m_mempool, ptx, false /* bypass_limits */); + const MempoolAcceptResult result = m_chainman.ProcessTransaction(ptx); const TxValidationState& state = result.m_state; if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) { @@ -4234,7 +4234,6 @@ void PeerManagerImpl::ProcessMessage( m_cj_ctx->dstxman->AddDSTX(dstx); } - m_mempool.check(m_chainman.ActiveChainstate()); RelayTransaction(tx.GetHash()); m_orphanage.AddChildrenToWorkSet(tx, peer->m_orphan_work_set); @@ -4306,8 +4305,8 @@ void PeerManagerImpl::ProcessMessage( } // If a tx has been detected by m_recent_rejects, we will have reached - // this point and the tx will have been ignored. Because we haven't run - // the tx through AcceptToMemoryPool, we won't have computed a DoS + // this point and the tx will have been ignored. Because we haven't + // submitted the tx to our mempool, we won't have computed a DoS // score for it or determined exactly why we consider it invalid. // // This means we won't penalize any peer subsequently relaying a DoSy diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp index b36af2c1b587f..b7d3e8c251311 100644 --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -65,8 +65,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t if (max_tx_fee > 0) { // First, call ATMP with test_accept and check the fee. If ATMP // fails here, return error immediately. - const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, - bypass_limits, true /* test_accept */); + const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/true, bypass_limits); if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { return HandleATMPError(result.m_state, err_string.original); } else if (result.m_base_fees.value() > max_tx_fee) { @@ -74,8 +73,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t } } // Try to submit the transaction to the mempool. - const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, - bypass_limits, false /* test_accept */); + const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/false, bypass_limits); if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { return HandleATMPError(result.m_state, err_string.original); } diff --git a/src/rpc/coinjoin.cpp b/src/rpc/coinjoin.cpp index 68210881a78d0..ccaaa840ecf90 100644 --- a/src/rpc/coinjoin.cpp +++ b/src/rpc/coinjoin.cpp @@ -134,10 +134,10 @@ static RPCHelpMan coinjoin_start() throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing has been started already."); } - const ChainstateManager& chainman = EnsureChainman(node); + ChainstateManager& chainman = EnsureChainman(node); CTxMemPool& mempool = EnsureMemPool(node); CConnman& connman = EnsureConnman(node); - bool result = cj_clientman->DoAutomaticDenominating(chainman.ActiveChainstate(), connman, mempool); + bool result = cj_clientman->DoAutomaticDenominating(chainman, connman, mempool); return "Mixing " + (result ? "started successfully" : ("start failed: " + cj_clientman->GetStatuses().original + ", will retry")); }, }; diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index bdee7e77402af..da7745374473d 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -13,13 +14,13 @@ #include #include #include -#include #include +#include #include #include #include #include -#include +#include #include #include #include diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 7d5418c829b8e..46fd76fbd5735 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -5,6 +5,7 @@ #include +#include #include #include #include diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index fca81b4c7ef16..f800db45f4610 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1246,12 +1246,13 @@ static RPCHelpMan testmempoolaccept() NodeContext& node = EnsureAnyNodeContext(request.context); CTxMemPool& mempool = EnsureMemPool(node); - CChainState& chainstate = EnsureChainman(node).ActiveChainstate(); + ChainstateManager& chainman = EnsureChainman(node); + CChainState& chainstate = chainman.ActiveChainstate(); const PackageMempoolAcceptResult package_result = [&] { LOCK(::cs_main); if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /* test_accept */ true); return PackageMempoolAcceptResult(txns[0]->GetHash(), - AcceptToMemoryPool(chainstate, mempool, txns[0], /* bypass_limits */ false, /* test_accept*/ true)); + chainman.ProcessTransaction(txns[0], /*test_accept=*/ true)); }(); UniValue rpc_result(UniValue::VARR); diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp index ead124552bcd3..75afc58bc45fd 100644 --- a/src/test/fuzz/connman.cpp +++ b/src/test/fuzz/connman.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include #include diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp index 9455a05ce398a..b3c562ee47dca 100644 --- a/src/test/fuzz/net.cpp +++ b/src/test/fuzz/net.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include #include diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index c689b52cc6881..d42b42122cae4 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -80,7 +80,7 @@ void SetMempoolConstraints(ArgsManager& args, FuzzedDataProvider& fuzzed_data_pr void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, const NodeContext& node, CChainState& chainstate) { - WITH_LOCK(::cs_main, tx_pool.check(chainstate)); + WITH_LOCK(::cs_main, tx_pool.check(chainstate.CoinsTip(), chainstate.m_chain.Height() + 1)); { BlockAssembler::Options options; options.nBlockMaxSize = fuzzed_data_provider.ConsumeIntegralInRange(0U, MaxBlockSize(true)); @@ -97,7 +97,7 @@ void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, con std::vector all_txids; tx_pool.queryHashes(all_txids); assert(all_txids.size() < info_all.size()); - WITH_LOCK(::cs_main, tx_pool.check(chainstate)); + WITH_LOCK(::cs_main, tx_pool.check(chainstate.CoinsTip(), chainstate.m_chain.Height() + 1)); } SyncWithValidationInterfaceQueue(); } diff --git a/src/test/script_parse_tests.cpp b/src/test/script_parse_tests.cpp new file mode 100644 index 0000000000000..5b8b6a725f712 --- /dev/null +++ b/src/test/script_parse_tests.cpp @@ -0,0 +1,55 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include