diff --git a/ci/dash/lint-tidy.sh b/ci/dash/lint-tidy.sh index 7b5aeab03258..0ed43ce633b4 100755 --- a/ci/dash/lint-tidy.sh +++ b/ci/dash/lint-tidy.sh @@ -87,6 +87,7 @@ iwyu_tool.py \ "src/compat" \ "src/dbwrapper.cpp" \ "src/init" \ + "src/kernel/mempool_persist.cpp" \ "src/node/chainstate.cpp" \ "src/node/minisketchwrapper.cpp" \ "src/policy/feerate.cpp" \ diff --git a/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh b/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh index ef228c677fef..291e949631c2 100755 --- a/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh +++ b/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh @@ -11,4 +11,4 @@ export HOST=x86_64-pc-linux-gnu export PACKAGES="python3-zmq" export DEP_OPTS="NO_WALLET=1 CC=gcc-14 CXX=g++-14" export GOAL="install" -export BITCOIN_CONFIG="--enable-reduce-exports CC=gcc-14 CXX=g++-14 --enable-experimental-util-chainstate" +export BITCOIN_CONFIG="--enable-reduce-exports CC=gcc-14 CXX=g++-14 --enable-experimental-util-chainstate --with-experimental-kernel-lib --enable-shared" diff --git a/configure.ac b/configure.ac index 0c97af58e657..9e9d21be5fd0 100644 --- a/configure.ac +++ b/configure.ac @@ -783,6 +783,12 @@ AC_ARG_WITH([libs], [build_bitcoin_libs=$withval], [build_bitcoin_libs=yes]) +AC_ARG_WITH([experimental-kernel-lib], + [AS_HELP_STRING([--with-experimental-kernel-lib], + [build experimental dashkernel library (default is to build if we're building libraries and the experimental build-chainstate executable)])], + [build_experimental_kernel_lib=$withval], + [build_experimental_kernel_lib=auto]) + AC_ARG_WITH([daemon], [AS_HELP_STRING([--with-daemon], [build dashd daemon (default=yes)])], @@ -1791,15 +1797,24 @@ AM_CONDITIONAL([BUILD_BITCOIN_UTIL], [test $build_bitcoin_util = "yes"]) AC_MSG_RESULT($build_bitcoin_util) AC_MSG_CHECKING([whether to build experimental dash-chainstate]) +if test "$build_bitcoin_chainstate" = "yes"; then + if test "$build_experimental_kernel_lib" = "no"; then + AC_MSG_ERROR([experimental dash-chainstate cannot be built without the experimental dashkernel library. Use --with-experimental-kernel-lib]); + fi +fi AM_CONDITIONAL([BUILD_BITCOIN_CHAINSTATE], [test $build_bitcoin_chainstate = "yes"]) AC_MSG_RESULT($build_bitcoin_chainstate) AC_MSG_CHECKING([whether to build libraries]) AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test $build_bitcoin_libs = "yes"]) + if test "$build_bitcoin_libs" = "yes"; then AC_DEFINE([HAVE_CONSENSUS_LIB], [1], [Define this symbol if the consensus lib has been built]) AC_CONFIG_FILES([libdashconsensus.pc:libdashconsensus.pc.in]) fi + +AM_CONDITIONAL([BUILD_BITCOIN_KERNEL_LIB], [test "$build_experimental_kernel_lib" != "no" && ( test "$build_experimental_kernel_lib" = "yes" || test "$build_bitcoin_chainstate" = "yes" )]) + AC_MSG_RESULT($build_bitcoin_libs) AC_LANG_POP diff --git a/contrib/devtools/iwyu/bitcoin.core.imp b/contrib/devtools/iwyu/bitcoin.core.imp index c4c4ba4cebd8..a7fe095226e1 100644 --- a/contrib/devtools/iwyu/bitcoin.core.imp +++ b/contrib/devtools/iwyu/bitcoin.core.imp @@ -1,3 +1,4 @@ # Nothing for now. [ + { include: [ "", private, "", public ] }, ] diff --git a/src/Makefile.am b/src/Makefile.am index 5137d940baef..42108e20079f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ AM_LIBTOOLFLAGS = --preserve-dup-deps PTHREAD_FLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) EXTRA_LIBRARIES = -lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS) +lib_LTLIBRARIES = noinst_LTLIBRARIES = bin_PROGRAMS = @@ -61,6 +61,9 @@ endif if BUILD_BITCOIN_LIBS LIBBITCOINCONSENSUS=libdashconsensus.la endif +if BUILD_BITCOIN_KERNEL_LIB +LIBBITCOINKERNEL=libdashkernel.la +endif if ENABLE_WALLET LIBBITCOIN_WALLET=libbitcoin_wallet.a LIBBITCOIN_WALLET_TOOL=libbitcoin_wallet_tool.a @@ -169,22 +172,21 @@ BITCOIN_CORE_H = \ bech32.h \ bip324.h \ blockencodings.h \ - common/bloom.h \ + blockfilter.h \ cachemap.h \ cachemultimap.h \ - blockfilter.h \ chain.h \ chainlock/chainlock.h \ - chainlock/handler.h \ chainlock/clsig.h \ + chainlock/handler.h \ chainlock/signing.h \ chainparams.h \ chainparamsbase.h \ chainparamsseeds.h \ checkqueue.h \ clientversion.h \ - coinjoin/coinjoin.h \ coinjoin/client.h \ + coinjoin/coinjoin.h \ coinjoin/common.h \ coinjoin/options.h \ coinjoin/server.h \ @@ -200,24 +202,25 @@ BITCOIN_CORE_H = \ compat/cpuid.h \ compat/endian.h \ compressor.h \ - context.h \ consensus/consensus.h \ consensus/tx_check.h \ consensus/tx_verify.h \ + context.h \ core_io.h \ core_memusage.h \ - cuckoocache.h \ ctpl_stl.h \ + cuckoocache.h \ cxxtimer.hpp \ dbwrapper.h \ deploymentinfo.h \ deploymentstatus.h \ + dsnotificationinterface.h \ evo/assetlocktx.h \ - evo/dmn_types.h \ evo/cbtx.h \ evo/chainhelper.h \ evo/creditpool.h \ evo/deterministicmns.h \ + evo/dmn_types.h \ evo/dmnstate.h \ evo/evodb.h \ evo/mnauth.h \ @@ -231,7 +234,9 @@ BITCOIN_CORE_H = \ evo/specialtxman.h \ evo/types.h \ external_signer.h \ - dsnotificationinterface.h \ + flat-database.h \ + flatfile.h \ + fs.h \ governance/common.h \ governance/governance.h \ governance/net_governance.h \ @@ -242,9 +247,6 @@ BITCOIN_CORE_H = \ governance/votedb.h \ gsl/assert.h \ gsl/pointers.h \ - flat-database.h \ - flatfile.h \ - fs.h \ httprpc.h \ httpserver.h \ i2p.h \ @@ -263,6 +265,11 @@ BITCOIN_CORE_H = \ indirectmap.h \ init.h \ init/common.h \ + instantsend/db.h \ + instantsend/instantsend.h \ + instantsend/lock.h \ + instantsend/net_instantsend.h \ + instantsend/signing.h \ interfaces/chain.h \ interfaces/coinjoin.h \ interfaces/echo.h \ @@ -271,13 +278,14 @@ BITCOIN_CORE_H = \ interfaces/ipc.h \ interfaces/node.h \ interfaces/wallet.h \ - instantsend/db.h \ - instantsend/instantsend.h \ - instantsend/lock.h \ - instantsend/net_instantsend.h \ - instantsend/signing.h \ kernel/blockmanager_opts.h \ + kernel/chainstatemanager_opts.h \ + kernel/checks.h \ kernel/coinstats.h \ + kernel/context.h \ + kernel/mempool_limits.h \ + kernel/mempool_options.h \ + kernel/mempool_persist.h \ key.h \ key_io.h \ limitedmap.h \ @@ -289,6 +297,8 @@ BITCOIN_CORE_H = \ llmq/dkgsessionhandler.h \ llmq/dkgsessionmgr.h \ llmq/ehf_signals.h \ + llmq/net_quorum.h \ + llmq/net_signing.h \ llmq/observer.h \ llmq/options.h \ llmq/params.h \ @@ -296,8 +306,6 @@ BITCOIN_CORE_H = \ llmq/quorumsman.h \ llmq/signhash.h \ llmq/signing.h \ - llmq/net_quorum.h \ - llmq/net_signing.h \ llmq/signing_shares.h \ llmq/snapshot.h \ llmq/types.h \ @@ -309,6 +317,7 @@ BITCOIN_CORE_H = \ masternode/payments.h \ masternode/sync.h \ masternode/utils.h \ + mempool_args.h \ memusage.h \ merkleblock.h \ messagesigner.h \ @@ -329,18 +338,20 @@ BITCOIN_CORE_H = \ node/connection_types.h \ node/context.h \ node/eviction.h \ + node/interface_ui.h \ + node/mempool_persist_args.h \ node/miner.h \ node/minisketchwrapper.h \ node/psbt.h \ node/sync_manager.h \ node/transaction.h \ node/txreconciliation.h \ - node/interface_ui.h \ node/utxo_snapshot.h \ noui.h \ outputtype.h \ policy/feerate.h \ policy/fees.h \ + policy/fees_args.h \ policy/packages.h \ policy/policy.h \ policy/settings.h \ @@ -375,9 +386,9 @@ BITCOIN_CORE_H = \ source_location.h \ spork.h \ stacktraces.h \ - streams.h \ stats/client.h \ stats/rawsender.h \ + streams.h \ support/allocators/mt_pooled_secure.h \ support/allocators/pool.h \ support/allocators/pooled_secure.h \ @@ -395,6 +406,7 @@ BITCOIN_CORE_H = \ txorphanage.h \ undo.h \ unordered_lru_cache.h \ + util/asmap.h \ util/bip32.h \ util/bytevectorhash.h \ util/check.h \ @@ -403,33 +415,32 @@ BITCOIN_CORE_H = \ util/error.h \ util/fastrange.h \ util/fees.h \ + util/getuniquepath.h \ util/golombrice.h \ - util/hasher.h \ util/hash_type.h \ + util/hasher.h \ util/helpers.h \ - util/asmap.h \ - util/getuniquepath.h \ util/macros.h \ util/message.h \ util/moneystr.h \ util/overflow.h \ util/overloaded.h \ + util/ranges_set.h \ util/readwritefile.h \ util/result.h \ util/serfloat.h \ util/settings.h \ - util/std23.h \ - util/ranges_set.h \ util/sock.h \ - util/string.h \ util/spanparsing.h \ + util/std23.h \ + util/string.h \ util/subprocess.hpp \ util/syserror.h \ util/system.h \ - util/time.h \ util/thread.h \ util/threadinterrupt.h \ util/threadnames.h \ + util/time.h \ util/tokenpipe.h \ util/trace.h \ util/translation.h \ @@ -511,8 +522,8 @@ libbitcoin_node_a_SOURCES = \ dsnotificationinterface.cpp \ evo/assetlocktx.cpp \ evo/cbtx.cpp \ - evo/creditpool.cpp \ evo/chainhelper.cpp \ + evo/creditpool.cpp \ evo/deterministicmns.cpp \ evo/dmnstate.cpp \ evo/evodb.cpp \ @@ -550,7 +561,10 @@ libbitcoin_node_a_SOURCES = \ instantsend/lock.cpp \ instantsend/net_instantsend.cpp \ instantsend/signing.cpp \ + kernel/checks.cpp \ kernel/coinstats.cpp \ + kernel/context.cpp \ + kernel/mempool_persist.cpp \ llmq/blockprocessor.cpp \ llmq/commitment.cpp \ llmq/context.cpp \ @@ -575,10 +589,11 @@ libbitcoin_node_a_SOURCES = \ masternode/payments.cpp \ masternode/sync.cpp \ masternode/utils.cpp \ + mempool_args.cpp \ net.cpp \ + net_processing.cpp \ netfulfilledman.cpp \ netgroup.cpp \ - net_processing.cpp \ node/blockstorage.cpp \ node/caches.cpp \ node/chainstate.cpp \ @@ -586,16 +601,18 @@ libbitcoin_node_a_SOURCES = \ node/connection_types.cpp \ node/context.cpp \ node/eviction.cpp \ + node/interface_ui.cpp \ node/interfaces.cpp \ + node/mempool_persist_args.cpp \ node/miner.cpp \ node/minisketchwrapper.cpp \ node/psbt.cpp \ node/sync_manager.cpp \ node/transaction.cpp \ node/txreconciliation.cpp \ - node/interface_ui.cpp \ noui.cpp \ policy/fees.cpp \ + policy/fees_args.cpp \ policy/packages.cpp \ policy/policy.cpp \ policy/settings.cpp \ @@ -605,12 +622,12 @@ libbitcoin_node_a_SOURCES = \ rpc/coinjoin.cpp \ rpc/evo.cpp \ rpc/fees.cpp \ + rpc/governance.cpp \ rpc/masternode.cpp \ rpc/mempool.cpp \ - rpc/governance.cpp \ rpc/mining.cpp \ - rpc/node.cpp \ rpc/net.cpp \ + rpc/node.cpp \ rpc/output_script.cpp \ rpc/quorums.cpp \ rpc/rawtransaction.cpp \ @@ -663,8 +680,9 @@ libbitcoin_wallet_a_SOURCES = \ coinjoin/interfaces.cpp \ coinjoin/util.cpp \ wallet/bip39.cpp \ - wallet/coinjoin.cpp \ wallet/coincontrol.cpp \ + wallet/coinjoin.cpp \ + wallet/coinselection.cpp \ wallet/context.cpp \ wallet/crypter.cpp \ wallet/db.cpp \ @@ -679,8 +697,8 @@ libbitcoin_wallet_a_SOURCES = \ wallet/rpc/backup.cpp \ wallet/rpc/coins.cpp \ wallet/rpc/encrypt.cpp \ - wallet/rpc/spend.cpp \ wallet/rpc/signmessage.cpp \ + wallet/rpc/spend.cpp \ wallet/rpc/transactions.cpp \ wallet/rpc/util.cpp \ wallet/rpc/wallet.cpp \ @@ -690,7 +708,6 @@ libbitcoin_wallet_a_SOURCES = \ wallet/wallet.cpp \ wallet/walletdb.cpp \ wallet/walletutil.cpp \ - wallet/coinselection.cpp \ $(BITCOIN_CORE_H) if USE_SQLITE @@ -722,10 +739,10 @@ crypto_libbitcoin_crypto_base_la_LDFLAGS = $(AM_LDFLAGS) -static crypto_libbitcoin_crypto_base_la_SOURCES = \ crypto/aes.cpp \ crypto/aes.h \ - crypto/chacha20.h \ crypto/chacha20.cpp \ - crypto/chacha20poly1305.h \ + crypto/chacha20.h \ crypto/chacha20poly1305.cpp \ + crypto/chacha20poly1305.h \ crypto/common.h \ crypto/hkdf_sha256_32.cpp \ crypto/hkdf_sha256_32.h \ @@ -733,12 +750,12 @@ crypto_libbitcoin_crypto_base_la_SOURCES = \ crypto/hmac_sha256.h \ crypto/hmac_sha512.cpp \ crypto/hmac_sha512.h \ - crypto/muhash.h \ crypto/muhash.cpp \ - crypto/poly1305.h \ - crypto/poly1305.cpp \ + crypto/muhash.h \ crypto/pkcs5_pbkdf2_hmac_sha512.cpp \ crypto/pkcs5_pbkdf2_hmac_sha512.h \ + crypto/poly1305.cpp \ + crypto/poly1305.h \ crypto/ripemd160.cpp \ crypto/ripemd160.h \ crypto/sha1.cpp \ @@ -939,10 +956,10 @@ libbitcoin_common_a_SOURCES = \ key_io.cpp \ llmq/core_write.cpp \ merkleblock.cpp \ + net_permissions.cpp \ net_types.cpp \ netaddress.cpp \ netbase.cpp \ - net_permissions.cpp \ outputtype.cpp \ policy/feerate.cpp \ policy/policy.cpp \ @@ -978,11 +995,10 @@ libbitcoin_util_a_SOURCES = \ bls/bls_ies.h \ bls/bls_worker.cpp \ bls/bls_worker.h \ - coinjoin/common.cpp \ - coinjoin/options.cpp \ - support/lockedpool.cpp \ chainparamsbase.cpp \ clientversion.cpp \ + coinjoin/common.cpp \ + coinjoin/options.cpp \ fs.cpp \ interfaces/echo.cpp \ interfaces/handler.cpp \ @@ -993,6 +1009,7 @@ libbitcoin_util_a_SOURCES = \ randomenv.cpp \ stacktraces.cpp \ support/cleanse.cpp \ + support/lockedpool.cpp \ sync.cpp \ util/asmap.cpp \ util/bip32.cpp \ @@ -1001,24 +1018,24 @@ libbitcoin_util_a_SOURCES = \ util/edge.cpp \ util/error.cpp \ util/fees.cpp \ - util/hasher.cpp \ util/getuniquepath.cpp \ - util/sock.cpp \ - util/syserror.cpp \ - util/system.cpp \ + util/hasher.cpp \ util/message.cpp \ util/moneystr.cpp \ + util/ranges_set.cpp \ util/readwritefile.cpp \ + util/serfloat.cpp \ util/settings.cpp \ - util/ranges_set.cpp \ + util/sock.cpp \ util/spanparsing.cpp \ util/strencodings.cpp \ - util/time.cpp \ - util/serfloat.cpp \ util/string.cpp \ + util/syserror.cpp \ + util/system.cpp \ util/thread.cpp \ util/threadinterrupt.cpp \ util/threadnames.cpp \ + util/time.cpp \ util/tokenpipe.cpp \ util/wpipe.cpp \ $(BITCOIN_CORE_H) @@ -1163,10 +1180,48 @@ dash_util_LDADD = \ dash_util_LDADD += $(BOOST_LIBS) # dash-chainstate binary # -dash_chainstate_SOURCES = \ - bitcoin-chainstate.cpp \ - index/addressindex.cpp \ - index/addressindex_util.cpp \ +dash_chainstate_SOURCES = bitcoin-chainstate.cpp +dash_chainstate_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) +dash_chainstate_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) + +# $(LIBTOOL_APP_LDFLAGS) deliberately omitted here so that we can test linking +# dash-chainstate against libdashkernel as a shared or static library by +# setting --{en,dis}able-shared. +dash_chainstate_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(PTHREAD_FLAGS) +dash_chainstate_LDADD = $(LIBBITCOINKERNEL) +# + +# dashkernel library # +if BUILD_BITCOIN_KERNEL_LIB +lib_LTLIBRARIES += $(LIBBITCOINKERNEL) + +libdashkernel_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) $(PTHREAD_FLAGS) +libdashkernel_la_LIBADD = $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) $(LIBSECP256K1) $(LIBDASHBLS) $(GMP_LIBS) +libdashkernel_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL -isystem$(srcdir)/dashbls/include -isystem$(srcdir)/dashbls/depends/relic/include -isystem$(srcdir)/dashbls/depends/minialloc/include -isystem$(srcdir)/immer $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) + +# libdashkernel requires default symbol visibility, explicitly specify that +# here so that things still work even when user configures with +# --enable-reduce-exports +# +# Note this is a quick hack that will be removed as we incrementally define what +# to export from the library. +libdashkernel_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -fvisibility=default + +# TODO: For now, Specify -static in both CXXFLAGS and LDFLAGS when building for +# windows targets so libtool will only build a static version of this +# library. There are unresolved problems when building dll's for mingw-w64 +# and attempting to statically embed libstdc++, libpthread, etc. +if TARGET_WINDOWS +libdashkernel_la_LDFLAGS += -static +libdashkernel_la_CXXFLAGS += -static +endif + +# TODO: libdashkernel is a work in progress consensus engine library, as more +# and more modules are decoupled from the consensus engine, this list will +# shrink to only those which are absolutely necessary. For example, things +# like index/*.cpp will be removed. +libdashkernel_la_SOURCES = \ + kernel/bitcoinkernel.cpp \ arith_uint256.cpp \ base58.cpp \ batchedlogger.cpp \ @@ -1175,30 +1230,30 @@ dash_chainstate_SOURCES = \ bls/bls.cpp \ bls/bls_worker.cpp \ chain.cpp \ - chainparamsbase.cpp \ + chainlock/chainlock.cpp \ + chainlock/clsig.cpp \ chainparams.cpp \ + chainparamsbase.cpp \ clientversion.cpp \ coins.cpp \ + common/bloom.cpp \ compressor.cpp \ - chainlock/clsig.cpp \ - chainlock/chainlock.cpp \ consensus/merkle.cpp \ consensus/tx_check.cpp \ consensus/tx_verify.cpp \ - common/bloom.cpp \ core_read.cpp \ dbwrapper.cpp \ deploymentinfo.cpp \ deploymentstatus.cpp \ evo/assetlocktx.cpp \ evo/cbtx.cpp \ - evo/creditpool.cpp \ evo/chainhelper.cpp \ + evo/creditpool.cpp \ evo/deterministicmns.cpp \ evo/dmnstate.cpp \ evo/evodb.cpp \ - evo/netinfo.cpp \ evo/mnhftx.cpp \ + evo/netinfo.cpp \ evo/providertx.cpp \ evo/simplifiedmns.cpp \ evo/smldiff.cpp \ @@ -1214,14 +1269,20 @@ dash_chainstate_SOURCES = \ governance/votedb.cpp \ gsl/assert.cpp \ hash.cpp \ + index/addressindex.cpp \ + index/addressindex_util.cpp \ index/base.cpp \ index/blockfilterindex.cpp \ index/coinstatsindex.cpp \ index/spentindex.cpp \ index/txindex.cpp \ + init/common.cpp \ instantsend/db.cpp \ instantsend/instantsend.cpp \ - init/common.cpp \ + kernel/checks.cpp \ + kernel/coinstats.cpp \ + kernel/context.cpp \ + kernel/mempool_persist.cpp \ key.cpp \ key_io.cpp \ llmq/blockprocessor.cpp \ @@ -1239,27 +1300,26 @@ dash_chainstate_SOURCES = \ llmq/snapshot.cpp \ llmq/utils.cpp \ logging.cpp \ - netaddress.cpp \ - netbase.cpp \ - node/blockstorage.cpp \ - node/chainstate.cpp \ - node/transaction.cpp \ - kernel/coinstats.cpp \ masternode/meta.cpp \ masternode/payments.cpp \ masternode/sync.cpp \ - messagesigner.cpp \ merkleblock.cpp \ + messagesigner.cpp \ + netaddress.cpp \ + netbase.cpp \ + node/blockstorage.cpp \ + node/chainstate.cpp \ node/interface_ui.cpp \ + node/transaction.cpp \ policy/feerate.cpp \ policy/fees.cpp \ policy/packages.cpp \ policy/policy.cpp \ policy/settings.cpp \ pow.cpp \ - protocol.cpp \ primitives/block.cpp \ primitives/transaction.cpp \ + protocol.cpp \ pubkey.cpp \ random.cpp \ randomenv.cpp \ @@ -1270,8 +1330,8 @@ dash_chainstate_SOURCES = \ script/script_error.cpp \ script/sigcache.cpp \ script/standard.cpp \ - spork.cpp \ shutdown.cpp \ + spork.cpp \ support/cleanse.cpp \ support/lockedpool.cpp \ sync.cpp \ @@ -1279,7 +1339,6 @@ dash_chainstate_SOURCES = \ txdb.cpp \ txmempool.cpp \ uint256.cpp \ - util/asmap.cpp \ util/bytevectorhash.cpp \ util/check.cpp \ util/getuniquepath.cpp \ @@ -1290,8 +1349,8 @@ dash_chainstate_SOURCES = \ util/serfloat.cpp \ util/settings.cpp \ util/sock.cpp \ - util/string.cpp \ util/strencodings.cpp \ + util/string.cpp \ util/syserror.cpp \ util/system.cpp \ util/thread.cpp \ @@ -1303,25 +1362,17 @@ dash_chainstate_SOURCES = \ validationinterface.cpp \ versionbits.cpp \ warnings.cpp -dash_chainstate_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) -dash_chainstate_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -dash_chainstate_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -dash_chainstate_LDADD = \ - $(LIBBITCOIN_CRYPTO) \ - $(LIBUNIVALUE) \ - $(LIBSECP256K1) \ - $(LIBDASHBLS) \ - $(LIBLEVELDB) \ - $(LIBMEMENV) \ - $(GMP_LIBS) # Required for obj/build.h to be generated first. # More details: https://www.gnu.org/software/automake/manual/html_node/Built-Sources-Example.html -dash_chainstate-clientversion.$(OBJEXT): obj/build.h +libdashkernel_la-clientversion.l$(OBJEXT): obj/build.h +endif # BUILD_BITCOIN_KERNEL_LIB # # dashconsensus library # if BUILD_BITCOIN_LIBS +lib_LTLIBRARIES += $(LIBBITCOINCONSENSUS) + include_HEADERS = script/bitcoinconsensus.h libdashconsensus_la_SOURCES = support/cleanse.cpp $(crypto_libbitcoin_crypto_base_la_SOURCES) $(crypto_libbitcoin_crypto_sph_la_SOURCES) $(libbitcoin_consensus_a_SOURCES) diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include index 143917357d78..9ad315beb0aa 100644 --- a/src/Makefile.test_fuzz.include +++ b/src/Makefile.test_fuzz.include @@ -12,6 +12,7 @@ TEST_FUZZ_H = \ test/fuzz/FuzzedDataProvider.h \ test/fuzz/util.h \ test/util/mining.h \ + test/fuzz/mempool_utils.h \ test/fuzz/util/net.h libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp index d9a4a4d0ace1..271a6ed7ed5c 100644 --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -11,6 +11,9 @@ // // It is part of the libbitcoinkernel project. +#include +#include + #include #include #include @@ -32,44 +35,11 @@ #include #include +#include #include #include #include -const std::function G_TRANSLATION_FUN = nullptr; - -//---------------- -// symbols g_stats_client, ValueFromAmount, GetPrettyExceptionStr are re-defined -// here especially for dash-chainstate binary (kernel), because adding sources -// containing them pulls too many extra dependencies recursively -#include -std::unique_ptr g_stats_client{std::make_unique()}; - -UniValue ValueFromAmount(const CAmount amount) -{ - static_assert(COIN > 1); - int64_t quotient = amount / COIN; - int64_t remainder = amount % COIN; - if (amount < 0) { - quotient = -quotient; - remainder = -remainder; - } - return UniValue(UniValue::VNUM, - strprintf("%s%d.%08d", amount < 0 ? "-" : "", quotient, remainder)); -} -std::string GetPrettyExceptionStr(const std::exception_ptr& e) -{ - try { - // rethrow and catch the exception as there is no other way to reliably cast to the real type (not possible with RTTI) - std::rethrow_exception(e); - } catch (const std::exception& e2) { - return e2.what(); - } catch (...) { - throw; - } -} -////////////////////// - int main(int argc, char* argv[]) { // SETUP: Argument parsing and handling @@ -91,7 +61,11 @@ int main(int argc, char* argv[]) SelectParams(CBaseChainParams::MAIN); const CChainParams& chainparams = Params(); - init::SetGlobals(); // ECC_Start, etc. + kernel::Context kernel_context{}; + // We can't use a goto here, but we can use an assert since none of the + // things instantiated so far requires running the epilogue to be torn down + // properly + assert(!kernel::SanityChecks(kernel_context).has_value()); // Necessary for CheckInputScripts (eventually called by ProcessNewBlock), // which will try the script cache first and fall back to actually @@ -112,7 +86,11 @@ int main(int argc, char* argv[]) // SETUP: Chainstate - ChainstateManager chainman{chainparams}; + const ChainstateManager::Options chainman_opts{ + .chainparams = chainparams, + .adjusted_time_callback = static_cast(GetTime), + }; + ChainstateManager chainman{chainman_opts}; CMasternodeMetaMan metaman; std::unique_ptr evodb; @@ -136,7 +114,6 @@ int main(int argc, char* argv[]) /*mempool=*/nullptr, gArgs.GetDataDirNet(), /*fPruneMode=*/false, - chainparams.GetConsensus(), /*fReindexChainState=*/false, 2 << 20, 2 << 22, @@ -157,10 +134,8 @@ int main(int argc, char* argv[]) *evodb, false, false, - chainparams.GetConsensus(), DEFAULT_CHECKBLOCKS, - DEFAULT_CHECKLEVEL, - /*get_unix_time_seconds=*/static_cast(GetTime)); + DEFAULT_CHECKLEVEL); if (maybe_verify_error.has_value()) { std::cerr << "Failed to verify loaded Chain state from your datadir." << std::endl; goto epilogue; @@ -314,9 +289,7 @@ int main(int argc, char* argv[]) } } GetMainSignals().UnregisterBackgroundSignalScheduler(); - // Tear down Dash kernel objects before init::UnsetGlobals(). + // Tear down Dash kernel objects before kernel::~Context(). node::DashChainstateSetupClose(chain_helper, dmnman, llmq_ctx, /*mempool=*/nullptr); evodb.reset(); - - init::UnsetGlobals(); } diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index b364c7e5439a..da628f0c51b8 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -193,11 +193,14 @@ static bool AppInit(NodeContext& node, int argc, char* argv[]) // InitError will have been called with detailed error, which ends up on console return false; } - if (!AppInitSanityChecks()) + + node.kernel = std::make_unique(); + if (!AppInitSanityChecks(*node.kernel)) { // InitError will have been called with detailed error, which ends up on console return false; } + if (args.GetBoolArg("-daemon", DEFAULT_DAEMON) || args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) { #if HAVE_DECL_FORK tfm::format(std::cout, PACKAGE_NAME " starting\n"); diff --git a/src/bls/bls.h b/src/bls/bls.h index 5be483b9b334..02a3bbefa5bf 100644 --- a/src/bls/bls.h +++ b/src/bls/bls.h @@ -386,7 +386,6 @@ class CBLSSignatureVersionWrapper { } }; -#ifndef BUILD_BITCOIN_INTERNAL template class CBLSLazyWrapper { @@ -592,7 +591,6 @@ class CBLSLazyPublicKeyVersionWrapper { obj.Unserialize(s, legacy); } }; -#endif using BLSVerificationVectorPtr = std::shared_ptr>; diff --git a/src/bls/bls_worker.cpp b/src/bls/bls_worker.cpp index 70e778c62df4..ddd32543ca3d 100644 --- a/src/bls/bls_worker.cpp +++ b/src/bls/bls_worker.cpp @@ -69,6 +69,7 @@ void CBLSWorker::Stop() workerPool.stop(true); } +#ifndef BUILD_BITCOIN_INTERNAL bool CBLSWorker::GenerateContributions(int quorumThreshold, Span ids, BLSVerificationVectorPtr& vvecRet, std::vector& skSharesRet) { auto svec = std::vector((size_t)quorumThreshold); @@ -109,6 +110,7 @@ bool CBLSWorker::GenerateContributions(int quorumThreshold, Span ids, BL } return std::ranges::all_of(futures, [](auto& f) { return f.get(); }); } +#endif // aggregates a single vector of BLS objects in parallel // the input vector is split into batches and each batch is aggregated in parallel diff --git a/src/bls/bls_worker.h b/src/bls/bls_worker.h index 529c9427baad..1ffa1ebfc34d 100644 --- a/src/bls/bls_worker.h +++ b/src/bls/bls_worker.h @@ -57,7 +57,9 @@ class CBLSWorker void Start(int16_t worker_count); void Stop(); +#ifndef BUILD_BITCOIN_INTERNAL bool GenerateContributions(int threshold, Span ids, BLSVerificationVectorPtr& vvecRet, std::vector& skSharesRet); +#endif // The following functions are all used to aggregate verification (public key) vectors // Inputs are in the following form: diff --git a/src/deploymentstatus.h b/src/deploymentstatus.h index 2651baac7349..6d613d1ec6ea 100644 --- a/src/deploymentstatus.h +++ b/src/deploymentstatus.h @@ -17,6 +17,13 @@ inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus return (pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1) >= params.DeploymentHeight(dep); } +/** Determine if a deployment is active for the next block */ +inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::BuriedDeployment dep, [[maybe_unused]] VersionBitsCache& versionbitscache) +{ + assert(Consensus::ValidDeployment(dep)); + return (pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1) >= params.DeploymentHeight(dep); +} + inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos dep, VersionBitsCache& versionbitscache) { assert(Consensus::ValidDeployment(dep)); @@ -30,6 +37,12 @@ inline bool DeploymentActiveAt(const CBlockIndex& index, const Consensus::Params return index.nHeight >= params.DeploymentHeight(dep); } +inline bool DeploymentActiveAt(const CBlockIndex& index, const Consensus::Params& params, Consensus::BuriedDeployment dep, [[maybe_unused]] VersionBitsCache& versionbitscache) +{ + assert(Consensus::ValidDeployment(dep)); + return index.nHeight >= params.DeploymentHeight(dep); +} + inline bool DeploymentActiveAt(const CBlockIndex& index, const Consensus::Params& params, Consensus::DeploymentPos dep, VersionBitsCache& versionbitscache) { assert(Consensus::ValidDeployment(dep)); diff --git a/src/evo/mnhftx.cpp b/src/evo/mnhftx.cpp index 9e7c6f60abf7..e0d52bde2f80 100644 --- a/src/evo/mnhftx.cpp +++ b/src/evo/mnhftx.cpp @@ -285,14 +285,13 @@ CMNHFManager::Signals CMNHFManager::GetForBlock(const CBlockIndex* pindex) pindex = pindex->pprev; } - const Consensus::Params& consensusParams{Params().GetConsensus()}; while (!to_calculate.empty()) { const CBlockIndex* pindex_top{to_calculate.top()}; if (pindex_top->nHeight % 1000 == 0) { LogPrintf("re-index EHF signals at block %d\n", pindex_top->nHeight); } CBlock block; - if (!ReadBlockFromDisk(block, pindex_top, consensusParams)) { + if (!ReadBlockFromDisk(block, pindex_top, m_chainman.GetConsensus())) { throw std::runtime_error("failed-getehfforblock-read"); } BlockValidationState state; diff --git a/src/fs.h b/src/fs.h index 270ce6fd1f00..761534a45da3 100644 --- a/src/fs.h +++ b/src/fs.h @@ -9,6 +9,7 @@ #include #include // IWYU pragma: export +#include #include #include #include @@ -204,6 +205,7 @@ bool create_directories(const std::filesystem::path& p, std::error_code& ec) = d /** Bridge operations to C stdio */ namespace fsbridge { + using FopenFn = std::function; FILE *fopen(const fs::path& p, const char *mode); /** diff --git a/src/init.cpp b/src/init.cpp index c6f641e7e407..20c08bb3f4ed 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -10,6 +10,9 @@ #include +#include +#include + #include #include #include @@ -38,7 +41,7 @@ #include #include #include -#include +#include #include #include #include @@ -49,10 +52,13 @@ #include #include #include +#include +#include #include #include #include #include +#include #include #include #include @@ -146,15 +152,19 @@ #endif using kernel::CoinStatsHashType; +using kernel::DumpMempool; using node::CacheSizes; using node::CalculateCacheSizes; using node::ChainstateLoadingError; using node::ChainstateLoadVerifyError; using node::DashChainstateSetupClose; +using node::DEFAULT_PERSIST_MEMPOOL; using node::DEFAULT_PRINTPRIORITY; using node::DEFAULT_STOPAFTERBLOCKIMPORT; using node::LoadChainstate; +using node::MempoolPath; +using node::ShouldPersistMempool; using node::NodeContext; using node::ThreadImport; using node::VerifyLoadedChainstate; @@ -334,8 +344,8 @@ void PrepareShutdown(NodeContext& node) node.netgroupman.reset(); ::g_stats_client.reset(); - if (node.mempool && node.mempool->IsLoaded() && node.args->GetBoolArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { - DumpMempool(*node.mempool); + if (node.mempool && node.mempool->GetLoadTried() && ShouldPersistMempool(*node.args)) { + DumpMempool(*node.mempool, MempoolPath(*node.args)); } // Drop transactions we were still watching, and record fee estimations. @@ -469,7 +479,7 @@ void Shutdown(NodeContext& node) PrepareShutdown(node); } // Shutdown part 2: delete wallet instance - init::UnsetGlobals(); + node.kernel.reset(); node.mempool.reset(); node.fee_estimator.reset(); node.chainman.reset(); @@ -581,10 +591,10 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-dbcache=", strprintf("Maximum database cache size MiB (%d to %d, default: %d). In addition, unused mempool memory is shared for this cache (see -maxmempool).", nMinDbCache, nMaxDbCache, nDefaultDbCache), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-includeconf=", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-loadblock=", "Imports blocks from external file on startup", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-maxmempool=", strprintf("Keep the transaction memory pool below megabytes (default: %u)", DEFAULT_MAX_MEMPOOL_SIZE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-maxmempool=", strprintf("Keep the transaction memory pool below megabytes (default: %u)", DEFAULT_MAX_MEMPOOL_SIZE_MB), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-maxorphantxsize=", strprintf("Maximum total size of all orphan transactions in megabytes (default: %u)", DEFAULT_MAX_ORPHAN_TRANSACTIONS_SIZE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-maxrecsigsage=", strprintf("Number of seconds to keep LLMQ recovery sigs (default: %u)", llmq::DEFAULT_MAX_RECOVERED_SIGS_AGE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-mempoolexpiry=", strprintf("Do not keep transactions in the mempool longer than hours (default: %u)", DEFAULT_MEMPOOL_EXPIRY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-mempoolexpiry=", strprintf("Do not keep transactions in the mempool longer than hours (default: %u)", DEFAULT_MEMPOOL_EXPIRY_HOURS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-minimumchainwork=", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet: %s, devnet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex(), devnetChainParams->GetConsensus().nMinimumChainWork.GetHex()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); argsman.AddArg("-par=", strprintf("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)", -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -772,9 +782,9 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-deprecatedrpc=", "Allows deprecated RPC method(s) to be used", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-forceevodbrepair", "Force evodb masternode list diff verification and repair on startup, even if already repaired (default: 0)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-limitancestorcount=", strprintf("Do not accept transactions if number of in-mempool ancestors is or more (default: %u)", DEFAULT_ANCESTOR_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-limitancestorsize=", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-limitancestorsize=", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT_KVB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-limitdescendantcount=", strprintf("Do not accept transactions if any ancestor would have or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-limitdescendantsize=", strprintf("Do not accept transactions if any ancestor would have more than kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-limitdescendantsize=", strprintf("Do not accept transactions if any ancestor would have more than kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT_KVB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-stopatheight", strprintf("Stop running after reaching the given height in the main chain (default: %u)", DEFAULT_STOPATHEIGHT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-watchquorums=", strprintf("Watch and validate quorum communication (default: %u)", llmq::DEFAULT_WATCH_QUORUMS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); @@ -884,7 +894,6 @@ static void StartupNotify(const ArgsManager& args) static void PeriodicStats(NodeContext& node) { assert(::g_stats_client->active()); - const ArgsManager& args = *Assert(node.args); ChainstateManager& chainman = *Assert(node.chainman); const CTxMemPool& mempool = *Assert(node.mempool); const llmq::CInstantSendManager& isman = *Assert(node.llmq_ctx->isman); @@ -938,7 +947,7 @@ static void PeriodicStats(NodeContext& node) ::g_stats_client->gauge("transactions.mempool.totalTransactions", mempool.size(), 1.0f); ::g_stats_client->gauge("transactions.mempool.totalTxBytes", (int64_t) mempool.GetTotalTxSize(), 1.0f); ::g_stats_client->gauge("transactions.mempool.memoryUsageBytes", (int64_t) mempool.DynamicMemoryUsage(), 1.0f); - ::g_stats_client->gauge("transactions.mempool.minFeePerKb", mempool.GetMinFee(args.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(), 1.0f); + ::g_stats_client->gauge("transactions.mempool.minFeePerKb", mempool.GetMinFee().GetFeePerK(), 1.0f); } ::g_stats_client->gauge("transactions.mempool.lockedTransactions", isman.GetInstantSendLockCount(), 1.0f); } @@ -1300,11 +1309,6 @@ bool AppInitParameterInteraction(const ArgsManager& args) LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainparams.GetConsensus().nMinimumChainWork.GetHex()); } - // mempool limits - int64_t nMempoolSizeMax = args.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; - int64_t nMempoolSizeMin = args.GetIntArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; - if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin) - return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0))); // incremental relay fee sets the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting. if (args.IsArgSet("-incrementalrelayfee")) { if (std::optional inc_relay_fee = ParseMoney(args.GetArg("-incrementalrelayfee", ""))) { @@ -1466,13 +1470,24 @@ static bool LockDataDirectory(bool probeOnly) return true; } -bool AppInitSanityChecks() +bool AppInitSanityChecks(const kernel::Context& kernel) { // ********************************************************* Step 4: sanity checks + auto maybe_error = kernel::SanityChecks(kernel); + + if (maybe_error.has_value()) { + switch (maybe_error.value()) { + case kernel::SanityCheckError::ERROR_ECC: + InitError(Untranslated("Elliptic curve cryptography sanity check failure. Aborting.")); + break; + case kernel::SanityCheckError::ERROR_BLS: + InitError(Untranslated("BLS cryptographic sanity check failure. Aborting.")); + break; + case kernel::SanityCheckError::ERROR_RANDOM: + InitError(Untranslated("OS cryptographic RNG sanity check failure. Aborting.")); + break; + } // no default case, so the compiler can warn about missing cases - init::SetGlobals(); - - if (!init::SanityChecks()) { return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), PACKAGE_NAME)); } @@ -1694,7 +1709,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) assert(!node.fee_estimator); // Don't initialize fee estimation with old data if we don't relay transactions, // as they would never get updated. - if (!ignores_incoming_txs) node.fee_estimator = std::make_unique(); + if (!ignores_incoming_txs) node.fee_estimator = std::make_unique(FeeestPath(args)); assert(!node.mn_metaman); node.mn_metaman = std::make_unique(); @@ -1954,7 +1969,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // cache size calculations CacheSizes cache_sizes = CalculateCacheSizes(args, g_enabled_filter_types.size()); - int64_t nMempoolSizeMax = args.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; LogPrintf("Cache configuration:\n"); LogPrintf("* Using %.1f MiB for block index database\n", cache_sizes.block_tree_db * (1.0 / 1024 / 1024)); if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { @@ -1974,17 +1988,32 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) cache_sizes.filter_index * (1.0 / 1024 / 1024), BlockFilterTypeName(filter_type)); } LogPrintf("* Using %.1f MiB for chain state database\n", cache_sizes.coins_db * (1.0 / 1024 / 1024)); - LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024)); assert(!node.mempool); assert(!node.chainman); assert(!node.mn_sync); - const int mempool_check_ratio = std::clamp(args.GetIntArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0, 1000000); + + CTxMemPool::Options mempool_opts{ + .estimator = node.fee_estimator.get(), + .check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0, + }; + ApplyArgsManOptions(args, mempool_opts); + mempool_opts.check_ratio = std::clamp(mempool_opts.check_ratio, 0, 1'000'000); + + int64_t descendant_limit_bytes = mempool_opts.limits.descendant_size_vbytes * 40; + if (mempool_opts.max_size_bytes < 0 || mempool_opts.max_size_bytes < descendant_limit_bytes) { + return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(descendant_limit_bytes / 1'000'000.0))); + } + LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024)); for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) { - node.mempool = std::make_unique(node.fee_estimator.get(), mempool_check_ratio); + node.mempool = std::make_unique(mempool_opts); - node.chainman = std::make_unique(chainparams); + const ChainstateManager::Options chainman_opts{ + .chainparams = chainparams, + .adjusted_time_callback = GetAdjustedTime, + }; + node.chainman = std::make_unique(chainman_opts); ChainstateManager& chainman = *node.chainman; /** @@ -2017,7 +2046,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) Assert(node.mempool.get()), args.GetDataDirNet(), fPruneMode, - chainparams.GetConsensus(), fReindexChainState, cache_sizes.block_tree_db, cache_sizes.coins_db, @@ -2102,10 +2130,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) *Assert(node.evodb.get()), fReset, fReindexChainState, - chainparams.GetConsensus(), check_blocks, args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL), - /*get_unix_time_seconds=*/static_cast(GetTime), [](bool bls_state) { LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls_state); }); @@ -2176,7 +2202,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.govman = std::make_unique(*node.mn_metaman, *node.chainman, *node.chain_helper->superblocks, *node.dmnman, *node.mn_sync); assert(!node.peerman); - node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(), *node.dstxman, + node.peerman = PeerManager::make(*node.connman, *node.addrman, node.banman.get(), *node.dstxman, chainman, *node.mempool, *node.mn_metaman, *node.mn_sync, *node.sporkman, *node.chainlocks, *node.clhandler, node.active_ctx, node.dmnman, node.cj_walletman, node.llmq_ctx, node.observer_ctx, ignores_incoming_txs); @@ -2455,7 +2481,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) chainman.m_load_block = std::thread(&util::TraceThread, "loadblk", [=, &args, &chainman, &node] { // ThreadImport can switch fReindex from true to false, fetch its original state here to use later bool skip_evodb_repair_on_reindex = fReindex || fReindexChainState; - ThreadImport(chainman, vImportFiles, args); + ThreadImport(chainman, vImportFiles, args, ShouldPersistMempool(args) ? MempoolPath(args) : fs::path{}); { const CBlockIndex* tip = WITH_LOCK(::cs_main, return chainman.ActiveTip()); @@ -2586,9 +2612,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) chain_active_height = chainman.ActiveChain().Height(); if (tip_info) { tip_info->block_height = chain_active_height; - tip_info->block_time = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockTime() : Params().GenesisBlock().GetBlockTime(); - tip_info->block_hash = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockHash() : Params().GenesisBlock().GetHash(); - tip_info->verification_progress = GuessVerificationProgress(Params().TxData(), chainman.ActiveChain().Tip()); + tip_info->block_time = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockTime() : chainman.GetParams().GenesisBlock().GetBlockTime(); + tip_info->block_hash = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockHash() : chainman.GetParams().GenesisBlock().GetHash(); + tip_info->verification_progress = GuessVerificationProgress(chainman.GetParams().TxData(), chainman.ActiveChain().Tip()); } if (tip_info && chainman.m_best_header) { tip_info->header_height = chainman.m_best_header->nHeight; @@ -2622,7 +2648,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // Port to bind to if `-bind=addr` is provided without a `:port` suffix. const uint16_t default_bind_port = - static_cast(args.GetIntArg("-port", Params().GetDefaultPort())); + static_cast(args.GetIntArg("-port", chainman.GetParams().GetDefaultPort())); const auto BadPortWarning = [](const char* prefix, uint16_t port) { return strprintf(_("%s request to listen on port %u. This port is considered \"bad\" and " diff --git a/src/init.h b/src/init.h index a50747c84962..f1030756469e 100644 --- a/src/init.h +++ b/src/init.h @@ -20,6 +20,9 @@ class ArgsManager; namespace interfaces { struct BlockAndHeaderTipInfo; } // namespace interfaces +namespace kernel { +struct Context; +} namespace node { struct NodeContext; } // namespace node @@ -48,7 +51,7 @@ bool AppInitParameterInteraction(const ArgsManager& args); * @note This can be done before daemonization. Do not call Shutdown() if this function fails. * @pre Parameters should be parsed and config file should be read, AppInitParameterInteraction should have been called. */ -bool AppInitSanityChecks(); +bool AppInitSanityChecks(const kernel::Context& kernel); /** * Lock Dash Core data directory. * @note This should only be done after daemonization. Do not call Shutdown() if this function fails. diff --git a/src/init/common.cpp b/src/init/common.cpp index 21d8e337b127..32c87136d88b 100644 --- a/src/init/common.cpp +++ b/src/init/common.cpp @@ -8,13 +8,9 @@ #include #include -#include -#include #include -#include #include #include -#include #include #include #include @@ -26,37 +22,6 @@ #include namespace init { -void SetGlobals() -{ - SapphireAutoDetect(); - std::string sha256_algo = SHA256AutoDetect(); - LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo); - RandomInit(); - ECC_Start(); -} - -void UnsetGlobals() -{ - ECC_Stop(); -} - -bool SanityChecks() -{ - if (!ECC_InitSanityCheck()) { - return InitError(Untranslated("Elliptic curve cryptography sanity check failure. Aborting.")); - } - - if (!BLSInit()) { - return false; - } - - if (!Random_SanityCheck()) { - return InitError(Untranslated("OS cryptographic RNG sanity check failure. Aborting.")); - } - - return true; -} - void AddLoggingArgs(ArgsManager& argsman) { argsman.AddArg("-debuglogfile=", strprintf("Specify location of debug log file (default: %s). Relative paths will be prefixed by a net-specific datadir location. Pass -nodebuglogfile to disable writing the log to a file.", DEFAULT_DEBUGLOGFILE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); diff --git a/src/init/common.h b/src/init/common.h index bcd46f41d32b..53c860c29784 100644 --- a/src/init/common.h +++ b/src/init/common.h @@ -11,13 +11,6 @@ class ArgsManager; namespace init { -void SetGlobals(); -void UnsetGlobals(); -/** - * Ensure a usable environment with all - * necessary library support. - */ -bool SanityChecks(); void AddLoggingArgs(ArgsManager& args); void SetLoggingOptions(const ArgsManager& args); void SetLoggingCategories(const ArgsManager& args); diff --git a/src/kernel/bitcoinkernel.cpp b/src/kernel/bitcoinkernel.cpp new file mode 100644 index 000000000000..d31335751185 --- /dev/null +++ b/src/kernel/bitcoinkernel.cpp @@ -0,0 +1,45 @@ +// 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 +#include +#include + +// Define G_TRANSLATION_FUN symbol in libbitcoinkernel library so users of the +// library aren't required to export this symbol +extern const std::function G_TRANSLATION_FUN = nullptr; + +//---------------- +// symbols g_stats_client, ValueFromAmount, GetPrettyExceptionStr are re-defined +// here because adding relevant sources files will pull too many extra dependencies recursively +#include +#include +#include +std::unique_ptr g_stats_client{std::make_unique()}; + +UniValue ValueFromAmount(const CAmount amount) +{ + static_assert(COIN > 1); + int64_t quotient = amount / COIN; + int64_t remainder = amount % COIN; + if (amount < 0) { + quotient = -quotient; + remainder = -remainder; + } + return UniValue(UniValue::VNUM, + strprintf("%s%d.%08d", amount < 0 ? "-" : "", quotient, remainder)); +} +////////////////////// + +std::string GetPrettyExceptionStr(const std::exception_ptr& e) +{ + try { + // rethrow and catch the exception as there is no other way to reliably cast to the real type (not possible with RTTI) + std::rethrow_exception(e); + } catch (const std::exception& e2) { + return e2.what(); + } catch (...) { + throw; + } +} diff --git a/src/kernel/chainstatemanager_opts.h b/src/kernel/chainstatemanager_opts.h new file mode 100644 index 000000000000..510a1f9edcfa --- /dev/null +++ b/src/kernel/chainstatemanager_opts.h @@ -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. + +#ifndef BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H +#define BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H + +#include +#include + +class CChainParams; + +namespace kernel { + +/** + * An options struct for `ChainstateManager`, more ergonomically referred to as + * `ChainstateManager::Options` due to the using-declaration in + * `ChainstateManager`. + */ +struct ChainstateManagerOpts { + const CChainParams& chainparams; + const std::function adjusted_time_callback{nullptr}; +}; + +} // namespace kernel + +#endif // BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H diff --git a/src/kernel/checks.cpp b/src/kernel/checks.cpp new file mode 100644 index 000000000000..12f4424dffe6 --- /dev/null +++ b/src/kernel/checks.cpp @@ -0,0 +1,30 @@ +// 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 + +#include +#include +#include + +namespace kernel { + +std::optional SanityChecks(const Context&) +{ + if (!ECC_InitSanityCheck()) { + return SanityCheckError::ERROR_ECC; + } + + if (!BLSInit()) { + return SanityCheckError::ERROR_BLS; + } + + if (!Random_SanityCheck()) { + return SanityCheckError::ERROR_RANDOM; + } + + return std::nullopt; +} + +} diff --git a/src/kernel/checks.h b/src/kernel/checks.h new file mode 100644 index 000000000000..b604bec415cb --- /dev/null +++ b/src/kernel/checks.h @@ -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. + +#ifndef BITCOIN_KERNEL_CHECKS_H +#define BITCOIN_KERNEL_CHECKS_H + +#include + +namespace kernel { + +struct Context; + +enum class SanityCheckError { + ERROR_ECC, + ERROR_BLS, + ERROR_RANDOM, +}; + +/** + * Ensure a usable environment with all necessary library support. + */ +std::optional SanityChecks(const Context&); + +} + +#endif // BITCOIN_KERNEL_CHECKS_H diff --git a/src/kernel/context.cpp b/src/kernel/context.cpp new file mode 100644 index 000000000000..627cc1498ad4 --- /dev/null +++ b/src/kernel/context.cpp @@ -0,0 +1,35 @@ +// 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 + +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace kernel { + +Context::Context() +{ + SapphireAutoDetect(); + std::string sha256_algo = SHA256AutoDetect(); + LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo); + RandomInit(); + ECC_Start(); + BLSInit(); +} + +Context::~Context() +{ + ECC_Stop(); +} + +} // namespace kernel diff --git a/src/kernel/context.h b/src/kernel/context.h new file mode 100644 index 000000000000..f11b7b54f049 --- /dev/null +++ b/src/kernel/context.h @@ -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. + +#ifndef BITCOIN_KERNEL_CONTEXT_H +#define BITCOIN_KERNEL_CONTEXT_H + +#include + +namespace kernel { +//! Context struct holding the kernel library's logically global state, and +//! passed to external libbitcoin_kernel functions which need access to this +//! state. The kernel library API is a work in progress, so state organization +//! and member list will evolve over time. +//! +//! State stored directly in this struct should be simple. More complex state +//! should be stored to std::unique_ptr members pointing to opaque types. +struct Context { + //! Declare default constructor and destructor that are not inline, so code + //! instantiating the kernel::Context struct doesn't need to #include class + //! definitions for all the unique_ptr members. + Context(); + ~Context(); +}; +} // namespace kernel + +#endif // BITCOIN_KERNEL_CONTEXT_H diff --git a/src/kernel/mempool_limits.h b/src/kernel/mempool_limits.h new file mode 100644 index 000000000000..e192e7e6cdee --- /dev/null +++ b/src/kernel/mempool_limits.h @@ -0,0 +1,30 @@ +// 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_KERNEL_MEMPOOL_LIMITS_H +#define BITCOIN_KERNEL_MEMPOOL_LIMITS_H + +#include + +#include + +namespace kernel { +/** + * Options struct containing limit options for a CTxMemPool. Default constructor + * populates the struct with sane default values which can be modified. + * + * Most of the time, this struct should be referenced as CTxMemPool::Limits. + */ +struct MemPoolLimits { + //! The maximum allowed number of transactions in a package including the entry and its ancestors. + int64_t ancestor_count{DEFAULT_ANCESTOR_LIMIT}; + //! The maximum allowed size in virtual bytes of an entry and its ancestors within a package. + int64_t ancestor_size_vbytes{DEFAULT_ANCESTOR_SIZE_LIMIT_KVB * 1'000}; + //! The maximum allowed number of transactions in a package including the entry and its descendants. + 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}; +}; +} // namespace kernel + +#endif // BITCOIN_KERNEL_MEMPOOL_LIMITS_H diff --git a/src/kernel/mempool_options.h b/src/kernel/mempool_options.h new file mode 100644 index 000000000000..a14abb662890 --- /dev/null +++ b/src/kernel/mempool_options.h @@ -0,0 +1,38 @@ +// 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_KERNEL_MEMPOOL_OPTIONS_H +#define BITCOIN_KERNEL_MEMPOOL_OPTIONS_H + +#include + +#include +#include + +class CBlockPolicyEstimator; + +/** Default for -maxmempool, maximum megabytes of mempool memory usage */ +static constexpr unsigned int DEFAULT_MAX_MEMPOOL_SIZE_MB{300}; +/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */ +static constexpr unsigned int DEFAULT_MEMPOOL_EXPIRY_HOURS{336}; + +namespace kernel { +/** + * Options struct containing options for constructing a CTxMemPool. Default + * constructor populates the struct with sane default values which can be + * modified. + * + * Most of the time, this struct should be referenced as CTxMemPool::Options. + */ +struct MemPoolOptions { + /* Used to estimate appropriate transaction fees. */ + CBlockPolicyEstimator* estimator{nullptr}; + /* The ratio used to determine how often sanity checks will run. */ + int check_ratio{0}; + int64_t max_size_bytes{DEFAULT_MAX_MEMPOOL_SIZE_MB * 1'000'000}; + std::chrono::seconds expiry{std::chrono::hours{DEFAULT_MEMPOOL_EXPIRY_HOURS}}; + MemPoolLimits limits{}; +}; +} // namespace kernel + +#endif // BITCOIN_KERNEL_MEMPOOL_OPTIONS_H diff --git a/src/kernel/mempool_persist.cpp b/src/kernel/mempool_persist.cpp new file mode 100644 index 000000000000..07f494d8603a --- /dev/null +++ b/src/kernel/mempool_persist.cpp @@ -0,0 +1,199 @@ +// 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using fsbridge::FopenFn; + +namespace kernel { + +static const uint64_t MEMPOOL_DUMP_VERSION = 1; + +bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, CChainState& active_chainstate, FopenFn mockable_fopen_function) +{ + if (load_path.empty()) return false; + + FILE* filestr{mockable_fopen_function(load_path, "rb")}; + AutoFile file(filestr); + if (file.IsNull()) { + LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n"); + return false; + } + + int64_t count = 0; + int64_t expired = 0; + int64_t failed = 0; + int64_t already_there = 0; + int64_t unbroadcast = 0; + auto now = NodeClock::now(); + + try { + uint64_t version; + file >> version; + if (version != MEMPOOL_DUMP_VERSION) { + return false; + } + uint64_t total_txns_to_load; + file >> total_txns_to_load; + uint64_t txns_tried = 0; + LogInfo("Loading %u mempool transactions from disk...\n", total_txns_to_load); + int next_tenth_to_report = 0; + while (txns_tried < total_txns_to_load) { + const int percentage_done(100.0 * txns_tried / total_txns_to_load); + if (next_tenth_to_report < percentage_done / 10) { + LogInfo("Progress loading mempool transactions from disk: %d%% (tried %u, %u remaining)\n", + percentage_done, txns_tried, total_txns_to_load - txns_tried); + next_tenth_to_report = percentage_done / 10; + } + ++txns_tried; + + CTransactionRef tx; + int64_t nTime; + int64_t nFeeDelta; + file >> tx; + file >> nTime; + file >> nFeeDelta; + + CAmount amountdelta = nFeeDelta; + if (amountdelta) { + pool.PrioritiseTransaction(tx->GetHash(), amountdelta); + } + if (nTime > TicksSinceEpoch(now - pool.m_expiry)) { + LOCK(cs_main); + const auto& accepted = AcceptToMemoryPool(active_chainstate, tx, nTime, /*bypass_limits=*/false, /*test_accept=*/false); + if (accepted.m_result_type == MempoolAcceptResult::ResultType::VALID) { + ++count; + } else { + // mempool may contain the transaction already, e.g. from + // wallet(s) having loaded it while we were processing + // mempool transactions; consider these as valid, instead of + // failed, but mark them as 'already there' + if (pool.exists(tx->GetHash())) { + ++already_there; + } else { + ++failed; + } + } + } else { + ++expired; + } + if (ShutdownRequested()) + return false; + } + std::map mapDeltas; + file >> mapDeltas; + + for (const auto& i : mapDeltas) { + pool.PrioritiseTransaction(i.first, i.second); + } + + std::set unbroadcast_txids; + file >> unbroadcast_txids; + unbroadcast = unbroadcast_txids.size(); + for (const auto& txid : unbroadcast_txids) { + // Ensure transactions were accepted to mempool then add to + // unbroadcast set. + if (pool.get(txid) != nullptr) pool.AddUnbroadcastTx(txid); + } + } catch (const std::exception& e) { + LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what()); + return false; + } + + LogPrintf("Imported mempool transactions from disk: %i succeeded, %i failed, %i expired, %i already there, %i waiting for initial broadcast\n", count, failed, expired, already_there, unbroadcast); + return true; +} + +bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mockable_fopen_function, bool skip_file_commit) +{ + auto start = SteadyClock::now(); + + std::map mapDeltas; + std::vector vinfo; + std::set unbroadcast_txids; + + static Mutex dump_mutex; + LOCK(dump_mutex); + + { + LOCK(pool.cs); + for (const auto &i : pool.mapDeltas) { + mapDeltas[i.first] = i.second; + } + vinfo = pool.infoAll(); + unbroadcast_txids = pool.GetUnbroadcastTxs(); + } + + auto mid = SteadyClock::now(); + + try { + FILE* filestr{mockable_fopen_function(dump_path + ".new", "wb")}; + if (!filestr) { + return false; + } + + AutoFile file(filestr); + + uint64_t version = MEMPOOL_DUMP_VERSION; + file << version; + + file << (uint64_t)vinfo.size(); + for (const auto& i : vinfo) { + file << *(i.tx); + file << int64_t{count_seconds(i.m_time)}; + file << int64_t{i.nFeeDelta}; + mapDeltas.erase(i.tx->GetHash()); + } + + file << mapDeltas; + + LogPrintf("Writing %d unbroadcast transactions to disk.\n", unbroadcast_txids.size()); + file << unbroadcast_txids; + + if (!skip_file_commit && !FileCommit(file.Get())) + throw std::runtime_error("FileCommit failed"); + file.fclose(); + if (!RenameOver(dump_path + ".new", dump_path)) { + throw std::runtime_error("Rename failed"); + } + auto last = SteadyClock::now(); + + LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", + Ticks(mid - start), + Ticks(last - mid)); + } catch (const std::exception& e) { + LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what()); + return false; + } + return true; +} + +} // namespace kernel diff --git a/src/kernel/mempool_persist.h b/src/kernel/mempool_persist.h new file mode 100644 index 000000000000..9a15ec6dcafa --- /dev/null +++ b/src/kernel/mempool_persist.h @@ -0,0 +1,28 @@ +// 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_KERNEL_MEMPOOL_PERSIST_H +#define BITCOIN_KERNEL_MEMPOOL_PERSIST_H + +#include + +class CChainState; +class CTxMemPool; + +namespace kernel { + +/** Dump the mempool to disk. */ +bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, + fsbridge::FopenFn mockable_fopen_function = fsbridge::fopen, + bool skip_file_commit = false); + +/** Load the mempool from disk. */ +bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, + CChainState& active_chainstate, + fsbridge::FopenFn mockable_fopen_function = fsbridge::fopen); + +} // namespace kernel + + +#endif // BITCOIN_KERNEL_MEMPOOL_PERSIST_H diff --git a/src/mempool_args.cpp b/src/mempool_args.cpp new file mode 100644 index 000000000000..e26cbe02753b --- /dev/null +++ b/src/mempool_args.cpp @@ -0,0 +1,37 @@ +// 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 + +#include +#include + +#include + +using kernel::MemPoolLimits; +using kernel::MemPoolOptions; + +namespace { +void ApplyArgsManOptions(const ArgsManager& argsman, MemPoolLimits& mempool_limits) +{ + mempool_limits.ancestor_count = argsman.GetIntArg("-limitancestorcount", mempool_limits.ancestor_count); + + if (auto vkb = argsman.GetIntArg("-limitancestorsize")) mempool_limits.ancestor_size_vbytes = *vkb * 1'000; + + mempool_limits.descendant_count = argsman.GetIntArg("-limitdescendantcount", mempool_limits.descendant_count); + + if (auto vkb = argsman.GetIntArg("-limitdescendantsize")) mempool_limits.descendant_size_vbytes = *vkb * 1'000; +} +} + +void ApplyArgsManOptions(const ArgsManager& argsman, MemPoolOptions& mempool_opts) +{ + mempool_opts.check_ratio = argsman.GetIntArg("-checkmempool", mempool_opts.check_ratio); + + if (auto mb = argsman.GetIntArg("-maxmempool")) mempool_opts.max_size_bytes = *mb * 1'000'000; + + if (auto hours = argsman.GetIntArg("-mempoolexpiry")) mempool_opts.expiry = std::chrono::hours{*hours}; + + ApplyArgsManOptions(argsman, mempool_opts.limits); +} diff --git a/src/mempool_args.h b/src/mempool_args.h new file mode 100644 index 000000000000..9a4abe6618f6 --- /dev/null +++ b/src/mempool_args.h @@ -0,0 +1,22 @@ +// 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_MEMPOOL_ARGS_H +#define BITCOIN_MEMPOOL_ARGS_H + +class ArgsManager; +namespace kernel { +struct MemPoolOptions; +}; + +/** + * Overlay the options set in \p argsman on top of corresponding members in \p mempool_opts. + * + * @param[in] argsman The ArgsManager in which to check set options. + * @param[in,out] mempool_opts The MemPoolOptions to modify according to \p argsman. + */ +void ApplyArgsManOptions(const ArgsManager& argsman, kernel::MemPoolOptions& mempool_opts); + + +#endif // BITCOIN_MEMPOOL_ARGS_H diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 015408b9306a..0d2c0b895e53 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -583,7 +583,7 @@ struct CNodeState { class PeerManagerImpl final : public PeerManager { public: - PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman, BanMan* banman, + PeerManagerImpl(CConnman& connman, AddrMan& addrman, BanMan* banman, CDSTXManager& dstxman, ChainstateManager& chainman, CTxMemPool& pool, CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, CSporkManager& sporkman, const chainlock::Chainlocks& chainlocks, @@ -1512,8 +1512,6 @@ void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int co void PeerManagerImpl::PushNodeVersion(CNode& pnode, const Peer& peer) { - const auto& params = Params(); - uint64_t my_services{peer.m_our_services}; const int64_t nTime{count_seconds(GetTime())}; uint64_t nonce = pnode.GetLocalNonce(); @@ -1529,7 +1527,7 @@ void PeerManagerImpl::PushNodeVersion(CNode& pnode, const Peer& peer) pnode.SetSentMNAuthChallenge(mnauthChallenge); int nProtocolVersion = PROTOCOL_VERSION; - if (params.NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) { + if (m_chainparams.NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) { nProtocolVersion = gArgs.GetIntArg("-pushversion", PROTOCOL_VERSION); } @@ -2055,7 +2053,7 @@ std::optional PeerManagerImpl::FetchBlock(NodeId peer_id, const CBl return std::nullopt; } -std::unique_ptr PeerManager::make(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman, +std::unique_ptr PeerManager::make(CConnman& connman, AddrMan& addrman, BanMan* banman, CDSTXManager& dstxman, ChainstateManager& chainman, CTxMemPool& pool, CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, @@ -2067,10 +2065,10 @@ std::unique_ptr PeerManager::make(const CChainParams& chainparams, const std::unique_ptr& llmq_ctx, const std::unique_ptr& observer_ctx, bool ignore_incoming_txs) { - return std::make_unique(chainparams, connman, addrman, banman, dstxman, chainman, pool, mn_metaman, mn_sync, sporkman, chainlocks, clhandler, active_ctx, dmnman, cj_walletman, llmq_ctx, observer_ctx, ignore_incoming_txs); + return std::make_unique(connman, addrman, banman, dstxman, chainman, pool, mn_metaman, mn_sync, sporkman, chainlocks, clhandler, active_ctx, dmnman, cj_walletman, llmq_ctx, observer_ctx, ignore_incoming_txs); } -PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman, BanMan* banman, +PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman, BanMan* banman, CDSTXManager& dstxman, ChainstateManager& chainman, CTxMemPool& pool, CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, CSporkManager& sporkman, @@ -2081,7 +2079,7 @@ PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& conn const std::unique_ptr& cj_walletman, const std::unique_ptr& llmq_ctx, const std::unique_ptr& observer_ctx, bool ignore_incoming_txs) - : m_chainparams(chainparams), + : m_chainparams(chainman.GetParams()), m_connman(connman), m_addrman(addrman), m_banman(banman), @@ -3684,7 +3682,7 @@ MessageProcessingResult PeerManagerImpl::ProcessPlatformBanMessage(NodeId node, return ret; } - Consensus::LLMQType llmq_type = Params().GetConsensus().llmqTypePlatform; + Consensus::LLMQType llmq_type = m_chainparams.GetConsensus().llmqTypePlatform; auto quorum = m_llmq_ctx->qman->GetQuorum(llmq_type, ban_msg.m_quorum_hash); if (!quorum) { LogPrintf("PLATFORMBAN -- hash: %s protx_hash: %s missing quorum_hash: %s llmq_type: %d\n", hash.ToString(), ban_msg.m_protx_hash.ToString(), ban_msg.m_quorum_hash.ToString(), std23::to_underlying(llmq_type)); @@ -3828,7 +3826,7 @@ void PeerManagerImpl::ProcessMessage( PushNodeVersion(pfrom, *peer); } - if (Params().NetworkIDString() == CBaseChainParams::DEVNET) { + if (m_chainparams.NetworkIDString() == CBaseChainParams::DEVNET) { if (cleanSubVer.find(strprintf("devnet.%s", gArgs.GetDevNetName())) == std::string::npos) { LogPrintf("connected to wrong devnet. Reported version is %s, expected devnet name is %s\n", cleanSubVer, gArgs.GetDevNetName()); if (!pfrom.IsInboundConn()) diff --git a/src/net_processing.h b/src/net_processing.h index e5f5132925f6..3e9d4302e203 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -107,7 +107,7 @@ class NetHandler class PeerManager : public CValidationInterface, public NetEventsInterface, public PeerManagerInternal { public: - static std::unique_ptr make(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman, + static std::unique_ptr make(CConnman& connman, AddrMan& addrman, BanMan* banman, CDSTXManager& dstxman, ChainstateManager& chainman, CTxMemPool& pool, CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, CSporkManager& sporkman, diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index e113e79b86cf..ec7888668773 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -836,7 +836,7 @@ struct CImportingNow { } }; -void ThreadImport(ChainstateManager& chainman, std::vector vImportFiles, const ArgsManager& args) +void ThreadImport(ChainstateManager& chainman, std::vector vImportFiles, const ArgsManager& args, const fs::path& mempool_path) { ScheduleBatchPriority(); @@ -908,7 +908,6 @@ void ThreadImport(ChainstateManager& chainman, std::vector vImportFile return; } } // End scope of CImportingNow - - chainman.ActiveChainstate().LoadMempool(args); + chainman.ActiveChainstate().LoadMempool(mempool_path); } } // namespace node diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index f8bce3088813..c05a7fc70f03 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -227,7 +227,7 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex); -void ThreadImport(ChainstateManager& chainman, std::vector vImportFiles, const ArgsManager& args); +void ThreadImport(ChainstateManager& chainman, std::vector vImportFiles, const ArgsManager& args, const fs::path& mempool_path); } // namespace node #endif // BITCOIN_NODE_BLOCKSTORAGE_H diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index 75a474a439ff..9a741f291c3e 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -46,7 +46,6 @@ std::optional LoadChainstate(bool fReset, CTxMemPool* mempool, const fs::path& data_dir, bool fPruneMode, - const Consensus::Params& consensus_params, bool fReindexChainState, int64_t nBlockTreeDBCache, int64_t nCoinDBCache, @@ -82,7 +81,7 @@ std::optional LoadChainstate(bool fReset, DashChainstateSetup(chainman, mn_metaman, sporkman, chainlocks, mn_sync, chain_helper, dmnman, *evodb, llmq_ctx, mempool, data_dir, dash_dbs_in_memory, /*llmq_dbs_wipe=*/fReset || fReindexChainState, bls_threads, worker_count, - max_recsigs_age, consensus_params); + max_recsigs_age); if (fReset) { pblocktree->WriteReindexing(true); @@ -103,12 +102,12 @@ std::optional LoadChainstate(bool fReset, } if (!chainman.BlockIndex().empty() && - !chainman.m_blockman.LookupBlockIndex(consensus_params.hashGenesisBlock)) { + !chainman.m_blockman.LookupBlockIndex(chainman.GetConsensus().hashGenesisBlock)) { return ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK; } - if (!consensus_params.hashDevnetGenesisBlock.IsNull() && !chainman.BlockIndex().empty() && - !chainman.m_blockman.LookupBlockIndex(consensus_params.hashDevnetGenesisBlock)) { + if (!chainman.GetConsensus().hashDevnetGenesisBlock.IsNull() && !chainman.BlockIndex().empty() && + !chainman.m_blockman.LookupBlockIndex(chainman.GetConsensus().hashDevnetGenesisBlock)) { return ChainstateLoadingError::ERROR_BAD_DEVNET_GENESIS_BLOCK; } @@ -198,8 +197,7 @@ void DashChainstateSetup(ChainstateManager& chainman, bool llmq_dbs_wipe, int8_t bls_threads, int16_t worker_count, - int64_t max_recsigs_age, - const Consensus::Params& consensus_params) + int64_t max_recsigs_age) { // Same logic as pblocktree dmnman.reset(); @@ -214,7 +212,7 @@ void DashChainstateSetup(ChainstateManager& chainman, } chain_helper.reset(); chain_helper = std::make_unique(evodb, *dmnman, mn_sync, *(llmq_ctx->isman), *(llmq_ctx->quorum_block_processor), - *(llmq_ctx->qsnapman), chainman, consensus_params, chainlocks, + *(llmq_ctx->qsnapman), chainman, chainman.GetConsensus(), chainlocks, *(llmq_ctx->qman)); } @@ -236,10 +234,8 @@ std::optional VerifyLoadedChainstate(ChainstateManage CEvoDB& evodb, bool fReset, bool fReindexChainState, - const Consensus::Params& consensus_params, int check_blocks, int check_level, - std::function get_unix_time_seconds, std::function notify_bls_state) { auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { @@ -251,17 +247,17 @@ std::optional VerifyLoadedChainstate(ChainstateManage for (CChainState* chainstate : chainman.GetAll()) { if (!is_coinsview_empty(chainstate)) { const CBlockIndex* tip = chainstate->m_chain.Tip(); - if (tip && tip->nTime > get_unix_time_seconds() + MAX_FUTURE_BLOCK_TIME) { + if (tip && tip->nTime > GetTime() + MAX_FUTURE_BLOCK_TIME) { return ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE; } - const bool v19active{DeploymentActiveAfter(tip, consensus_params, Consensus::DEPLOYMENT_V19)}; + const bool v19active{DeploymentActiveAfter(tip, chainman, Consensus::DEPLOYMENT_V19)}; if (v19active) { bls::bls_legacy_scheme.store(false); if (notify_bls_state) notify_bls_state(bls::bls_legacy_scheme.load()); } if (!CVerifyDB().VerifyDB( - *chainstate, consensus_params, chainstate->CoinsDB(), + *chainstate, chainman.GetConsensus(), chainstate->CoinsDB(), evodb, check_level, check_blocks)) { diff --git a/src/node/chainstate.h b/src/node/chainstate.h index bbddf1f72ea5..2e3a830ea445 100644 --- a/src/node/chainstate.h +++ b/src/node/chainstate.h @@ -22,9 +22,6 @@ class CTxMemPool; struct LLMQContext; namespace chainlock { class Chainlocks; } -namespace Consensus { -struct Params; -} // namespace Consensus namespace fs { class path; } // namespace fs @@ -85,7 +82,6 @@ std::optional LoadChainstate(bool fReset, CTxMemPool* mempool, const fs::path& data_dir, bool fPruneMode, - const Consensus::Params& consensus_params, bool fReindexChainState, int64_t nBlockTreeDBCache, int64_t nCoinDBCache, @@ -115,8 +111,7 @@ void DashChainstateSetup(ChainstateManager& chainman, bool llmq_dbs_wipe, int8_t bls_threads, int16_t worker_count, - int64_t max_recsigs_age, - const Consensus::Params& consensus_params); + int64_t max_recsigs_age); void DashChainstateSetupClose(std::unique_ptr& chain_helper, std::unique_ptr& dmnman, @@ -134,10 +129,8 @@ std::optional VerifyLoadedChainstate(ChainstateManage CEvoDB& evodb, bool fReset, bool fReindexChainState, - const Consensus::Params& consensus_params, int check_blocks, int check_level, - std::function get_unix_time_seconds, std::function notify_bls_state = nullptr); } // namespace node diff --git a/src/node/context.cpp b/src/node/context.cpp index 776b74a9da19..2bd9531e97fd 100644 --- a/src/node/context.cpp +++ b/src/node/context.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/src/node/context.h b/src/node/context.h index 1d579276bd77..43f36be32eca 100644 --- a/src/node/context.h +++ b/src/node/context.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_NODE_CONTEXT_H #define BITCOIN_NODE_CONTEXT_H +#include + #include #include #include @@ -65,6 +67,8 @@ namespace node { //! any member functions. It should just be a collection of references that can //! be used without pulling in unwanted dependencies or functionality. struct NodeContext { + //! libbitcoin_kernel context + std::unique_ptr kernel; //! Init interface for initializing current process and connecting to other processes. interfaces::Init* init{nullptr}; std::unique_ptr addrman; diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index d9fe93f70e41..c25818ac2b17 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -289,19 +289,19 @@ class GOVImpl : public GOV GovernanceInfo getGovernanceInfo() override { GovernanceInfo info; - const Consensus::Params& consensusParams = Params().GetConsensus(); if (context().chainman) { + const Consensus::Params& consensusParams = context().chainman->GetConsensus(); LOCK(::cs_main); CSuperblock::GetNearestSuperblocksHeights(context().chainman->ActiveHeight(), info.lastsuperblock, info.nextsuperblock); info.governancebudget = CSuperblock::GetPaymentsLimit(context().chainman->ActiveChain(), info.nextsuperblock); if (context().dmnman) { info.fundingthreshold = static_cast(context().dmnman->GetListAtChainTip().GetCounts().m_valid_weighted / 10); } + info.superblockcycle = consensusParams.nSuperblockCycle; + info.superblockmaturitywindow = consensusParams.nSuperblockMaturityWindow; + info.targetSpacing = consensusParams.nPowTargetSpacing; } info.proposalfee = GOVERNANCE_PROPOSAL_FEE_TX; - info.superblockcycle = consensusParams.nSuperblockCycle; - info.superblockmaturitywindow = consensusParams.nSuperblockMaturityWindow; - info.targetSpacing = consensusParams.nPowTargetSpacing; info.relayRequiredConfs = GOVERNANCE_MIN_RELAY_FEE_CONFIRMATIONS; info.requiredConfs = GOVERNANCE_FEE_CONFIRMATIONS; return info; @@ -685,8 +685,16 @@ class NodeImpl : public Node uint64_t getLogCategories() override { return LogInstance().GetCategoryMask(); } bool baseInitialize() override { - return AppInitBasicSetup(gArgs) && AppInitParameterInteraction(gArgs) && AppInitSanityChecks() && - AppInitLockDataDirectory() && AppInitInterfaces(*m_context); + if (!AppInitBasicSetup(gArgs)) return false; + if (!AppInitParameterInteraction(gArgs)) return false; + + m_context->kernel = std::make_unique(); + if (!AppInitSanityChecks(*m_context->kernel)) return false; + + if (!AppInitLockDataDirectory()) return false; + if (!AppInitInterfaces(*m_context)) return false; + + return true; } bool appInitMain(interfaces::BlockAndHeaderTipInfo* tip_info) override { @@ -850,7 +858,7 @@ class NodeImpl : public Node int64_t getTotalBytesSent() override { return m_context->connman ? m_context->connman->GetTotalBytesSent() : 0; } size_t getMempoolSize() override { return m_context->mempool ? m_context->mempool->size() : 0; } size_t getMempoolDynamicUsage() override { return m_context->mempool ? m_context->mempool->DynamicMemoryUsage() : 0; } - size_t getMempoolMaxUsage() override { return gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; } + size_t getMempoolMaxUsage() override { return gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE_MB) * 1000000; } bool getHeaderTip(int& height, int64_t& block_time) override { LOCK(::cs_main); @@ -877,7 +885,7 @@ class NodeImpl : public Node uint256 getBestBlockHash() override { const CBlockIndex* tip = WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip()); - return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash(); + return tip ? tip->GetBlockHash() : chainman().GetParams().GenesisBlock().GetHash(); } int64_t getLastBlockTime() override { @@ -885,7 +893,7 @@ class NodeImpl : public Node if (chainman().ActiveChain().Tip()) { return chainman().ActiveChain().Tip()->GetBlockTime(); } - return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network + return chainman().GetParams().GenesisBlock().GetBlockTime(); // Genesis block's time of current network } std::string getLastBlockHash() override { @@ -893,7 +901,7 @@ class NodeImpl : public Node if (m_context->chainman->ActiveChain().Tip()) { return m_context->chainman->ActiveChain().Tip()->GetBlockHash().ToString(); } - return Params().GenesisBlock().GetHash().ToString(); // Genesis block's hash of current network + return chainman().GetParams().GenesisBlock().GetHash().ToString(); // Genesis block's hash of current network } double getVerificationProgress() override { @@ -902,7 +910,7 @@ class NodeImpl : public Node LOCK(::cs_main); tip = chainman().ActiveChain().Tip(); } - return GuessVerificationProgress(Params().TxData(), tip); + return GuessVerificationProgress(chainman().GetParams().TxData(), tip); } bool isInitialBlockDownload() override { return chainman().ActiveChainstate().IsInitialBlockDownload(); @@ -1318,7 +1326,7 @@ class ChainImpl : public Chain double guessVerificationProgress(const uint256& block_hash) override { LOCK(::cs_main); - return GuessVerificationProgress(Params().TxData(), chainman().m_blockman.LookupBlockIndex(block_hash)); + return GuessVerificationProgress(chainman().GetParams().TxData(), chainman().m_blockman.LookupBlockIndex(block_hash)); } bool hasBlocks(const uint256& block_hash, int min_height, std::optional max_height) override { @@ -1368,8 +1376,12 @@ class ChainImpl : public Chain } void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) override { - limit_ancestor_count = gArgs.GetIntArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); - limit_descendant_count = gArgs.GetIntArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); + const CTxMemPool::Limits default_limits{}; + + const CTxMemPool::Limits& limits{m_node.mempool ? m_node.mempool->m_limits : default_limits}; + + limit_ancestor_count = limits.ancestor_count; + limit_descendant_count = limits.descendant_count; } bool checkChainLimits(const CTransactionRef& tx) override { @@ -1377,15 +1389,12 @@ class ChainImpl : public Chain LockPoints lp; CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp); CTxMemPool::setEntries ancestors; - auto limit_ancestor_count = gArgs.GetIntArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); - auto limit_ancestor_size = gArgs.GetIntArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * 1000; - auto limit_descendant_count = gArgs.GetIntArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); - auto limit_descendant_size = gArgs.GetIntArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000; + const CTxMemPool::Limits& limits{m_node.mempool->m_limits}; std::string unused_error_string; LOCK(m_node.mempool->cs); return m_node.mempool->CalculateMemPoolAncestors( - entry, ancestors, limit_ancestor_count, limit_ancestor_size, - limit_descendant_count, limit_descendant_size, unused_error_string); + entry, ancestors, limits.ancestor_count, limits.ancestor_size_vbytes, + limits.descendant_count, limits.descendant_size_vbytes, unused_error_string); } CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override { @@ -1400,7 +1409,7 @@ class ChainImpl : public Chain CFeeRate mempoolMinFee() override { if (!m_node.mempool) return {}; - return m_node.mempool->GetMinFee(gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000); + return m_node.mempool->GetMinFee(); } CFeeRate relayMinFee() override { return ::minRelayTxFee; } CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; } diff --git a/src/node/mempool_persist_args.cpp b/src/node/mempool_persist_args.cpp new file mode 100644 index 000000000000..4e775869c647 --- /dev/null +++ b/src/node/mempool_persist_args.cpp @@ -0,0 +1,23 @@ +// 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 + +#include +#include +#include + +namespace node { + +bool ShouldPersistMempool(const ArgsManager& argsman) +{ + return argsman.GetBoolArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL); +} + +fs::path MempoolPath(const ArgsManager& argsman) +{ + return argsman.GetDataDirNet() / "mempool.dat"; +} + +} // namespace node diff --git a/src/node/mempool_persist_args.h b/src/node/mempool_persist_args.h new file mode 100644 index 000000000000..f719ec62ab24 --- /dev/null +++ b/src/node/mempool_persist_args.h @@ -0,0 +1,25 @@ +// 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_NODE_MEMPOOL_PERSIST_ARGS_H +#define BITCOIN_NODE_MEMPOOL_PERSIST_ARGS_H + +#include + +class ArgsManager; + +namespace node { + +/** + * Default for -persistmempool, indicating whether the node should attempt to + * automatically load the mempool on start and save to disk on shutdown + */ +static constexpr bool DEFAULT_PERSIST_MEMPOOL{true}; + +bool ShouldPersistMempool(const ArgsManager& argsman); +fs::path MempoolPath(const ArgsManager& argsman); + +} // namespace node + +#endif // BITCOIN_NODE_MEMPOOL_PERSIST_ARGS_H diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 6b267353cd5f..e475b501b8ad 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -69,7 +69,7 @@ BlockAssembler::Options::Options() nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE; } -BlockAssembler::BlockAssembler(CChainState& chainstate, const NodeContext& node, const CTxMemPool* mempool, const CChainParams& params, const Options& options) : +BlockAssembler::BlockAssembler(CChainState& chainstate, const NodeContext& node, const CTxMemPool* mempool, const Options& options) : m_blockman(chainstate.m_blockman), m_chain_helper(chainstate.ChainHelper()), m_chainstate(chainstate), @@ -77,7 +77,7 @@ BlockAssembler::BlockAssembler(CChainState& chainstate, const NodeContext& node, m_chainlocks(*Assert(node.chainlocks)), m_clhandler(*Assert(node.clhandler)), m_isman(*Assert(Assert(node.llmq_ctx)->isman)), - chainparams(params), + chainparams(chainstate.m_chainman.GetParams()), m_mempool(mempool), m_quorum_block_processor(*Assert(Assert(node.llmq_ctx)->quorum_block_processor)), m_qman(*Assert(Assert(node.llmq_ctx)->qman)) @@ -103,8 +103,8 @@ static BlockAssembler::Options DefaultOptions() return options; } -BlockAssembler::BlockAssembler(CChainState& chainstate, const NodeContext& node, const CTxMemPool* mempool, const CChainParams& params) - : BlockAssembler(chainstate, node, mempool, params, DefaultOptions()) {} +BlockAssembler::BlockAssembler(CChainState& chainstate, const NodeContext& node, const CTxMemPool* mempool) + : BlockAssembler(chainstate, node, mempool, DefaultOptions()) {} void BlockAssembler::resetBlock() { @@ -214,7 +214,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc pblock->nVersion = m_chainstate.m_chainman.m_versionbitscache.ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); // Non-mainnet only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios - if (Params().NetworkIDString() != CBaseChainParams::MAIN) { + if (chainparams.NetworkIDString() != CBaseChainParams::MAIN) { pblock->nVersion = gArgs.GetIntArg("-blockversion", pblock->nVersion); } @@ -259,7 +259,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn; // NOTE: unlike in bitcoin, we need to pass PREVIOUS block height here - CAmount blockSubsidy = GetBlockSubsidyInner(pindexPrev->nBits, pindexPrev->nHeight, Params().GetConsensus(), fV20Active_context); + CAmount blockSubsidy = GetBlockSubsidyInner(pindexPrev->nBits, pindexPrev->nHeight, chainparams.GetConsensus(), fV20Active_context); CAmount blockReward = blockSubsidy + nFees; // Compute regular coinbase transaction. @@ -333,7 +333,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]); BlockValidationState state; - if (!TestBlockValidity(state, m_chainlocks, m_evoDb, chainparams, m_chainstate, *pblock, pindexPrev, false, false)) { + if (!TestBlockValidity(state, m_chainlocks, m_evoDb, chainparams, m_chainstate, *pblock, pindexPrev, GetAdjustedTime, false, false)) { throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString())); } int64_t nTime2 = GetTimeMicros(); diff --git a/src/node/miner.h b/src/node/miner.h index f16bb8ef5d94..18d9520d0061 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -187,9 +187,8 @@ class BlockAssembler CFeeRate blockMinFeeRate; }; - explicit BlockAssembler(CChainState& chainstate, const node::NodeContext& node, const CTxMemPool* mempool, const CChainParams& params); - explicit BlockAssembler(CChainState& chainstate, const node::NodeContext& node, const CTxMemPool* mempool, const CChainParams& params, - const Options& options); + explicit BlockAssembler(CChainState& chainstate, const node::NodeContext& node, const CTxMemPool* mempool); + explicit BlockAssembler(CChainState& chainstate, const node::NodeContext& node, const CTxMemPool* mempool, const Options& options); /** Construct a new block template with coinbase to scriptPubKeyIn */ std::unique_ptr CreateNewBlock(const CScript& scriptPubKeyIn); diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 03b629e7b9e6..7db5b932df9c 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -31,8 +31,6 @@ #include #include -static const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat"; - static constexpr double INF_FEERATE = 1e99; std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon) @@ -542,7 +540,8 @@ bool CBlockPolicyEstimator::_removeTx(const uint256& hash, bool inBlock) } } -CBlockPolicyEstimator::CBlockPolicyEstimator() +CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath) + : m_estimation_filepath{estimation_filepath} { static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero"); size_t bucketIndex = 0; @@ -560,10 +559,9 @@ CBlockPolicyEstimator::CBlockPolicyEstimator() longStats = std::make_unique(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE); // If the fee estimation file is present, read recorded estimations - fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME; - AutoFile est_file{fsbridge::fopen(est_filepath, "rb")}; + AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "rb")}; if (est_file.IsNull() || !Read(est_file)) { - LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(est_filepath)); + LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath)); } } @@ -918,10 +916,9 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation void CBlockPolicyEstimator::Flush() { FlushUnconfirmed(); - fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME; - AutoFile est_file{fsbridge::fopen(est_filepath, "wb")}; + AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "wb")}; if (est_file.IsNull() || !Write(est_file)) { - LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", fs::PathToString(est_filepath)); + LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath)); } } diff --git a/src/policy/fees.h b/src/policy/fees.h index 45bc40ab75c0..d851fce8d746 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -6,6 +6,7 @@ #define BITCOIN_POLICY_FEES_H #include +#include #include #include #include @@ -179,9 +180,10 @@ class CBlockPolicyEstimator */ static constexpr double FEE_SPACING = 1.05; + const fs::path m_estimation_filepath; public: /** Create new BlockPolicyEstimator and initialize stats tracking classes with default values */ - CBlockPolicyEstimator(); + CBlockPolicyEstimator(const fs::path& estimation_filepath); ~CBlockPolicyEstimator(); /** Process all the transactions that have been included in a block */ diff --git a/src/policy/fees_args.cpp b/src/policy/fees_args.cpp new file mode 100644 index 000000000000..a3531153b5b4 --- /dev/null +++ b/src/policy/fees_args.cpp @@ -0,0 +1,12 @@ +#include + +#include + +namespace { +const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat"; +} // namespace + +fs::path FeeestPath(const ArgsManager& argsman) +{ + return argsman.GetDataDirNet() / FEE_ESTIMATES_FILENAME; +} diff --git a/src/policy/fees_args.h b/src/policy/fees_args.h new file mode 100644 index 000000000000..6b65ce0aa9f6 --- /dev/null +++ b/src/policy/fees_args.h @@ -0,0 +1,15 @@ +// 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_POLICY_FEES_ARGS_H +#define BITCOIN_POLICY_FEES_ARGS_H + +#include + +class ArgsManager; + +/** @return The fee estimates data file path. */ +fs::path FeeestPath(const ArgsManager& argsman); + +#endif // BITCOIN_POLICY_FEES_ARGS_H diff --git a/src/policy/packages.h b/src/policy/packages.h index 997056a61471..51f48d499418 100644 --- a/src/policy/packages.h +++ b/src/policy/packages.h @@ -24,8 +24,8 @@ static_assert(MAX_PACKAGE_SIZE * 1000 >= MAX_STANDARD_TX_SIZE); // defaults reflect this constraint. static_assert(DEFAULT_DESCENDANT_LIMIT >= MAX_PACKAGE_COUNT); static_assert(DEFAULT_ANCESTOR_LIMIT >= MAX_PACKAGE_COUNT); -static_assert(DEFAULT_ANCESTOR_SIZE_LIMIT >= MAX_PACKAGE_SIZE); -static_assert(DEFAULT_DESCENDANT_SIZE_LIMIT >= MAX_PACKAGE_SIZE); +static_assert(DEFAULT_ANCESTOR_SIZE_LIMIT_KVB >= MAX_PACKAGE_SIZE); +static_assert(DEFAULT_DESCENDANT_SIZE_LIMIT_KVB >= MAX_PACKAGE_SIZE); /** A "reason" why a package was invalid. It may be that one or more of the included * transactions is invalid or the package itself violates our rules. diff --git a/src/policy/policy.h b/src/policy/policy.h index 838f35306498..0a3853900463 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -31,8 +31,6 @@ static constexpr unsigned int MIN_STANDARD_TX_SIZE{83}; static constexpr unsigned int MAX_P2SH_SIGOPS{15}; /** The maximum number of sigops we're willing to relay/mine in a single tx */ static constexpr unsigned int MAX_STANDARD_TX_SIGOPS{4000}; -/** Default for -maxmempool, maximum megabytes of mempool memory usage */ -static constexpr unsigned int DEFAULT_MAX_MEMPOOL_SIZE{300}; /** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting **/ static constexpr unsigned int DEFAULT_INCREMENTAL_RELAY_FEE{1000}; /** Default for -bytespersigop */ @@ -52,11 +50,11 @@ static constexpr unsigned int DEFAULT_MIN_RELAY_TX_FEE{1000}; /** Default for -limitancestorcount, max number of in-mempool ancestors */ static constexpr unsigned int DEFAULT_ANCESTOR_LIMIT{25}; /** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */ -static constexpr unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT{101}; +static constexpr unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT_KVB{101}; /** Default for -limitdescendantcount, max number of in-mempool descendants */ static constexpr unsigned int DEFAULT_DESCENDANT_LIMIT{25}; /** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */ -static constexpr unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT{101}; +static constexpr unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT_KVB{101}; /** * An extra transaction can be added to a package, as long as it only has one * ancestor and is no larger than this. Not really any reason to make this diff --git a/src/rest.cpp b/src/rest.cpp index 70c61e40fe25..87f5671cf000 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -333,7 +333,7 @@ static bool rest_block(const CoreContext& context, return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)"); } - if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) { + if (!ReadBlockFromDisk(block, pblockindex, chainman.GetParams().GetConsensus())) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index eca003933174..97f28f5bd8a6 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1090,11 +1090,11 @@ static RPCHelpMan pruneblockchain() unsigned int height = (unsigned int) heightParam; unsigned int chainHeight = (unsigned int) active_chain.Height(); - if (chainHeight < Params().PruneAfterHeight()) + if (chainHeight < chainman.GetParams().PruneAfterHeight()) { throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning."); - else if (height > chainHeight) + } else if (height > chainHeight) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height."); - else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) { + } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) { LogPrint(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.\n"); height = chainHeight - MIN_BLOCKS_TO_KEEP; } @@ -1409,7 +1409,7 @@ static RPCHelpMan verifychain() CChainState& active_chainstate = chainman.ActiveChainstate(); return CVerifyDB().VerifyDB( - active_chainstate, Params().GetConsensus(), active_chainstate.CoinsTip(), *CHECK_NONFATAL(node.evodb), check_level, check_depth); + active_chainstate, chainman.GetParams().GetConsensus(), active_chainstate.CoinsTip(), *CHECK_NONFATAL(node.evodb), check_level, check_depth); }, }; } @@ -1563,7 +1563,7 @@ RPCHelpMan getblockchaininfo() if (args.IsArgSet("-devnet")) { obj.pushKV("chain", args.GetDevNetName()); } else { - obj.pushKV("chain", Params().NetworkIDString()); + obj.pushKV("chain", chainman.GetParams().NetworkIDString()); } obj.pushKV("blocks", height); obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1); @@ -1571,7 +1571,7 @@ RPCHelpMan getblockchaininfo() obj.pushKV("difficulty", GetDifficulty(&tip)); obj.pushKV("time", tip.GetBlockTime()); obj.pushKV("mediantime", tip.GetMedianTimePast()); - obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), &tip)); + obj.pushKV("verificationprogress", GuessVerificationProgress(chainman.GetParams().TxData(), &tip)); obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload()); obj.pushKV("chainwork", tip.nChainWork.GetHex()); obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage()); @@ -1912,7 +1912,7 @@ static RPCHelpMan getchaintxstats() CChain& active_chain = chainman.ActiveChain(); const CBlockIndex* pindex; - int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month + int blockcount = 30 * 24 * 60 * 60 / chainman.GetParams().GetConsensus().nPowTargetSpacing; // By default: 1 month if (request.params[1].isNull()) { LOCK(cs_main); @@ -2232,7 +2232,7 @@ static RPCHelpMan getblockstats() ret_all.pushKV("minfeerate", (minfeerate == MAX_MONEY) ? 0 : minfeerate); ret_all.pushKV("mintxsize", mintxsize == MaxBlockSize() ? 0 : mintxsize); ret_all.pushKV("outs", outputs); - ret_all.pushKV("subsidy", GetBlockSubsidy(&pindex, Params().GetConsensus())); + ret_all.pushKV("subsidy", GetBlockSubsidy(&pindex, chainman.GetParams().GetConsensus())); ret_all.pushKV("time", pindex.GetBlockTime()); ret_all.pushKV("total_out", total_out); ret_all.pushKV("total_size", total_size); diff --git a/src/rpc/fees.cpp b/src/rpc/fees.cpp index 0835759b3e75..47a30a3beedb 100644 --- a/src/rpc/fees.cpp +++ b/src/rpc/fees.cpp @@ -86,7 +86,7 @@ static RPCHelpMan estimatesmartfee() FeeCalculation feeCalc; CFeeRate feeRate{fee_estimator.estimateSmartFee(conf_target, &feeCalc, conservative)}; if (feeRate != CFeeRate(0)) { - CFeeRate min_mempool_feerate{mempool.GetMinFee(gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000)}; + CFeeRate min_mempool_feerate{mempool.GetMinFee()}; CFeeRate min_relay_feerate{::minRelayTxFee}; feeRate = std::max({feeRate, min_mempool_feerate, min_relay_feerate}); result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK())); diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index 8315c6a96db3..46215c339063 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -5,13 +5,14 @@ #include -#include -#include -#include +#include #include #include #include +#include +#include +#include #include #include #include @@ -19,13 +20,17 @@ #include #include #include +#include #include -#include -#include #include +#include #include +#include + +using kernel::DumpMempool; using node::DEFAULT_MAX_RAW_TX_FEE_RATE; +using node::MempoolPath; using node::NodeContext; RPCHelpMan sendrawtransaction() @@ -686,14 +691,13 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool, const llmq::CInstantSendManag // Make sure this call is atomic in the pool. LOCK(pool.cs); UniValue ret(UniValue::VOBJ); - ret.pushKV("loaded", pool.IsLoaded()); + ret.pushKV("loaded", pool.GetLoadTried()); ret.pushKV("size", (int64_t)pool.size()); ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize()); ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage()); ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee())); - int64_t maxmempool{gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000}; - ret.pushKV("maxmempool", maxmempool); - ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK())); + ret.pushKV("maxmempool", pool.m_max_size_bytes); + ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), ::minRelayTxFee).GetFeePerK())); ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())); ret.pushKV("instantsendlocks", isman.GetInstantSendLockCount()); ret.pushKV("unbroadcastcount", pool.GetUnbroadcastTxs().size()); @@ -752,16 +756,18 @@ static RPCHelpMan savemempool() const ArgsManager& args{EnsureAnyArgsman(request.context)}; const CTxMemPool& mempool = EnsureAnyMemPool(request.context); - if (!mempool.IsLoaded()) { + if (!mempool.GetLoadTried()) { throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet"); } - if (!DumpMempool(mempool)) { + const fs::path& dump_path = MempoolPath(args); + + if (!DumpMempool(mempool, dump_path)) { throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk"); } UniValue ret(UniValue::VOBJ); - ret.pushKV("filename", fs::path((args.GetDataDirNet() / "mempool.dat")).utf8string()); + ret.pushKV("filename", dump_path.utf8string()); return ret; }, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 24b63fe83eec..f419d141ba87 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -33,6 +33,7 @@ #include