diff options
42 files changed, 652 insertions, 489 deletions
diff --git a/build_msvc/common.init.vcxproj.in b/build_msvc/common.init.vcxproj.in index 9710e50744..24d5922182 100644 --- a/build_msvc/common.init.vcxproj.in +++ b/build_msvc/common.init.vcxproj.in @@ -88,7 +88,7 @@ <WarningLevel>Level3</WarningLevel> <PrecompiledHeader>NotUsing</PrecompiledHeader> <AdditionalOptions>/utf-8 /Zc:__cplusplus /std:c++20 %(AdditionalOptions)</AdditionalOptions> - <DisableSpecificWarnings>4018;4244;4267;4334;4715;4805</DisableSpecificWarnings> + <DisableSpecificWarnings>4018;4244;4267;4715;4805</DisableSpecificWarnings> <TreatWarningAsError>true</TreatWarningAsError> <PreprocessorDefinitions>_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;ZMQ_STATIC;NOMINMAX;WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;_WIN32_WINNT=0x0601;_WIN32_IE=0x0501;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>..\..\src;..\..\src\minisketch\include;..\..\src\univalue\include;..\..\src\secp256k1\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh index 2b57411c3f..6f9a4709dd 100755 --- a/ci/lint/04_install.sh +++ b/ci/lint/04_install.sh @@ -7,7 +7,7 @@ export LC_ALL=C ${CI_RETRY_EXE} apt-get update -${CI_RETRY_EXE} apt-get install -y clang-format-9 python3-pip curl git gawk jq +${CI_RETRY_EXE} apt-get install -y python3-pip curl git gawk jq ( # Temporary workaround for https://github.com/bitcoin/bitcoin/pull/26130#issuecomment-1260499544 # Can be removed once the underlying image is bumped to something that includes git2.34 or later @@ -15,8 +15,6 @@ ${CI_RETRY_EXE} apt-get install -y clang-format-9 python3-pip curl git gawk jq ${CI_RETRY_EXE} apt-get update ${CI_RETRY_EXE} apt-get install -y --reinstall git ) -update-alternatives --install /usr/bin/clang-format clang-format "$(which clang-format-9 )" 100 -update-alternatives --install /usr/bin/clang-format-diff clang-format-diff "$(which clang-format-diff-9)" 100 ${CI_RETRY_EXE} pip3 install codespell==2.2.1 ${CI_RETRY_EXE} pip3 install flake8==4.0.1 diff --git a/configure.ac b/configure.ac index 82cb469864..936ade6bc3 100644 --- a/configure.ac +++ b/configure.ac @@ -588,8 +588,8 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ CXXFLAGS="$TEMP_CXXFLAGS" # ARM -AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc+crypto], [ARM_CRC_CXXFLAGS="-march=armv8-a+crc+crypto"], [], [$CXXFLAG_WERROR]) -AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc+crypto], [ARM_SHANI_CXXFLAGS="-march=armv8-a+crc+crypto"], [], [$CXXFLAG_WERROR]) +AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc], [ARM_CRC_CXXFLAGS="-march=armv8-a+crc"], [], [$CXXFLAG_WERROR]) +AX_CHECK_COMPILE_FLAG([-march=armv8-a+crypto], [ARM_SHANI_CXXFLAGS="-march=armv8-a+crypto"], [], [$CXXFLAG_WERROR]) TEMP_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$ARM_CRC_CXXFLAGS $CXXFLAGS" diff --git a/depends/packages/capnp.mk b/depends/packages/capnp.mk index 8a3a14810d..f4778c1ecd 100644 --- a/depends/packages/capnp.mk +++ b/depends/packages/capnp.mk @@ -6,8 +6,15 @@ $(package)_file_name=$(native_$(package)_file_name) $(package)_sha256_hash=$(native_$(package)_sha256_hash) $(package)_dependencies=native_$(package) +define $(package)_set_vars := +$(package)_config_opts := --with-external-capnp +$(package)_config_opts += CAPNP="$$(native_capnp_prefixbin)/capnp" +$(package)_config_opts += CAPNP_CXX="$$(native_capnp_prefixbin)/capnp-c++" +$(package)_config_opts_android := --disable-shared +endef + define $(package)_config_cmds - $($(package)_autoconf) --with-external-capnp + $($(package)_autoconf) endef define $(package)_build_cmds diff --git a/src/Makefile.am b/src/Makefile.am index bc1c6a0d0f..caeaee511f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -133,6 +133,7 @@ BITCOIN_CORE_H = \ clientversion.h \ coins.h \ common/bloom.h \ + common/run_command.h \ compat/assumptions.h \ compat/byteswap.h \ compat/compat.h \ @@ -616,7 +617,7 @@ libbitcoin_consensus_a_SOURCES = \ version.h # common: shared between bitcoind, and bitcoin-qt and non-server tools -libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_common_a_SOURCES = \ base58.cpp \ @@ -624,6 +625,7 @@ libbitcoin_common_a_SOURCES = \ chainparams.cpp \ coins.cpp \ common/bloom.cpp \ + common/run_command.cpp \ compressor.cpp \ core_read.cpp \ core_write.cpp \ diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include index 11b5c12062..b35d713d57 100644 --- a/src/Makefile.test_fuzz.include +++ b/src/Makefile.test_fuzz.include @@ -10,12 +10,13 @@ EXTRA_LIBRARIES += \ TEST_FUZZ_H = \ test/fuzz/fuzz.h \ test/fuzz/FuzzedDataProvider.h \ - test/fuzz/mempool_utils.h \ - test/fuzz/util.h + test/fuzz/util.h \ + test/fuzz/util/mempool.h libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) libtest_fuzz_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libtest_fuzz_a_SOURCES = \ test/fuzz/fuzz.cpp \ test/fuzz/util.cpp \ + test/fuzz/util/mempool.cpp \ $(TEST_FUZZ_H) diff --git a/src/bech32.cpp b/src/bech32.cpp index dce9b2e4cc..8e0025b8f4 100644 --- a/src/bech32.cpp +++ b/src/bech32.cpp @@ -241,7 +241,7 @@ constexpr std::array<uint32_t, 25> GenerateSyndromeConstants() { std::array<uint32_t, 25> SYNDROME_CONSTS{}; for (int k = 1; k < 6; ++k) { for (int shift = 0; shift < 5; ++shift) { - int16_t b = GF1024_LOG.at(1 << shift); + int16_t b = GF1024_LOG.at(size_t{1} << shift); int16_t c0 = GF1024_EXP.at((997*k + b) % 1023); int16_t c1 = GF1024_EXP.at((998*k + b) % 1023); int16_t c2 = GF1024_EXP.at((999*k + b) % 1023); diff --git a/src/common/run_command.cpp b/src/common/run_command.cpp new file mode 100644 index 0000000000..6ad9f75b5d --- /dev/null +++ b/src/common/run_command.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + +#include <common/run_command.h> + +#include <tinyformat.h> +#include <univalue.h> + +#ifdef ENABLE_EXTERNAL_SIGNER +#if defined(__GNUC__) +// Boost 1.78 requires the following workaround. +// See: https://github.com/boostorg/process/issues/235 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnarrowing" +#endif +#include <boost/process.hpp> +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#endif // ENABLE_EXTERNAL_SIGNER + +UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in) +{ +#ifdef ENABLE_EXTERNAL_SIGNER + namespace bp = boost::process; + + UniValue result_json; + bp::opstream stdin_stream; + bp::ipstream stdout_stream; + bp::ipstream stderr_stream; + + if (str_command.empty()) return UniValue::VNULL; + + bp::child c( + str_command, + bp::std_out > stdout_stream, + bp::std_err > stderr_stream, + bp::std_in < stdin_stream + ); + if (!str_std_in.empty()) { + stdin_stream << str_std_in << std::endl; + } + stdin_stream.pipe().close(); + + std::string result; + std::string error; + std::getline(stdout_stream, result); + std::getline(stderr_stream, error); + + c.wait(); + const int n_error = c.exit_code(); + if (n_error) throw std::runtime_error(strprintf("RunCommandParseJSON error: process(%s) returned %d: %s\n", str_command, n_error, error)); + if (!result_json.read(result)) throw std::runtime_error("Unable to parse JSON: " + result); + + return result_json; +#else + throw std::runtime_error("Compiled without external signing support (required for external signing)."); +#endif // ENABLE_EXTERNAL_SIGNER +} diff --git a/src/common/run_command.h b/src/common/run_command.h new file mode 100644 index 0000000000..2fbdc071ee --- /dev/null +++ b/src/common/run_command.h @@ -0,0 +1,21 @@ +// Copyright (c) 2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_COMMON_RUN_COMMAND_H +#define BITCOIN_COMMON_RUN_COMMAND_H + +#include <string> + +class UniValue; + +/** + * Execute a command which returns JSON, and parse the result. + * + * @param str_command The command to execute, including any arguments + * @param str_std_in string to pass to stdin + * @return parsed JSON + */ +UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in=""); + +#endif // BITCOIN_COMMON_RUN_COMMAND_H diff --git a/src/external_signer.cpp b/src/external_signer.cpp index 094314e878..0e582629f7 100644 --- a/src/external_signer.cpp +++ b/src/external_signer.cpp @@ -3,10 +3,10 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <chainparams.h> +#include <common/run_command.h> #include <core_io.h> #include <psbt.h> #include <util/strencodings.h> -#include <util/system.h> #include <external_signer.h> #include <algorithm> diff --git a/src/index/base.cpp b/src/index/base.cpp index 88c2ce98fa..3eea09b17d 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -298,6 +298,10 @@ void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const } interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex, block.get()); if (CustomAppend(block_info)) { + // Setting the best block index is intentionally the last step of this + // function, so BlockUntilSyncedToCurrentChain callers waiting for the + // best block index to be updated can rely on the block being fully + // processed, and the index object being safe to delete. SetBestBlockIndex(pindex); } else { FatalError("%s: Failed to write block %s to index", @@ -414,10 +418,17 @@ IndexSummary BaseIndex::GetSummary() const void BaseIndex::SetBestBlockIndex(const CBlockIndex* block) { assert(!node::fPruneMode || AllowPrune()); - m_best_block_index = block; if (AllowPrune() && block) { node::PruneLockInfo prune_lock; prune_lock.height_first = block->nHeight; WITH_LOCK(::cs_main, m_chainstate->m_blockman.UpdatePruneLock(GetName(), prune_lock)); } + + // Intentionally set m_best_block_index as the last step in this function, + // after updating prune locks above, and after making any other references + // to *this, so the BlockUntilSyncedToCurrentChain function (which checks + // m_best_block_index as an optimization) can be used to wait for the last + // BlockConnected notification and safely assume that prune locks are + // updated and that the index object is safe to delete. + m_best_block_index = block; } diff --git a/src/kernel/mempool_limits.h b/src/kernel/mempool_limits.h index e192e7e6cd..8d4495c3cb 100644 --- a/src/kernel/mempool_limits.h +++ b/src/kernel/mempool_limits.h @@ -24,6 +24,15 @@ struct MemPoolLimits { int64_t descendant_count{DEFAULT_DESCENDANT_LIMIT}; //! The maximum allowed size in virtual bytes of an entry and its descendants within a package. int64_t descendant_size_vbytes{DEFAULT_DESCENDANT_SIZE_LIMIT_KVB * 1'000}; + + /** + * @return MemPoolLimits with all the limits set to the maximum + */ + static constexpr MemPoolLimits NoLimits() + { + int64_t no_limit{std::numeric_limits<int64_t>::max()}; + return {no_limit, no_limit, no_limit, no_limit}; + } }; } // namespace kernel diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index aa7ddec770..8a0011a629 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -660,8 +660,7 @@ public: std::string unused_error_string; LOCK(m_node.mempool->cs); return m_node.mempool->CalculateMemPoolAncestors( - entry, ancestors, limits.ancestor_count, limits.ancestor_size_vbytes, - limits.descendant_count, limits.descendant_size_vbytes, unused_error_string); + entry, ancestors, limits, unused_error_string); } CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override { diff --git a/src/node/miner.cpp b/src/node/miner.cpp index b277188c1f..e11ec5b0f1 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -105,7 +105,7 @@ void BlockAssembler::resetBlock() std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) { - int64_t nTimeStart = GetTimeMicros(); + const auto time_start{SteadyClock::now()}; resetBlock(); @@ -143,7 +143,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc addPackageTxs(*m_mempool, nPackagesSelected, nDescendantsUpdated); } - int64_t nTime1 = GetTimeMicros(); + const auto time_1{SteadyClock::now()}; m_last_block_num_txs = nBlockTx; m_last_block_weight = nBlockWeight; @@ -173,9 +173,12 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc if (!TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev, GetAdjustedTime, false, false)) { throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString())); } - int64_t nTime2 = GetTimeMicros(); + const auto time_2{SteadyClock::now()}; - LogPrint(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", 0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, 0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart)); + LogPrint(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", + Ticks<MillisecondsDouble>(time_1 - time_start), nPackagesSelected, nDescendantsUpdated, + Ticks<MillisecondsDouble>(time_2 - time_1), + Ticks<MillisecondsDouble>(time_2 - time_start)); return std::move(pblocktemplate); } @@ -257,13 +260,9 @@ static int UpdatePackagesForAdded(const CTxMemPool& mempool, modtxiter mit = mapModifiedTx.find(desc); if (mit == mapModifiedTx.end()) { CTxMemPoolModifiedEntry modEntry(desc); - modEntry.nSizeWithAncestors -= it->GetTxSize(); - modEntry.nModFeesWithAncestors -= it->GetModifiedFee(); - modEntry.nSigOpCostWithAncestors -= it->GetSigOpCost(); - mapModifiedTx.insert(modEntry); - } else { - mapModifiedTx.modify(mit, update_for_parent_inclusion(it)); + mit = mapModifiedTx.insert(modEntry).first; } + mapModifiedTx.modify(mit, update_for_parent_inclusion(it)); } } return nDescendantsUpdated; @@ -396,9 +395,8 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele } CTxMemPool::setEntries ancestors; - uint64_t nNoLimit = std::numeric_limits<uint64_t>::max(); std::string dummy; - mempool.CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); + mempool.CalculateMemPoolAncestors(*iter, ancestors, CTxMemPool::Limits::NoLimits(), dummy, false); onlyUnconfirmed(ancestors); ancestors.insert(iter); diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 2b940be07e..22defb91a9 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -997,8 +997,9 @@ bool CBlockPolicyEstimator::Read(AutoFile& filein) return true; } -void CBlockPolicyEstimator::FlushUnconfirmed() { - int64_t startclear = GetTimeMicros(); +void CBlockPolicyEstimator::FlushUnconfirmed() +{ + const auto startclear{SteadyClock::now()}; LOCK(m_cs_fee_estimator); size_t num_entries = mapMemPoolTxs.size(); // Remove every entry in mapMemPoolTxs @@ -1006,8 +1007,8 @@ void CBlockPolicyEstimator::FlushUnconfirmed() { auto mi = mapMemPoolTxs.begin(); _removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs } - int64_t endclear = GetTimeMicros(); - LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, (endclear - startclear)*0.000001); + const auto endclear{SteadyClock::now()}; + LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear)); } FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee) diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp index 6098caced9..55f47f485b 100644 --- a/src/policy/rbf.cpp +++ b/src/policy/rbf.cpp @@ -36,10 +36,9 @@ RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool) // If all the inputs have nSequence >= maxint-1, it still might be // signaled for RBF if any unconfirmed parents have signaled. - uint64_t noLimit = std::numeric_limits<uint64_t>::max(); std::string dummy; CTxMemPoolEntry entry = *pool.mapTx.find(tx.GetHash()); - pool.CalculateMemPoolAncestors(entry, ancestors, noLimit, noLimit, noLimit, noLimit, dummy, false); + pool.CalculateMemPoolAncestors(entry, ancestors, CTxMemPool::Limits::NoLimits(), dummy, false); for (CTxMemPool::txiter it : ancestors) { if (SignalsOptInRBF(it->GetTx())) { diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index e390a7c15c..706d783942 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -449,9 +449,8 @@ static RPCHelpMan getmempoolancestors() } CTxMemPool::setEntries setAncestors; - uint64_t noLimit = std::numeric_limits<uint64_t>::max(); std::string dummy; - mempool.CalculateMemPoolAncestors(*it, setAncestors, noLimit, noLimit, noLimit, noLimit, dummy, false); + mempool.CalculateMemPoolAncestors(*it, setAncestors, CTxMemPool::Limits::NoLimits(), dummy, false); if (!fVerbose) { UniValue o(UniValue::VARR); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index c4bd03fa9f..98383fdaca 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -730,10 +730,10 @@ static RPCHelpMan getblocktemplate() // Update block static CBlockIndex* pindexPrev; - static int64_t nStart; + static int64_t time_start; static std::unique_ptr<CBlockTemplate> pblocktemplate; if (pindexPrev != active_chain.Tip() || - (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) + (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5)) { // Clear pindexPrev so future calls make a new block, despite any failures from here on pindexPrev = nullptr; @@ -741,7 +741,7 @@ static RPCHelpMan getblocktemplate() // Store the pindexBest used before CreateNewBlock, to avoid races nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrevNew = active_chain.Tip(); - nStart = GetTime(); + time_start = GetTime(); // Create new block CScript scriptDummy = CScript() << OP_TRUE; diff --git a/src/streams.h b/src/streams.h index 24778ab331..ce1ba26d45 100644 --- a/src/streams.h +++ b/src/streams.h @@ -269,7 +269,6 @@ public: // Stream subset // bool eof() const { return size() == 0; } - CDataStream* rdbuf() { return this; } int in_avail() const { return size(); } void SetType(int n) { nType = n; } diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp index c52fca5fe8..f05248ab47 100644 --- a/src/test/fuzz/integer.cpp +++ b/src/test/fuzz/integer.cpp @@ -12,6 +12,7 @@ #include <key_io.h> #include <memusage.h> #include <netbase.h> +#include <policy/policy.h> #include <policy/settings.h> #include <pow.h> #include <protocol.h> diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp index 637ba503c6..a3d57dbdd5 100644 --- a/src/test/fuzz/policy_estimator.cpp +++ b/src/test/fuzz/policy_estimator.cpp @@ -8,6 +8,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/fuzz/util/mempool.h> #include <test/util/setup_common.h> #include <txmempool.h> diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp index 1a06ae886e..e06e57d919 100644 --- a/src/test/fuzz/rbf.cpp +++ b/src/test/fuzz/rbf.cpp @@ -9,6 +9,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/fuzz/util/mempool.h> #include <test/util/setup_common.h> #include <txmempool.h> diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index 283a146369..a34e501fcc 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -8,8 +8,8 @@ #include <node/miner.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> -#include <test/fuzz/mempool_utils.h> #include <test/fuzz/util.h> +#include <test/fuzz/util/mempool.h> #include <test/util/mining.h> #include <test/util/script.h> #include <test/util/setup_common.h> diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index 8625898855..0080b1e56e 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -478,21 +478,6 @@ CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) no return tx_destination; } -CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept -{ - // Avoid: - // policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long' - // - // Reproduce using CFeeRate(348732081484775, 10).GetFeePerK() - const CAmount fee = std::min<CAmount>(ConsumeMoney(fuzzed_data_provider), std::numeric_limits<CAmount>::max() / static_cast<CAmount>(100000)); - assert(MoneyRange(fee)); - const int64_t time = fuzzed_data_provider.ConsumeIntegral<int64_t>(); - const unsigned int entry_height = fuzzed_data_provider.ConsumeIntegral<unsigned int>(); - const bool spends_coinbase = fuzzed_data_provider.ConsumeBool(); - const unsigned int sig_op_cost = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, MAX_BLOCK_SIGOPS_COST); - return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}}; -} - bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept { for (const CTxIn& tx_in : tx.vin) { diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index 36d55079cb..a354df2bf7 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -23,7 +23,6 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/util/net.h> -#include <txmempool.h> #include <uint256.h> #include <version.h> @@ -213,8 +212,6 @@ template <typename WeakEnumType, size_t size> return UintToArith256(ConsumeUInt256(fuzzed_data_provider)); } -[[nodiscard]] CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept; - [[nodiscard]] CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept; template <typename T> diff --git a/src/test/fuzz/util/mempool.cpp b/src/test/fuzz/util/mempool.cpp new file mode 100644 index 0000000000..d0053f77d2 --- /dev/null +++ b/src/test/fuzz/util/mempool.cpp @@ -0,0 +1,27 @@ +// Copyright (c) 2022 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 <consensus/amount.h> +#include <primitives/transaction.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/util.h> +#include <test/fuzz/util/mempool.h> +#include <txmempool.h> + +#include <limits> + +CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept +{ + // Avoid: + // policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long' + // + // Reproduce using CFeeRate(348732081484775, 10).GetFeePerK() + const CAmount fee{ConsumeMoney(fuzzed_data_provider, /*max=*/std::numeric_limits<CAmount>::max() / CAmount{100'000})}; + assert(MoneyRange(fee)); + const int64_t time = fuzzed_data_provider.ConsumeIntegral<int64_t>(); + const unsigned int entry_height = fuzzed_data_provider.ConsumeIntegral<unsigned int>(); + const bool spends_coinbase = fuzzed_data_provider.ConsumeBool(); + const unsigned int sig_op_cost = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, MAX_BLOCK_SIGOPS_COST); + return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}}; +} diff --git a/src/test/fuzz/mempool_utils.h b/src/test/fuzz/util/mempool.h index c172e8c4b7..4304e5294e 100644 --- a/src/test/fuzz/mempool_utils.h +++ b/src/test/fuzz/util/mempool.h @@ -2,9 +2,12 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_TEST_FUZZ_MEMPOOL_UTILS_H -#define BITCOIN_TEST_FUZZ_MEMPOOL_UTILS_H +#ifndef BITCOIN_TEST_FUZZ_UTIL_MEMPOOL_H +#define BITCOIN_TEST_FUZZ_UTIL_MEMPOOL_H +#include <primitives/transaction.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <txmempool.h> #include <validation.h> class DummyChainState final : public Chainstate @@ -16,4 +19,6 @@ public: } }; -#endif // BITCOIN_TEST_FUZZ_MEMPOOL_UTILS_H +[[nodiscard]] CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept; + +#endif // BITCOIN_TEST_FUZZ_UTIL_MEMPOOL_H diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp index 8241dff189..d96609416b 100644 --- a/src/test/fuzz/validation_load_mempool.cpp +++ b/src/test/fuzz/validation_load_mempool.cpp @@ -9,8 +9,8 @@ #include <node/mempool_persist_args.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> -#include <test/fuzz/mempool_utils.h> #include <test/fuzz/util.h> +#include <test/fuzz/util/mempool.h> #include <test/util/setup_common.h> #include <txmempool.h> #include <util/time.h> diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 8c745b07b9..19f457b8dd 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -203,7 +203,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) CTxMemPool::setEntries setAncestorsCalculated; std::string dummy; - BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); + BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2'000'000LL).FromTx(tx7), setAncestorsCalculated, CTxMemPool::Limits::NoLimits(), dummy), true); BOOST_CHECK(setAncestorsCalculated == setAncestors); pool.addUnchecked(entry.FromTx(tx7), setAncestors); @@ -261,7 +261,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx10.vout[0].nValue = 10 * COIN; setAncestorsCalculated.clear(); - BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(4).FromTx(tx10), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); + BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200'000LL).Time(4).FromTx(tx10), setAncestorsCalculated, CTxMemPool::Limits::NoLimits(), dummy), true); BOOST_CHECK(setAncestorsCalculated == setAncestors); pool.addUnchecked(entry.FromTx(tx10), setAncestors); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index c7ce998f2d..696a799872 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -2,7 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <chainparams.h> #include <coins.h> #include <consensus/consensus.h> #include <consensus/merkle.h> @@ -30,15 +29,24 @@ using node::CBlockTemplate; namespace miner_tests { struct MinerTestingSetup : public TestingSetup { - void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs); - void TestBasicMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs); - void TestPrioritisedMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs); - bool TestSequenceLocks(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs) + void TestPackageSelection(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + void TestBasicMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + void TestPrioritisedMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + bool TestSequenceLocks(const CTransaction& tx, CTxMemPool& tx_mempool) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { - CCoinsViewMemPool view_mempool(&m_node.chainman->ActiveChainstate().CoinsTip(), *m_node.mempool); + CCoinsViewMemPool view_mempool{&m_node.chainman->ActiveChainstate().CoinsTip(), tx_mempool}; return CheckSequenceLocksAtTip(m_node.chainman->ActiveChain().Tip(), view_mempool, tx); } - BlockAssembler AssemblerForTest(const CChainParams& params); + CTxMemPool& MakeMempool() + { + // Delete the previous mempool to ensure with valgrind that the old + // pointer is not accessed, when the new one should be accessed + // instead. + m_node.mempool.reset(); + m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node)); + return *m_node.mempool; + } + BlockAssembler AssemblerForTest(CTxMemPool& tx_mempool); }; } // namespace miner_tests @@ -46,13 +54,13 @@ BOOST_FIXTURE_TEST_SUITE(miner_tests, MinerTestingSetup) static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE); -BlockAssembler MinerTestingSetup::AssemblerForTest(const CChainParams& params) +BlockAssembler MinerTestingSetup::AssemblerForTest(CTxMemPool& tx_mempool) { BlockAssembler::Options options; options.nBlockMaxWeight = MAX_BLOCK_WEIGHT; options.blockMinFeeRate = blockMinFeeRate; - return BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}; + return BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}; } constexpr static struct { @@ -89,8 +97,10 @@ static CBlockIndex CreateBlockIndex(int nHeight, CBlockIndex* active_chain_tip) // Test suite for ancestor feerate transaction selection. // Implemented as an additional function, rather than a separate test case, // to allow reusing the blockchain created in CreateNewBlock_validity. -void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) +void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) { + CTxMemPool& tx_mempool{MakeMempool()}; + LOCK(tx_mempool.cs); // Test the ancestor feerate transaction selection. TestMemPoolEntryHelper entry; @@ -105,21 +115,21 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co tx.vout[0].nValue = 5000000000LL - 1000; // This tx has a low fee: 1000 satoshis uint256 hashParentTx = tx.GetHash(); // save this txid for later use - m_node.mempool->addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a medium fee: 10000 satoshis tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = 5000000000LL - 10000; uint256 hashMediumFeeTx = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a high fee, but depends on the first transaction tx.vin[0].prevout.hash = hashParentTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee uint256 hashHighFeeTx = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); - std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); + std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 4U); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx); BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx); @@ -129,7 +139,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co tx.vin[0].prevout.hash = hashHighFeeTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee uint256 hashFreeTx = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(0).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(0).FromTx(tx)); size_t freeTxSize = ::GetSerializeSize(tx, PROTOCOL_VERSION); // Calculate a fee on child transaction that will put the package just @@ -139,8 +149,8 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co tx.vin[0].prevout.hash = hashFreeTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse; uint256 hashLowFeeTx = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(feeToUse).FromTx(tx)); - pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); + tx_mempool.addUnchecked(entry.Fee(feeToUse).FromTx(tx)); + pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); // Verify that the free tx and the low fee tx didn't get selected for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx); @@ -150,11 +160,11 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co // Test that packages above the min relay fee do get included, even if one // of the transactions is below the min relay fee // Remove the low fee transaction and replace with a higher fee transaction - m_node.mempool->removeRecursive(CTransaction(tx), MemPoolRemovalReason::REPLACED); + tx_mempool.removeRecursive(CTransaction(tx), MemPoolRemovalReason::REPLACED); tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee hashLowFeeTx = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(feeToUse+2).FromTx(tx)); - pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); + tx_mempool.addUnchecked(entry.Fee(feeToUse + 2).FromTx(tx)); + pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U); BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx); @@ -167,7 +177,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co tx.vout[0].nValue = 5000000000LL - 100000000; tx.vout[1].nValue = 100000000; // 1BTC output uint256 hashFreeTx2 = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); // This tx can't be mined by itself tx.vin[0].prevout.hash = hashFreeTx2; @@ -175,8 +185,8 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co feeToUse = blockMinFeeRate.GetFee(freeTxSize); tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse; uint256 hashLowFeeTx2 = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); - pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); + tx_mempool.addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); + pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); // Verify that this tx isn't selected. for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { @@ -188,13 +198,13 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co // as well. tx.vin[0].prevout.n = 1; tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee - m_node.mempool->addUnchecked(entry.Fee(10000).FromTx(tx)); - pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); + tx_mempool.addUnchecked(entry.Fee(10000).FromTx(tx)); + pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 9U); BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2); } -void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight) +void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight) { uint256 hash; CMutableTransaction tx; @@ -202,172 +212,205 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C entry.nFee = 11; entry.nHeight = 11; - // Just to make sure we can still make simple blocks - auto pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); - BOOST_CHECK(pblocktemplate); - - const CAmount BLOCKSUBSIDY = 50*COIN; + const CAmount BLOCKSUBSIDY = 50 * COIN; const CAmount LOWFEE = CENT; const CAmount HIGHFEE = COIN; - const CAmount HIGHERFEE = 4*COIN; + const CAmount HIGHERFEE = 4 * COIN; - // block sigops > limit: 1000 CHECKMULTISIG + 1 - tx.vin.resize(1); - // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG - tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1; - tx.vin[0].prevout.hash = txFirst[0]->GetHash(); - tx.vin[0].prevout.n = 0; - tx.vout.resize(1); - tx.vout[0].nValue = BLOCKSUBSIDY; - for (unsigned int i = 0; i < 1001; ++i) { - tx.vout[0].nValue -= LOWFEE; - hash = tx.GetHash(); - bool spendsCoinbase = i == 0; // only first tx spends coinbase - // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails - m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); - tx.vin[0].prevout.hash = hash; + CTxMemPool& tx_mempool{MakeMempool()}; + LOCK(tx_mempool.cs); + + // Just to make sure we can still make simple blocks + auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); + BOOST_CHECK(pblocktemplate); + + // block sigops > limit: 1000 CHECKMULTISIG + 1 + tx.vin.resize(1); + // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG + tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1; + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vin[0].prevout.n = 0; + tx.vout.resize(1); + tx.vout[0].nValue = BLOCKSUBSIDY; + for (unsigned int i = 0; i < 1001; ++i) { + tx.vout[0].nValue -= LOWFEE; + hash = tx.GetHash(); + bool spendsCoinbase = i == 0; // only first tx spends coinbase + // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); + tx.vin[0].prevout.hash = hash; + } + + BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops")); } - BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops")); - m_node.mempool->clear(); + { + CTxMemPool& tx_mempool{MakeMempool()}; + LOCK(tx_mempool.cs); + + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vout[0].nValue = BLOCKSUBSIDY; + for (unsigned int i = 0; i < 1001; ++i) { + tx.vout[0].nValue -= LOWFEE; + hash = tx.GetHash(); + bool spendsCoinbase = i == 0; // only first tx spends coinbase + // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); + tx.vin[0].prevout.hash = hash; + } + BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); + } - tx.vin[0].prevout.hash = txFirst[0]->GetHash(); - tx.vout[0].nValue = BLOCKSUBSIDY; - for (unsigned int i = 0; i < 1001; ++i) { - tx.vout[0].nValue -= LOWFEE; - hash = tx.GetHash(); - bool spendsCoinbase = i == 0; // only first tx spends coinbase - // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes - m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); - tx.vin[0].prevout.hash = hash; + CTxMemPool& tx_mempool{MakeMempool()}; + LOCK(tx_mempool.cs); + + // block size > limit + tx.vin[0].scriptSig = CScript(); + // 18 * (520char + DROP) + OP_1 = 9433 bytes + std::vector<unsigned char> vchData(520); + for (unsigned int i = 0; i < 18; ++i) { + tx.vin[0].scriptSig << vchData << OP_DROP; + } + tx.vin[0].scriptSig << OP_1; + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vout[0].nValue = BLOCKSUBSIDY; + for (unsigned int i = 0; i < 128; ++i) { + tx.vout[0].nValue -= LOWFEE; + hash = tx.GetHash(); + bool spendsCoinbase = i == 0; // only first tx spends coinbase + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); + tx.vin[0].prevout.hash = hash; + } + BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); } - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); - m_node.mempool->clear(); - - // block size > limit - tx.vin[0].scriptSig = CScript(); - // 18 * (520char + DROP) + OP_1 = 9433 bytes - std::vector<unsigned char> vchData(520); - for (unsigned int i = 0; i < 18; ++i) - tx.vin[0].scriptSig << vchData << OP_DROP; - tx.vin[0].scriptSig << OP_1; - tx.vin[0].prevout.hash = txFirst[0]->GetHash(); - tx.vout[0].nValue = BLOCKSUBSIDY; - for (unsigned int i = 0; i < 128; ++i) + { - tx.vout[0].nValue -= LOWFEE; + CTxMemPool& tx_mempool{MakeMempool()}; + LOCK(tx_mempool.cs); + + // orphan in tx_mempool, template creation fails hash = tx.GetHash(); - bool spendsCoinbase = i == 0; // only first tx spends coinbase - m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); - tx.vin[0].prevout.hash = hash; + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); + BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); } - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); - m_node.mempool->clear(); - // orphan in *m_node.mempool, template creation fails - hash = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); - BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); - m_node.mempool->clear(); - - // child with higher feerate than parent - tx.vin[0].scriptSig = CScript() << OP_1; - tx.vin[0].prevout.hash = txFirst[1]->GetHash(); - tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE; - hash = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - tx.vin[0].prevout.hash = hash; - tx.vin.resize(2); - tx.vin[1].scriptSig = CScript() << OP_1; - tx.vin[1].prevout.hash = txFirst[0]->GetHash(); - tx.vin[1].prevout.n = 0; - tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee - hash = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); - m_node.mempool->clear(); + { + CTxMemPool& tx_mempool{MakeMempool()}; + LOCK(tx_mempool.cs); - // coinbase in *m_node.mempool, template creation fails - tx.vin.resize(1); - tx.vin[0].prevout.SetNull(); - tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; - tx.vout[0].nValue = 0; - hash = tx.GetHash(); - // give it a fee so it'll get mined - m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); - // Should throw bad-cb-multiple - BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple")); - m_node.mempool->clear(); + // child with higher feerate than parent + tx.vin[0].scriptSig = CScript() << OP_1; + tx.vin[0].prevout.hash = txFirst[1]->GetHash(); + tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; + hash = tx.GetHash(); + tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx.vin[0].prevout.hash = hash; + tx.vin.resize(2); + tx.vin[1].scriptSig = CScript() << OP_1; + tx.vin[1].prevout.hash = txFirst[0]->GetHash(); + tx.vin[1].prevout.n = 0; + tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE; // First txn output + fresh coinbase - new txn fee + hash = tx.GetHash(); + tx_mempool.addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); + } - // double spend txn pair in *m_node.mempool, template creation fails - tx.vin[0].prevout.hash = txFirst[0]->GetHash(); - tx.vin[0].scriptSig = CScript() << OP_1; - tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE; - tx.vout[0].scriptPubKey = CScript() << OP_1; - hash = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - tx.vout[0].scriptPubKey = CScript() << OP_2; - hash = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); - m_node.mempool->clear(); - - // subsidy changing - int nHeight = m_node.chainman->ActiveChain().Height(); - // Create an actual 209999-long block chain (without valid blocks). - while (m_node.chainman->ActiveChain().Tip()->nHeight < 209999) { - CBlockIndex* prev = m_node.chainman->ActiveChain().Tip(); - CBlockIndex* next = new CBlockIndex(); - next->phashBlock = new uint256(InsecureRand256()); - m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash()); - next->pprev = prev; - next->nHeight = prev->nHeight + 1; - next->BuildSkip(); - m_node.chainman->ActiveChain().SetTip(*next); + { + CTxMemPool& tx_mempool{MakeMempool()}; + LOCK(tx_mempool.cs); + + // coinbase in tx_mempool, template creation fails + tx.vin.resize(1); + tx.vin[0].prevout.SetNull(); + tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; + tx.vout[0].nValue = 0; + hash = tx.GetHash(); + // give it a fee so it'll get mined + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + // Should throw bad-cb-multiple + BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple")); } - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); - // Extend to a 210000-long block chain. - while (m_node.chainman->ActiveChain().Tip()->nHeight < 210000) { - CBlockIndex* prev = m_node.chainman->ActiveChain().Tip(); - CBlockIndex* next = new CBlockIndex(); - next->phashBlock = new uint256(InsecureRand256()); - m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash()); - next->pprev = prev; - next->nHeight = prev->nHeight + 1; - next->BuildSkip(); - m_node.chainman->ActiveChain().SetTip(*next); + + { + CTxMemPool& tx_mempool{MakeMempool()}; + LOCK(tx_mempool.cs); + + // double spend txn pair in tx_mempool, template creation fails + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vin[0].scriptSig = CScript() << OP_1; + tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; + tx.vout[0].scriptPubKey = CScript() << OP_1; + hash = tx.GetHash(); + tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx.vout[0].scriptPubKey = CScript() << OP_2; + hash = tx.GetHash(); + tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); } - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); - // invalid p2sh txn in *m_node.mempool, template creation fails - tx.vin[0].prevout.hash = txFirst[0]->GetHash(); - tx.vin[0].prevout.n = 0; - tx.vin[0].scriptSig = CScript() << OP_1; - tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE; - CScript script = CScript() << OP_0; - tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script)); - hash = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - tx.vin[0].prevout.hash = hash; - tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end()); - tx.vout[0].nValue -= LOWFEE; - hash = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); - // Should throw block-validation-failed - BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed")); - m_node.mempool->clear(); - - // Delete the dummy blocks again. - while (m_node.chainman->ActiveChain().Tip()->nHeight > nHeight) { - CBlockIndex* del = m_node.chainman->ActiveChain().Tip(); - m_node.chainman->ActiveChain().SetTip(*Assert(del->pprev)); - m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(del->pprev->GetBlockHash()); - delete del->phashBlock; - delete del; + { + CTxMemPool& tx_mempool{MakeMempool()}; + LOCK(tx_mempool.cs); + + // subsidy changing + int nHeight = m_node.chainman->ActiveChain().Height(); + // Create an actual 209999-long block chain (without valid blocks). + while (m_node.chainman->ActiveChain().Tip()->nHeight < 209999) { + CBlockIndex* prev = m_node.chainman->ActiveChain().Tip(); + CBlockIndex* next = new CBlockIndex(); + next->phashBlock = new uint256(InsecureRand256()); + m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash()); + next->pprev = prev; + next->nHeight = prev->nHeight + 1; + next->BuildSkip(); + m_node.chainman->ActiveChain().SetTip(*next); + } + BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); + // Extend to a 210000-long block chain. + while (m_node.chainman->ActiveChain().Tip()->nHeight < 210000) { + CBlockIndex* prev = m_node.chainman->ActiveChain().Tip(); + CBlockIndex* next = new CBlockIndex(); + next->phashBlock = new uint256(InsecureRand256()); + m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash()); + next->pprev = prev; + next->nHeight = prev->nHeight + 1; + next->BuildSkip(); + m_node.chainman->ActiveChain().SetTip(*next); + } + BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); + + // invalid p2sh txn in tx_mempool, template creation fails + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vin[0].prevout.n = 0; + tx.vin[0].scriptSig = CScript() << OP_1; + tx.vout[0].nValue = BLOCKSUBSIDY - LOWFEE; + CScript script = CScript() << OP_0; + tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script)); + hash = tx.GetHash(); + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx.vin[0].prevout.hash = hash; + tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end()); + tx.vout[0].nValue -= LOWFEE; + hash = tx.GetHash(); + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + // Should throw block-validation-failed + BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed")); + + // Delete the dummy blocks again. + while (m_node.chainman->ActiveChain().Tip()->nHeight > nHeight) { + CBlockIndex* del = m_node.chainman->ActiveChain().Tip(); + m_node.chainman->ActiveChain().SetTip(*Assert(del->pprev)); + m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(del->pprev->GetBlockHash()); + delete del->phashBlock; + delete del; + } } + CTxMemPool& tx_mempool{MakeMempool()}; + LOCK(tx_mempool.cs); + // non-final txs in mempool SetMockTime(m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1); const int flags{LOCKTIME_VERIFY_SEQUENCE}; @@ -388,9 +431,9 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C tx.vout[0].scriptPubKey = CScript() << OP_1; tx.nLockTime = 0; hash = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes - BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail + BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail { CBlockIndex* active_chain_tip = m_node.chainman->ActiveChain().Tip(); @@ -402,9 +445,9 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((m_node.chainman->ActiveChain().Tip()->GetMedianTimePast()+1-m_node.chainman->ActiveChain()[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block prevheights[0] = baseheight + 2; hash = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx)); + tx_mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes - BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail + BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail const int SEQUENCE_LOCK_TIME = 512; // Sequence locks pass 512 seconds later for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i) @@ -425,9 +468,9 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C prevheights[0] = baseheight + 3; tx.nLockTime = m_node.chainman->ActiveChain().Tip()->nHeight + 1; hash = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx)); + tx_mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(!CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime fails - BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass + BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass BOOST_CHECK(IsFinalTx(CTransaction(tx), m_node.chainman->ActiveChain().Tip()->nHeight + 2, m_node.chainman->ActiveChain().Tip()->GetMedianTimePast())); // Locktime passes on 2nd block // absolute time locked @@ -436,9 +479,9 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C prevheights.resize(1); prevheights[0] = baseheight + 4; hash = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx)); + tx_mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(!CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime fails - BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass + BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass BOOST_CHECK(IsFinalTx(CTransaction(tx), m_node.chainman->ActiveChain().Tip()->nHeight + 2, m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later // mempool-dependent transactions (not added) @@ -447,15 +490,16 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C tx.nLockTime = 0; tx.vin[0].nSequence = 0; BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes - BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass + BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass tx.vin[0].nSequence = 1; - BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail + BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG; - BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass + BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1; - BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail + BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); + auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); + BOOST_CHECK(pblocktemplate); // None of the of the absolute height/time locked tx should have made // it into the template because we still check IsFinalTx in CreateNewBlock, @@ -470,12 +514,15 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C m_node.chainman->ActiveChain().Tip()->nHeight++; SetMockTime(m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1); - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U); } -void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) +void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) { + CTxMemPool& tx_mempool{MakeMempool()}; + LOCK(tx_mempool.cs); + TestMemPoolEntryHelper entry; // Test that a tx below min fee but prioritised is included @@ -487,29 +534,29 @@ void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, c tx.vout.resize(1); tx.vout[0].nValue = 5000000000LL; // 0 fee uint256 hashFreePrioritisedTx = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(0).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - m_node.mempool->PrioritiseTransaction(hashFreePrioritisedTx, 5 * COIN); + tx_mempool.addUnchecked(entry.Fee(0).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.PrioritiseTransaction(hashFreePrioritisedTx, 5 * COIN); tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vin[0].prevout.n = 0; tx.vout[0].nValue = 5000000000LL - 1000; // This tx has a low fee: 1000 satoshis uint256 hashParentTx = tx.GetHash(); // save this txid for later use - m_node.mempool->addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a medium fee: 10000 satoshis tx.vin[0].prevout.hash = txFirst[2]->GetHash(); tx.vout[0].nValue = 5000000000LL - 10000; uint256 hashMediumFeeTx = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - m_node.mempool->PrioritiseTransaction(hashMediumFeeTx, -5 * COIN); + tx_mempool.addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.PrioritiseTransaction(hashMediumFeeTx, -5 * COIN); // This tx also has a low fee, but is prioritised tx.vin[0].prevout.hash = hashParentTx; tx.vout[0].nValue = 5000000000LL - 1000 - 1000; // 1000 satoshi fee uint256 hashPrioritsedChild = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); - m_node.mempool->PrioritiseTransaction(hashPrioritsedChild, 2 * COIN); + tx_mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + tx_mempool.PrioritiseTransaction(hashPrioritsedChild, 2 * COIN); // Test that transaction selection properly updates ancestor fee calculations as prioritised // parents get included in a block. Create a transaction with two prioritised ancestors, each @@ -520,21 +567,21 @@ void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, c tx.vin[0].prevout.hash = txFirst[3]->GetHash(); tx.vout[0].nValue = 5000000000LL; // 0 fee uint256 hashFreeParent = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); - m_node.mempool->PrioritiseTransaction(hashFreeParent, 10 * COIN); + tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.PrioritiseTransaction(hashFreeParent, 10 * COIN); tx.vin[0].prevout.hash = hashFreeParent; tx.vout[0].nValue = 5000000000LL; // 0 fee uint256 hashFreeChild = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx)); - m_node.mempool->PrioritiseTransaction(hashFreeChild, 1 * COIN); + tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx)); + tx_mempool.PrioritiseTransaction(hashFreeChild, 1 * COIN); tx.vin[0].prevout.hash = hashFreeChild; tx.vout[0].nValue = 5000000000LL; // 0 fee uint256 hashFreeGrandchild = tx.GetHash(); - m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx)); - auto pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); + auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashFreeParent); BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashFreePrioritisedTx); @@ -553,13 +600,12 @@ void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, c BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { // Note that by default, these tests run with size accounting enabled. - const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); - const CChainParams& chainparams = *chainParams; CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; std::unique_ptr<CBlockTemplate> pblocktemplate; + CTxMemPool& tx_mempool{*m_node.mempool}; // Simple block creation, nothing special yet: - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); // We can't make transactions until we have inputs // Therefore, load 110 blocks :) @@ -591,21 +637,18 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) } LOCK(cs_main); - LOCK(m_node.mempool->cs); - TestBasicMining(chainparams, scriptPubKey, txFirst, baseheight); + TestBasicMining(scriptPubKey, txFirst, baseheight); m_node.chainman->ActiveChain().Tip()->nHeight--; SetMockTime(0); - m_node.mempool->clear(); - TestPackageSelection(chainparams, scriptPubKey, txFirst); + TestPackageSelection(scriptPubKey, txFirst); m_node.chainman->ActiveChain().Tip()->nHeight--; SetMockTime(0); - m_node.mempool->clear(); - TestPrioritisedMining(chainparams, scriptPubKey, txFirst); + TestPrioritisedMining(scriptPubKey, txFirst); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/minisketch_tests.cpp b/src/test/minisketch_tests.cpp index 9c53ace633..81f2aad623 100644 --- a/src/test/minisketch_tests.cpp +++ b/src/test/minisketch_tests.cpp @@ -40,7 +40,7 @@ BOOST_AUTO_TEST_CASE(minisketch_test) Minisketch sketch_c = std::move(sketch_ar); sketch_c.Merge(sketch_br); auto dec = sketch_c.Decode(errors); - BOOST_CHECK(dec.has_value()); + BOOST_REQUIRE(dec.has_value()); auto sols = std::move(*dec); std::sort(sols.begin(), sols.end()); for (uint32_t i = 0; i < a_not_b; ++i) BOOST_CHECK_EQUAL(sols[i], start_a + i); diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp index f160bb08a5..11f4be7fef 100644 --- a/src/test/system_tests.cpp +++ b/src/test/system_tests.cpp @@ -3,7 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. // #include <test/util/setup_common.h> -#include <util/system.h> +#include <common/run_command.h> #include <univalue.h> #ifdef ENABLE_EXTERNAL_SIGNER diff --git a/src/txmempool.cpp b/src/txmempool.cpp index e1288b7346..84ed2e9ef5 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -145,7 +145,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashes // Iterate in reverse, so that whenever we are looking at a transaction // we are sure that all in-mempool descendants have already been processed. // This maximizes the benefit of the descendant cache and guarantees that - // CTxMemPool::m_children will be updated, an assumption made in + // CTxMemPoolEntry::m_children will be updated, an assumption made in // UpdateForDescendants. for (const uint256 &hash : reverse_iterate(vHashesToUpdate)) { // calculate children from mapNextTx @@ -154,7 +154,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashes continue; } auto iter = mapNextTx.lower_bound(COutPoint(hash, 0)); - // First calculate the children, and update CTxMemPool::m_children to + // First calculate the children, and update CTxMemPoolEntry::m_children to // include them, and update their CTxMemPoolEntry::m_parents to include this tx. // we cache the in-mempool children to avoid duplicate updates { @@ -187,10 +187,7 @@ bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size, size_t entry_count, setEntries& setAncestors, CTxMemPoolEntry::Parents& staged_ancestors, - uint64_t limitAncestorCount, - uint64_t limitAncestorSize, - uint64_t limitDescendantCount, - uint64_t limitDescendantSize, + const Limits& limits, std::string &errString) const { size_t totalSizeWithAncestors = entry_size; @@ -203,14 +200,14 @@ bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size, staged_ancestors.erase(stage); totalSizeWithAncestors += stageit->GetTxSize(); - if (stageit->GetSizeWithDescendants() + entry_size > limitDescendantSize) { - errString = strprintf("exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limitDescendantSize); + if (stageit->GetSizeWithDescendants() + entry_size > static_cast<uint64_t>(limits.descendant_size_vbytes)) { + errString = strprintf("exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_size_vbytes); return false; - } else if (stageit->GetCountWithDescendants() + entry_count > limitDescendantCount) { - errString = strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limitDescendantCount); + } else if (stageit->GetCountWithDescendants() + entry_count > static_cast<uint64_t>(limits.descendant_count)) { + errString = strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_count); return false; - } else if (totalSizeWithAncestors > limitAncestorSize) { - errString = strprintf("exceeds ancestor size limit [limit: %u]", limitAncestorSize); + } else if (totalSizeWithAncestors > static_cast<uint64_t>(limits.ancestor_size_vbytes)) { + errString = strprintf("exceeds ancestor size limit [limit: %u]", limits.ancestor_size_vbytes); return false; } @@ -222,8 +219,8 @@ bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size, if (setAncestors.count(parent_it) == 0) { staged_ancestors.insert(parent); } - if (staged_ancestors.size() + setAncestors.size() + entry_count > limitAncestorCount) { - errString = strprintf("too many unconfirmed ancestors [limit: %u]", limitAncestorCount); + if (staged_ancestors.size() + setAncestors.size() + entry_count > static_cast<uint64_t>(limits.ancestor_count)) { + errString = strprintf("too many unconfirmed ancestors [limit: %u]", limits.ancestor_count); return false; } } @@ -233,10 +230,7 @@ bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size, } bool CTxMemPool::CheckPackageLimits(const Package& package, - uint64_t limitAncestorCount, - uint64_t limitAncestorSize, - uint64_t limitDescendantCount, - uint64_t limitDescendantSize, + const Limits& limits, std::string &errString) const { CTxMemPoolEntry::Parents staged_ancestors; @@ -247,8 +241,8 @@ bool CTxMemPool::CheckPackageLimits(const Package& package, std::optional<txiter> piter = GetIter(input.prevout.hash); if (piter) { staged_ancestors.insert(**piter); - if (staged_ancestors.size() + package.size() > limitAncestorCount) { - errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount); + if (staged_ancestors.size() + package.size() > static_cast<uint64_t>(limits.ancestor_count)) { + errString = strprintf("too many unconfirmed parents [limit: %u]", limits.ancestor_count); return false; } } @@ -260,8 +254,7 @@ bool CTxMemPool::CheckPackageLimits(const Package& package, setEntries setAncestors; const auto ret = CalculateAncestorsAndCheckLimits(total_size, package.size(), setAncestors, staged_ancestors, - limitAncestorCount, limitAncestorSize, - limitDescendantCount, limitDescendantSize, errString); + limits, errString); // It's possible to overestimate the ancestor/descendant totals. if (!ret) errString.insert(0, "possibly "); return ret; @@ -269,10 +262,7 @@ bool CTxMemPool::CheckPackageLimits(const Package& package, bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, - uint64_t limitAncestorCount, - uint64_t limitAncestorSize, - uint64_t limitDescendantCount, - uint64_t limitDescendantSize, + const Limits& limits, std::string &errString, bool fSearchForParents /* = true */) const { @@ -287,8 +277,8 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, std::optional<txiter> piter = GetIter(tx.vin[i].prevout.hash); if (piter) { staged_ancestors.insert(**piter); - if (staged_ancestors.size() + 1 > limitAncestorCount) { - errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount); + if (staged_ancestors.size() + 1 > static_cast<uint64_t>(limits.ancestor_count)) { + errString = strprintf("too many unconfirmed parents [limit: %u]", limits.ancestor_count); return false; } } @@ -302,8 +292,7 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, return CalculateAncestorsAndCheckLimits(entry.GetTxSize(), /*entry_count=*/1, setAncestors, staged_ancestors, - limitAncestorCount, limitAncestorSize, - limitDescendantCount, limitDescendantSize, errString); + limits, errString); } void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors) @@ -347,7 +336,6 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b { // For each entry, walk back all ancestors and decrement size associated with this // transaction - const uint64_t nNoLimit = std::numeric_limits<uint64_t>::max(); if (updateDescendants) { // updateDescendants should be true whenever we're not recursively // removing a tx and all its descendants, eg when a transaction is @@ -390,7 +378,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b // mempool parents we'd calculate by searching, and it's important that // we use the cached notion of ancestor transactions as the set of // things to update for removal. - CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); + CalculateMemPoolAncestors(entry, setAncestors, Limits::NoLimits(), dummy, false); // Note that UpdateAncestorsOf severs the child links that point to // removeIt in the entries for the parents of removeIt. UpdateAncestorsOf(false, removeIt, setAncestors); @@ -744,9 +732,8 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei assert(std::equal(setParentCheck.begin(), setParentCheck.end(), it->GetMemPoolParentsConst().begin(), comp)); // Verify ancestor state is correct. setEntries setAncestors; - uint64_t nNoLimit = std::numeric_limits<uint64_t>::max(); std::string dummy; - CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); + CalculateMemPoolAncestors(*it, setAncestors, Limits::NoLimits(), dummy); uint64_t nCountCheck = setAncestors.size() + 1; uint64_t nSizeCheck = it->GetTxSize(); CAmount nFeesCheck = it->GetModifiedFee(); @@ -908,9 +895,8 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeD mapTx.modify(it, [&nFeeDelta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(nFeeDelta); }); // Now update all ancestors' modified fees with descendants setEntries setAncestors; - uint64_t nNoLimit = std::numeric_limits<uint64_t>::max(); std::string dummy; - CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); + CalculateMemPoolAncestors(*it, setAncestors, Limits::NoLimits(), dummy, false); for (txiter ancestorIt : setAncestors) { mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e){ e.UpdateDescendantState(0, nFeeDelta, 0);}); } @@ -1049,9 +1035,8 @@ int CTxMemPool::Expire(std::chrono::seconds time) void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, bool validFeeEstimate) { setEntries setAncestors; - uint64_t nNoLimit = std::numeric_limits<uint64_t>::max(); std::string dummy; - CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); + CalculateMemPoolAncestors(entry, setAncestors, Limits::NoLimits(), dummy); return addUnchecked(entry, setAncestors, validFeeEstimate); } diff --git a/src/txmempool.h b/src/txmempool.h index cd15d069b1..4afaac0506 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -526,6 +526,8 @@ public: typedef std::set<txiter, CompareIteratorByHash> setEntries; + using Limits = kernel::MemPoolLimits; + uint64_t CalculateDescendantMaximum(txiter entry) const EXCLUSIVE_LOCKS_REQUIRED(cs); private: typedef std::map<txiter, setEntries, CompareIteratorByHash> cacheMap; @@ -545,19 +547,22 @@ private: /** * Helper function to calculate all in-mempool ancestors of staged_ancestors and apply ancestor * and descendant limits (including staged_ancestors thsemselves, entry_size and entry_count). - * param@[in] entry_size Virtual size to include in the limits. - * param@[in] entry_count How many entries to include in the limits. - * param@[in] staged_ancestors Should contain entries in the mempool. - * param@[out] setAncestors Will be populated with all mempool ancestors. + * + * @param[in] entry_size Virtual size to include in the limits. + * @param[in] entry_count How many entries to include in the limits. + * @param[out] setAncestors Will be populated with all mempool ancestors. + * @param[in] staged_ancestors Should contain entries in the mempool. + * @param[in] limits Maximum number and size of ancestors and descendants + * @param[out] errString Populated with error reason if any limits are hit + * + * @return true if no limits were hit and all in-mempool ancestors were calculated, false + * otherwise */ bool CalculateAncestorsAndCheckLimits(size_t entry_size, size_t entry_count, setEntries& setAncestors, CTxMemPoolEntry::Parents &staged_ancestors, - uint64_t limitAncestorCount, - uint64_t limitAncestorSize, - uint64_t limitDescendantCount, - uint64_t limitDescendantSize, + const Limits& limits, std::string &errString) const EXCLUSIVE_LOCKS_REQUIRED(cs); public: @@ -576,8 +581,6 @@ public: const bool m_require_standard; const bool m_full_rbf; - using Limits = kernel::MemPoolLimits; - const Limits m_limits; /** Create a new CTxMemPool. @@ -668,38 +671,41 @@ public: */ void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main) LOCKS_EXCLUDED(m_epoch); - /** Try to calculate all in-mempool ancestors of entry. - * (these are all calculated including the tx itself) - * limitAncestorCount = max number of ancestors - * limitAncestorSize = max size of ancestors - * limitDescendantCount = max number of descendants any ancestor can have - * limitDescendantSize = max size of descendants any ancestor can have - * errString = populated with error reason if any limits are hit - * fSearchForParents = whether to search a tx's vin for in-mempool parents, or - * look up parents from mapLinks. Must be true for entries not in the mempool + /** + * Try to calculate all in-mempool ancestors of entry. + * (these are all calculated including the tx itself) + * + * @param[in] entry CTxMemPoolEntry of which all in-mempool ancestors are calculated + * @param[out] setAncestors Will be populated with all mempool ancestors. + * @param[in] limits Maximum number and size of ancestors and descendants + * @param[out] errString Populated with error reason if any limits are hit + * @param[in] fSearchForParents Whether to search a tx's vin for in-mempool parents, or look + * up parents from mapLinks. Must be true for entries not in + * the mempool + * + * @return true if no limits were hit and all in-mempool ancestors were calculated, false + * otherwise */ - bool CalculateMemPoolAncestors(const CTxMemPoolEntry& entry, setEntries& setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string& errString, bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs); + bool CalculateMemPoolAncestors(const CTxMemPoolEntry& entry, + setEntries& setAncestors, + const Limits& limits, + std::string& errString, + bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs); /** Calculate all in-mempool ancestors of a set of transactions not already in the mempool and * check ancestor and descendant limits. Heuristics are used to estimate the ancestor and * descendant count of all entries if the package were to be added to the mempool. The limits * are applied to the union of all package transactions. For example, if the package has 3 - * transactions and limitAncestorCount = 25, the union of all 3 sets of ancestors (including the + * transactions and limits.ancestor_count = 25, the union of all 3 sets of ancestors (including the * transactions themselves) must be <= 22. * @param[in] package Transaction package being evaluated for acceptance * to mempool. The transactions need not be direct * ancestors/descendants of each other. - * @param[in] limitAncestorCount Max number of txns including ancestors. - * @param[in] limitAncestorSize Max virtual size including ancestors. - * @param[in] limitDescendantCount Max number of txns including descendants. - * @param[in] limitDescendantSize Max virtual size including descendants. + * @param[in] limits Maximum number and size of ancestors and descendants * @param[out] errString Populated with error reason if a limit is hit. */ bool CheckPackageLimits(const Package& package, - uint64_t limitAncestorCount, - uint64_t limitAncestorSize, - uint64_t limitDescendantCount, - uint64_t limitDescendantSize, + const Limits& limits, std::string &errString) const EXCLUSIVE_LOCKS_REQUIRED(cs); /** Populate setDescendants with all in-mempool descendants of hash. @@ -825,7 +831,7 @@ private: * mempool but may have child transactions in the mempool, eg during a * chain reorg. * - * @pre CTxMemPool::m_children is correct for the given tx and all + * @pre CTxMemPoolEntry::m_children is correct for the given tx and all * descendants. * @pre cachedDescendants is an accurate cache where each entry has all * descendants of the corresponding key, including those that should diff --git a/src/util/system.cpp b/src/util/system.cpp index c3c6cbfef6..ce5d846eb9 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -5,19 +5,6 @@ #include <util/system.h> -#ifdef ENABLE_EXTERNAL_SIGNER -#if defined(__GNUC__) -// Boost 1.78 requires the following workaround. -// See: https://github.com/boostorg/process/issues/235 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnarrowing" -#endif -#include <boost/process.hpp> -#if defined(__GNUC__) -#pragma GCC diagnostic pop -#endif -#endif // ENABLE_EXTERNAL_SIGNER - #include <chainparamsbase.h> #include <fs.h> #include <sync.h> @@ -1332,44 +1319,6 @@ void runCommand(const std::string& strCommand) } #endif -UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in) -{ -#ifdef ENABLE_EXTERNAL_SIGNER - namespace bp = boost::process; - - UniValue result_json; - bp::opstream stdin_stream; - bp::ipstream stdout_stream; - bp::ipstream stderr_stream; - - if (str_command.empty()) return UniValue::VNULL; - - bp::child c( - str_command, - bp::std_out > stdout_stream, - bp::std_err > stderr_stream, - bp::std_in < stdin_stream - ); - if (!str_std_in.empty()) { - stdin_stream << str_std_in << std::endl; - } - stdin_stream.pipe().close(); - - std::string result; - std::string error; - std::getline(stdout_stream, result); - std::getline(stderr_stream, error); - - c.wait(); - const int n_error = c.exit_code(); - if (n_error) throw std::runtime_error(strprintf("RunCommandParseJSON error: process(%s) returned %d: %s\n", str_command, n_error, error)); - if (!result_json.read(result)) throw std::runtime_error("Unable to parse JSON: " + result); - - return result_json; -#else - throw std::runtime_error("Compiled without external signing support (required for external signing)."); -#endif // ENABLE_EXTERNAL_SIGNER -} void SetupEnvironment() { diff --git a/src/util/system.h b/src/util/system.h index c8e1de6700..29629e547e 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -107,14 +107,6 @@ std::string ShellEscape(const std::string& arg); #if HAVE_SYSTEM void runCommand(const std::string& strCommand); #endif -/** - * Execute a command which returns JSON, and parse the result. - * - * @param str_command The command to execute, including any arguments - * @param str_std_in string to pass to stdin - * @return parsed JSON - */ -UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in=""); /** * Most paths passed as configuration arguments are treated as relative to diff --git a/src/util/time.h b/src/util/time.h index 0ec79bec32..10a581a44c 100644 --- a/src/util/time.h +++ b/src/util/time.h @@ -57,6 +57,7 @@ constexpr int64_t count_microseconds(std::chrono::microseconds t) { return t.cou using HoursDouble = std::chrono::duration<double, std::chrono::hours::period>; using SecondsDouble = std::chrono::duration<double, std::chrono::seconds::period>; +using MillisecondsDouble = std::chrono::duration<double, std::chrono::milliseconds::period>; /** * DEPRECATED diff --git a/src/validation.cpp b/src/validation.cpp index fb29ca3ae7..514a528314 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -82,9 +82,6 @@ using node::SnapshotMetadata; using node::UndoReadFromDisk; using node::UnlinkPrunedFiles; -#define MICRO 0.000001 -#define MILLI 0.001 - /** Maximum kilobytes for transactions to store for processing during reorg */ static const unsigned int MAX_DISCONNECTED_TX_POOL_SIZE = 20000; /** Time to wait between writing blocks/block index to disk. */ @@ -424,11 +421,13 @@ namespace { class MemPoolAccept { public: - explicit MemPoolAccept(CTxMemPool& mempool, Chainstate& active_chainstate) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&active_chainstate.CoinsTip(), m_pool), m_active_chainstate(active_chainstate), - m_limit_ancestors(m_pool.m_limits.ancestor_count), - m_limit_ancestor_size(m_pool.m_limits.ancestor_size_vbytes), - m_limit_descendants(m_pool.m_limits.descendant_count), - m_limit_descendant_size(m_pool.m_limits.descendant_size_vbytes) { + explicit MemPoolAccept(CTxMemPool& mempool, Chainstate& active_chainstate) : + m_pool(mempool), + m_view(&m_dummy), + m_viewmempool(&active_chainstate.CoinsTip(), m_pool), + m_active_chainstate(active_chainstate), + m_limits{m_pool.m_limits} + { } // We put the arguments we're handed into a struct, so we can pass them @@ -660,13 +659,7 @@ private: Chainstate& m_active_chainstate; - // The package limits in effect at the time of invocation. - const size_t m_limit_ancestors; - const size_t m_limit_ancestor_size; - // These may be modified while evaluating a transaction (eg to account for - // in-mempool conflicts; see below). - size_t m_limit_descendants; - size_t m_limit_descendant_size; + CTxMemPool::Limits m_limits; /** Whether the transaction(s) would replace any mempool transactions. If so, RBF rules apply. */ bool m_rbf{false}; @@ -879,12 +872,12 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) assert(ws.m_iters_conflicting.size() == 1); CTxMemPool::txiter conflict = *ws.m_iters_conflicting.begin(); - m_limit_descendants += 1; - m_limit_descendant_size += conflict->GetSizeWithDescendants(); + m_limits.descendant_count += 1; + m_limits.descendant_size_vbytes += conflict->GetSizeWithDescendants(); } std::string errString; - if (!m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants, m_limit_descendant_size, errString)) { + if (!m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, m_limits, errString)) { ws.m_ancestors.clear(); // If CalculateMemPoolAncestors fails second time, we want the original error string. std::string dummy_err_string; @@ -899,8 +892,16 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // to be secure by simply only having two immediately-spendable // outputs - one for each counterparty. For more info on the uses for // this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html + CTxMemPool::Limits cpfp_carve_out_limits{ + .ancestor_count = 2, + .ancestor_size_vbytes = m_limits.ancestor_size_vbytes, + .descendant_count = m_limits.descendant_count + 1, + .descendant_size_vbytes = m_limits.descendant_size_vbytes + EXTRA_DESCENDANT_TX_SIZE_LIMIT, + }; if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || - !m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) { + !m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, + cpfp_carve_out_limits, + dummy_err_string)) { return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", errString); } } @@ -976,8 +977,7 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn { return !m_pool.exists(GenTxid::Txid(tx->GetHash()));})); std::string err_string; - if (!m_pool.CheckPackageLimits(txns, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants, - m_limit_descendant_size, err_string)) { + if (!m_pool.CheckPackageLimits(txns, m_limits, err_string)) { // This is a package-wide error, separate from an individual transaction error. return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-mempool-limits", err_string); } @@ -1121,9 +1121,7 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>& // Re-calculate mempool ancestors to call addUnchecked(). They may have changed since the // last calculation done in PreChecks, since package ancestors have already been submitted. std::string unused_err_string; - if(!m_pool.CalculateMemPoolAncestors(*ws.m_entry, ws.m_ancestors, m_limit_ancestors, - m_limit_ancestor_size, m_limit_descendants, - m_limit_descendant_size, unused_err_string)) { + if(!m_pool.CalculateMemPoolAncestors(*ws.m_entry, ws.m_ancestors, m_limits, unused_err_string)) { results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state)); // Since PreChecks() and PackageMempoolChecks() both enforce limits, this should never fail. Assume(false); @@ -1965,14 +1963,14 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Ch } -static int64_t nTimeCheck = 0; -static int64_t nTimeForks = 0; -static int64_t nTimeConnect = 0; -static int64_t nTimeVerify = 0; -static int64_t nTimeUndo = 0; -static int64_t nTimeIndex = 0; -static int64_t nTimeTotal = 0; -static int64_t nBlocksTotal = 0; +static SteadyClock::duration time_check{}; +static SteadyClock::duration time_forks{}; +static SteadyClock::duration time_connect{}; +static SteadyClock::duration time_verify{}; +static SteadyClock::duration time_undo{}; +static SteadyClock::duration time_index{}; +static SteadyClock::duration time_total{}; +static int64_t num_blocks_total = 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() @@ -1986,7 +1984,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, uint256 block_hash{block.GetHash()}; assert(*pindex->phashBlock == block_hash); - int64_t nTimeStart = GetTimeMicros(); + const auto time_start{SteadyClock::now()}; // Check it again in case a previous version let a bad block in // NOTE: We don't currently (re-)invoke ContextualCheckBlock() or @@ -2015,7 +2013,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, uint256 hashPrevBlock = pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash(); assert(hashPrevBlock == view.GetBestBlock()); - nBlocksTotal++; + num_blocks_total++; // Special case for the genesis block, skipping connection of its transactions // (its coinbase is unspendable) @@ -2056,8 +2054,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, } } - int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart; - LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime1 - nTimeStart), nTimeCheck * MICRO, nTimeCheck * MILLI / nBlocksTotal); + const auto time_1{SteadyClock::now()}; + time_check += time_1 - time_start; + LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs (%.2fms/blk)]\n", + Ticks<MillisecondsDouble>(time_1 - time_start), + Ticks<SecondsDouble>(time_check), + Ticks<MillisecondsDouble>(time_check) / num_blocks_total); // Do not allow blocks that contain transactions which 'overwrite' older transactions, // unless those are already completely spent. @@ -2155,8 +2157,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, // Get the script flags for this block unsigned int flags{GetBlockScriptFlags(*pindex, m_chainman)}; - int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1; - LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime2 - nTime1), nTimeForks * MICRO, nTimeForks * MILLI / nBlocksTotal); + const auto time_2{SteadyClock::now()}; + time_forks += time_2 - time_1; + LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", + Ticks<MillisecondsDouble>(time_2 - time_1), + Ticks<SecondsDouble>(time_forks), + Ticks<MillisecondsDouble>(time_forks) / num_blocks_total); CBlockUndo blockundo; @@ -2240,8 +2246,13 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, } UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); } - int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2; - LogPrint(BCLog::BENCH, " - 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); + const auto time_3{SteadyClock::now()}; + time_connect += time_3 - time_2; + LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), + Ticks<MillisecondsDouble>(time_3 - time_2), Ticks<MillisecondsDouble>(time_3 - time_2) / block.vtx.size(), + nInputs <= 1 ? 0 : Ticks<MillisecondsDouble>(time_3 - time_2) / (nInputs - 1), + Ticks<SecondsDouble>(time_connect), + Ticks<MillisecondsDouble>(time_connect) / num_blocks_total); CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, m_params.GetConsensus()); if (block.vtx[0]->GetValueOut() > blockReward) { @@ -2253,8 +2264,13 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, 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::BENCH, " - 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); + const auto time_4{SteadyClock::now()}; + time_verify += time_4 - time_2; + LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, + Ticks<MillisecondsDouble>(time_4 - time_2), + nInputs <= 1 ? 0 : Ticks<MillisecondsDouble>(time_4 - time_2) / (nInputs - 1), + Ticks<SecondsDouble>(time_verify), + Ticks<MillisecondsDouble>(time_verify) / num_blocks_total); if (fJustCheck) return true; @@ -2263,8 +2279,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, return false; } - int64_t nTime5 = GetTimeMicros(); nTimeUndo += nTime5 - nTime4; - LogPrint(BCLog::BENCH, " - Write undo data: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5 - nTime4), nTimeUndo * MICRO, nTimeUndo * MILLI / nBlocksTotal); + const auto time_5{SteadyClock::now()}; + time_undo += time_5 - time_4; + LogPrint(BCLog::BENCH, " - Write undo data: %.2fms [%.2fs (%.2fms/blk)]\n", + Ticks<MillisecondsDouble>(time_5 - time_4), + Ticks<SecondsDouble>(time_undo), + Ticks<MillisecondsDouble>(time_undo) / num_blocks_total); if (!pindex->IsValid(BLOCK_VALID_SCRIPTS)) { pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); @@ -2274,8 +2294,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, // add this block to the view's block chain view.SetBestBlock(pindex->GetBlockHash()); - int64_t nTime6 = GetTimeMicros(); nTimeIndex += nTime6 - nTime5; - LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime6 - nTime5), nTimeIndex * MICRO, nTimeIndex * MILLI / nBlocksTotal); + const auto time_6{SteadyClock::now()}; + time_index += time_6 - time_5; + LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n", + Ticks<MillisecondsDouble>(time_6 - time_5), + Ticks<SecondsDouble>(time_index), + Ticks<MillisecondsDouble>(time_index) / num_blocks_total); TRACE6(validation, block_connected, block_hash.data(), @@ -2283,7 +2307,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, block.vtx.size(), nInputs, nSigOpsCost, - nTime5 - nTimeStart // in microseconds (µs) + time_5 - time_start // in microseconds (µs) ); return true; @@ -2590,7 +2614,7 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra return error("DisconnectTip(): Failed to read block"); } // Apply the block atomically to the chain state. - int64_t nStart = GetTimeMicros(); + const auto time_start{SteadyClock::now()}; { CCoinsViewCache view(&CoinsTip()); assert(view.GetBestBlock() == pindexDelete->GetBlockHash()); @@ -2599,7 +2623,8 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra bool flushed = view.Flush(); assert(flushed); } - LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * MILLI); + LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", + Ticks<MillisecondsDouble>(SteadyClock::now() - time_start)); { // Prune locks that began at or after the tip should be moved backward so they get a chance to reorg @@ -2639,11 +2664,11 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra return true; } -static int64_t nTimeReadFromDiskTotal = 0; -static int64_t nTimeConnectTotal = 0; -static int64_t nTimeFlush = 0; -static int64_t nTimeChainState = 0; -static int64_t nTimePostConnect = 0; +static SteadyClock::duration time_read_from_disk_total{}; +static SteadyClock::duration time_connect_total{}; +static SteadyClock::duration time_flush{}; +static SteadyClock::duration time_chainstate{}; +static SteadyClock::duration time_post_connect{}; struct PerBlockConnectTrace { CBlockIndex* pindex = nullptr; @@ -2698,7 +2723,7 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, assert(pindexNew->pprev == m_chain.Tip()); // Read block from disk. - int64_t nTime1 = GetTimeMicros(); + const auto time_1{SteadyClock::now()}; std::shared_ptr<const CBlock> pthisBlock; if (!pblock) { std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>(); @@ -2712,9 +2737,13 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, } const CBlock& blockConnecting = *pthisBlock; // Apply the block atomically to the chain state. - int64_t nTime2 = GetTimeMicros(); nTimeReadFromDiskTotal += nTime2 - nTime1; - int64_t nTime3; - LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime2 - nTime1) * MILLI, nTimeReadFromDiskTotal * MICRO, nTimeReadFromDiskTotal * MILLI / nBlocksTotal); + const auto time_2{SteadyClock::now()}; + time_read_from_disk_total += time_2 - time_1; + SteadyClock::time_point time_3; + LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs (%.2fms/blk)]\n", + Ticks<MillisecondsDouble>(time_2 - time_1), + Ticks<SecondsDouble>(time_read_from_disk_total), + Ticks<MillisecondsDouble>(time_read_from_disk_total) / num_blocks_total); { CCoinsViewCache view(&CoinsTip()); bool rv = ConnectBlock(blockConnecting, state, pindexNew, view); @@ -2724,20 +2753,32 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, InvalidBlockFound(pindexNew, state); return error("%s: ConnectBlock %s failed, %s", __func__, pindexNew->GetBlockHash().ToString(), state.ToString()); } - nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2; - assert(nBlocksTotal > 0); - LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, nTimeConnectTotal * MILLI / nBlocksTotal); + time_3 = SteadyClock::now(); + time_connect_total += time_3 - time_2; + assert(num_blocks_total > 0); + LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", + Ticks<MillisecondsDouble>(time_3 - time_2), + Ticks<SecondsDouble>(time_connect_total), + Ticks<MillisecondsDouble>(time_connect_total) / num_blocks_total); bool flushed = view.Flush(); assert(flushed); } - int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3; - LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, nTimeFlush * MILLI / nBlocksTotal); + const auto time_4{SteadyClock::now()}; + time_flush += time_4 - time_3; + LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", + Ticks<MillisecondsDouble>(time_4 - time_3), + Ticks<SecondsDouble>(time_flush), + Ticks<MillisecondsDouble>(time_flush) / num_blocks_total); // Write the chain state to disk, if necessary. if (!FlushStateToDisk(state, FlushStateMode::IF_NEEDED)) { return false; } - int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4; - LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, nTimeChainState * MILLI / nBlocksTotal); + const auto time_5{SteadyClock::now()}; + time_chainstate += time_5 - time_4; + LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", + Ticks<MillisecondsDouble>(time_5 - time_4), + Ticks<SecondsDouble>(time_chainstate), + Ticks<MillisecondsDouble>(time_chainstate) / num_blocks_total); // Remove conflicting transactions from the mempool.; if (m_mempool) { m_mempool->removeForBlock(blockConnecting.vtx, pindexNew->nHeight); @@ -2747,9 +2788,17 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, m_chain.SetTip(*pindexNew); UpdateTip(pindexNew); - int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; - LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, nTimePostConnect * MILLI / nBlocksTotal); - LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime1) * MILLI, nTimeTotal * MICRO, nTimeTotal * MILLI / nBlocksTotal); + const auto time_6{SteadyClock::now()}; + time_post_connect += time_6 - time_5; + time_total += time_6 - time_1; + LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", + Ticks<MillisecondsDouble>(time_6 - time_5), + Ticks<SecondsDouble>(time_post_connect), + Ticks<MillisecondsDouble>(time_post_connect) / num_blocks_total); + LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n", + Ticks<MillisecondsDouble>(time_6 - time_1), + Ticks<SecondsDouble>(time_total), + Ticks<MillisecondsDouble>(time_total) / num_blocks_total); connectTrace.BlockConnected(pindexNew, std::move(pthisBlock)); return true; diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 41654579c6..6da0741d59 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -586,7 +586,7 @@ bool LegacyScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& sig // or solving information, even if not able to sign fully. return true; } else { - // If, given the stuff in sigdata, we could make a valid sigature, then we can provide for this script + // If, given the stuff in sigdata, we could make a valid signature, then we can provide for this script ProduceSignature(*this, DUMMY_SIGNATURE_CREATOR, script, sigdata); if (!sigdata.signatures.empty()) { // If we could make signatures, make sure we have a private key to actually make a signature diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5889de2e36..461e64751a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -124,7 +124,7 @@ bool RemoveWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet interfaces::Chain& chain = wallet->chain(); std::string name = wallet->GetName(); - // Unregister with the validation interface which also drops shared ponters. + // Unregister with the validation interface which also drops shared pointers. wallet->m_chain_notifications_handler.reset(); LOCK(context.wallets_mutex); std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(context.wallets.begin(), context.wallets.end(), wallet); @@ -3111,12 +3111,14 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf // If a block is pruned after this check, we will load the wallet, // but fail the rescan with a generic error. - error = chain.hasAssumedValidChain() ? - _( - "Assumed-valid: last wallet synchronisation goes beyond " - "available block data. You need to wait for the background " - "validation chain to download more blocks.") : - _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"); + error = chain.havePruned() ? + _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)") : + strprintf(_( + "Error loading wallet. Wallet requires blocks to be downloaded, " + "and software does not currently support loading wallets while " + "blocks are being downloaded out of order when using assumeutxo " + "snapshots. Wallet should be able to load successfully after " + "node sync reaches height %s"), block_height); return false; } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 6a1b76505c..953d3e5bde 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -195,7 +195,7 @@ public: util::Result<CTxDestination> GetReservedDestination(bool internal); //! Return reserved address void ReturnDestination(); - //! Keep the address. Do not return it's key to the keypool when this object goes out of scope + //! Keep the address. Do not return its key to the keypool when this object goes out of scope void KeepDestination(); }; diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py index 05d274a9fe..5b43fe4f8e 100755 --- a/test/functional/feature_bip68_sequence.py +++ b/test/functional/feature_bip68_sequence.py @@ -10,15 +10,21 @@ from test_framework.blocktools import ( NORMAL_GBT_REQUEST_PARAMS, add_witness_commitment, create_block, + script_to_p2wsh_script, ) from test_framework.messages import ( COIN, COutPoint, CTransaction, CTxIn, + CTxInWitness, CTxOut, tx_from_hex, ) +from test_framework.script import ( + CScript, + OP_TRUE, +) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -26,7 +32,8 @@ from test_framework.util import ( assert_raises_rpc_error, softfork_active, ) -from test_framework.script_util import DUMMY_P2WPKH_SCRIPT + +SCRIPT_W0_SH_OP_TRUE = script_to_p2wsh_script(CScript([OP_TRUE])) SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31) SEQUENCE_LOCKTIME_TYPE_FLAG = (1<<22) # this means use time (0 means height) @@ -42,11 +49,9 @@ class BIP68Test(BitcoinTestFramework): self.extra_args = [ [ '-testactivationheight=csv@432', - "-acceptnonstdtxn=1", ], [ '-testactivationheight=csv@432', - "-acceptnonstdtxn=0", ], ] @@ -100,7 +105,7 @@ class BIP68Test(BitcoinTestFramework): # input to mature. sequence_value = SEQUENCE_LOCKTIME_DISABLE_FLAG | 1 tx1.vin = [CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), nSequence=sequence_value)] - tx1.vout = [CTxOut(value, DUMMY_P2WPKH_SCRIPT)] + tx1.vout = [CTxOut(value, SCRIPT_W0_SH_OP_TRUE)] tx1_signed = self.nodes[0].signrawtransactionwithwallet(tx1.serialize().hex())["hex"] tx1_id = self.nodes[0].sendrawtransaction(tx1_signed) @@ -112,7 +117,9 @@ class BIP68Test(BitcoinTestFramework): tx2.nVersion = 2 sequence_value = sequence_value & 0x7fffffff tx2.vin = [CTxIn(COutPoint(tx1_id, 0), nSequence=sequence_value)] - tx2.vout = [CTxOut(int(value - self.relayfee * COIN), DUMMY_P2WPKH_SCRIPT)] + tx2.wit.vtxinwit = [CTxInWitness()] + tx2.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])] + tx2.vout = [CTxOut(int(value - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)] tx2.rehash() assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, tx2.serialize().hex()) @@ -207,7 +214,7 @@ class BIP68Test(BitcoinTestFramework): value += utxos[j]["amount"]*COIN # Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output tx_size = len(tx.serialize().hex())//2 + 120*num_inputs + 50 - tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), DUMMY_P2WPKH_SCRIPT)) + tx.vout.append(CTxOut(int(value - self.relayfee * tx_size * COIN / 1000), SCRIPT_W0_SH_OP_TRUE)) rawtx = self.nodes[0].signrawtransactionwithwallet(tx.serialize().hex())["hex"] if (using_sequence_locks and not should_pass): @@ -236,7 +243,7 @@ class BIP68Test(BitcoinTestFramework): tx2 = CTransaction() tx2.nVersion = 2 tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)] - tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), DUMMY_P2WPKH_SCRIPT)] + tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)] tx2_raw = self.nodes[0].signrawtransactionwithwallet(tx2.serialize().hex())["hex"] tx2 = tx_from_hex(tx2_raw) tx2.rehash() @@ -254,7 +261,9 @@ class BIP68Test(BitcoinTestFramework): tx = CTransaction() tx.nVersion = 2 tx.vin = [CTxIn(COutPoint(orig_tx.sha256, 0), nSequence=sequence_value)] - tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee * COIN), DUMMY_P2WPKH_SCRIPT)] + tx.wit.vtxinwit = [CTxInWitness()] + tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])] + tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)] tx.rehash() if (orig_tx.hash in node.getrawmempool()): @@ -367,7 +376,7 @@ class BIP68Test(BitcoinTestFramework): tx2 = CTransaction() tx2.nVersion = 1 tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)] - tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), DUMMY_P2WPKH_SCRIPT)] + tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)] # sign tx2 tx2_raw = self.nodes[0].signrawtransactionwithwallet(tx2.serialize().hex())["hex"] @@ -382,7 +391,9 @@ class BIP68Test(BitcoinTestFramework): tx3 = CTransaction() tx3.nVersion = 2 tx3.vin = [CTxIn(COutPoint(tx2.sha256, 0), nSequence=sequence_value)] - tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee * COIN), DUMMY_P2WPKH_SCRIPT)] + tx3.wit.vtxinwit = [CTxInWitness()] + tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])] + tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)] tx3.rehash() assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, tx3.serialize().hex()) |