diff options
author | MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> | 2023-08-03 11:48:34 +0200 |
---|---|---|
committer | MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> | 2023-11-09 19:44:50 +0100 |
commit | fa6b053b5c964fb35935fa994cb782c0731a56f8 (patch) | |
tree | c9ba4d5a3b2771f596bb838d55c0e8e78699b454 | |
parent | b3898e946cf81e2e7b573e1c5204bd29af2feecd (diff) |
mempool: persist with XOR
-rw-r--r-- | doc/release-notes-28207.md | 7 | ||||
-rw-r--r-- | src/init.cpp | 5 | ||||
-rw-r--r-- | src/kernel/mempool_options.h | 3 | ||||
-rw-r--r-- | src/kernel/mempool_persist.cpp | 36 | ||||
-rw-r--r-- | src/node/mempool_args.cpp | 2 | ||||
-rw-r--r-- | src/streams.h | 5 | ||||
-rw-r--r-- | src/txmempool.cpp | 1 | ||||
-rw-r--r-- | src/txmempool.h | 1 | ||||
-rwxr-xr-x | test/functional/mempool_compatibility.py | 4 |
9 files changed, 49 insertions, 15 deletions
diff --git a/doc/release-notes-28207.md b/doc/release-notes-28207.md new file mode 100644 index 0000000000..56b88da16a --- /dev/null +++ b/doc/release-notes-28207.md @@ -0,0 +1,7 @@ +mempool.dat compatibility +======================== + +The `mempool.dat` file created by -persistmempool or the savemempool RPC will +be written in a new format, which can not be read by previous software +releases. To allow for a downgrade, a temporary setting `-persistmempoolv1` has +been added to fall back to the legacy format. diff --git a/src/init.cpp b/src/init.cpp index 62e7e32272..52ebd4a626 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -458,6 +458,11 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-par=<n>", 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); argsman.AddArg("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", DEFAULT_PERSIST_MEMPOOL), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-persistmempoolv1", + strprintf("Whether a mempool.dat file created by -persistmempool or the savemempool RPC will be written in the legacy format " + "(version 1) or the current format (version 2). This temporary option will be removed in the future. (default: %u)", + DEFAULT_PERSIST_V1_DAT), + ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-pid=<file>", strprintf("Specify pid file. Relative paths will be prefixed by a net-specific datadir location. (default: %s)", BITCOIN_PID_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-prune=<n>", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex. " "Warning: Reverting this setting requires re-downloading the entire blockchain. " diff --git a/src/kernel/mempool_options.h b/src/kernel/mempool_options.h index 757be41b3c..d09fd2ba35 100644 --- a/src/kernel/mempool_options.h +++ b/src/kernel/mempool_options.h @@ -23,6 +23,8 @@ static constexpr unsigned int DEFAULT_BLOCKSONLY_MAX_MEMPOOL_SIZE_MB{5}; static constexpr unsigned int DEFAULT_MEMPOOL_EXPIRY_HOURS{336}; /** Default for -mempoolfullrbf, if the transaction replaceability signaling is ignored */ static constexpr bool DEFAULT_MEMPOOL_FULL_RBF{false}; +/** Whether to fall back to legacy V1 serialization when writing mempool.dat */ +static constexpr bool DEFAULT_PERSIST_V1_DAT{false}; /** Default for -acceptnonstdtxn */ static constexpr bool DEFAULT_ACCEPT_NON_STD_TXN{false}; @@ -56,6 +58,7 @@ struct MemPoolOptions { bool permit_bare_multisig{DEFAULT_PERMIT_BAREMULTISIG}; bool require_standard{true}; bool full_rbf{DEFAULT_MEMPOOL_FULL_RBF}; + bool persist_v1_dat{DEFAULT_PERSIST_V1_DAT}; MemPoolLimits limits{}; }; } // namespace kernel diff --git a/src/kernel/mempool_persist.cpp b/src/kernel/mempool_persist.cpp index ff655c5ffa..4087308d1a 100644 --- a/src/kernel/mempool_persist.cpp +++ b/src/kernel/mempool_persist.cpp @@ -8,6 +8,7 @@ #include <consensus/amount.h> #include <logging.h> #include <primitives/transaction.h> +#include <random.h> #include <serialize.h> #include <streams.h> #include <sync.h> @@ -34,14 +35,14 @@ using fsbridge::FopenFn; namespace kernel { -static const uint64_t MEMPOOL_DUMP_VERSION = 1; +static const uint64_t MEMPOOL_DUMP_VERSION_NO_XOR_KEY{1}; +static const uint64_t MEMPOOL_DUMP_VERSION{2}; bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active_chainstate, ImportMempoolOptions&& opts) { if (load_path.empty()) return false; - FILE* filestr{opts.mockable_fopen_function(load_path, "rb")}; - CAutoFile file{filestr, CLIENT_VERSION}; + CAutoFile file{opts.mockable_fopen_function(load_path, "rb"), CLIENT_VERSION}; if (file.IsNull()) { LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n"); return false; @@ -57,9 +58,15 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active try { uint64_t version; file >> version; - if (version != MEMPOOL_DUMP_VERSION) { + std::vector<std::byte> xor_key; + if (version == MEMPOOL_DUMP_VERSION_NO_XOR_KEY) { + // Leave XOR-key empty + } else if (version == MEMPOOL_DUMP_VERSION) { + file >> xor_key; + } else { return false; } + file.SetXor(xor_key); uint64_t num; file >> num; while (num) { @@ -151,17 +158,22 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mock auto mid = SteadyClock::now(); - try { - FILE* filestr{mockable_fopen_function(dump_path + ".new", "wb")}; - if (!filestr) { - return false; - } - - CAutoFile file{filestr, CLIENT_VERSION}; + CAutoFile file{mockable_fopen_function(dump_path + ".new", "wb"), CLIENT_VERSION}; + if (file.IsNull()) { + return false; + } - uint64_t version = MEMPOOL_DUMP_VERSION; + try { + const uint64_t version{pool.m_persist_v1_dat ? MEMPOOL_DUMP_VERSION_NO_XOR_KEY : MEMPOOL_DUMP_VERSION}; file << version; + std::vector<std::byte> xor_key(8); + if (!pool.m_persist_v1_dat) { + FastRandomContext{}.fillrand(xor_key); + file << xor_key; + } + file.SetXor(xor_key); + file << (uint64_t)vinfo.size(); for (const auto& i : vinfo) { file << *(i.tx); diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp index f63d9875fc..ac26600919 100644 --- a/src/node/mempool_args.cpp +++ b/src/node/mempool_args.cpp @@ -93,6 +93,8 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& argsman, const CChainP mempool_opts.full_rbf = argsman.GetBoolArg("-mempoolfullrbf", mempool_opts.full_rbf); + mempool_opts.persist_v1_dat = argsman.GetBoolArg("-persistmempoolv1", mempool_opts.persist_v1_dat); + ApplyArgsManOptions(argsman, mempool_opts.limits); return {}; diff --git a/src/streams.h b/src/streams.h index d58de5233b..fe5df72abe 100644 --- a/src/streams.h +++ b/src/streams.h @@ -471,7 +471,7 @@ class AutoFile { protected: std::FILE* m_file; - const std::vector<std::byte> m_xor; + std::vector<std::byte> m_xor; public: explicit AutoFile(std::FILE* file, std::vector<std::byte> data_xor={}) : m_file{file}, m_xor{std::move(data_xor)} {} @@ -511,6 +511,9 @@ public: */ bool IsNull() const { return m_file == nullptr; } + /** Continue with a different XOR key */ + void SetXor(std::vector<std::byte> data_xor) { m_xor = data_xor; } + /** Implementation detail, only used internally. */ std::size_t detail_fread(Span<std::byte> dst); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 461662ad93..90a3a040d0 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -412,6 +412,7 @@ CTxMemPool::CTxMemPool(const Options& opts) m_max_datacarrier_bytes{opts.max_datacarrier_bytes}, m_require_standard{opts.require_standard}, m_full_rbf{opts.full_rbf}, + m_persist_v1_dat{opts.persist_v1_dat}, m_limits{opts.limits} { } diff --git a/src/txmempool.h b/src/txmempool.h index cbeabb31fa..a86b5a37e0 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -446,6 +446,7 @@ public: const std::optional<unsigned> m_max_datacarrier_bytes; const bool m_require_standard; const bool m_full_rbf; + const bool m_persist_v1_dat; const Limits m_limits; diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py index fd3e219586..a126f164aa 100755 --- a/test/functional/mempool_compatibility.py +++ b/test/functional/mempool_compatibility.py @@ -28,7 +28,7 @@ class MempoolCompatibilityTest(BitcoinTestFramework): def setup_network(self): self.add_nodes(self.num_nodes, versions=[ - 200100, # Last release with previous mempool format + 200100, # Last release without unbroadcast serialization and without XOR None, ]) self.start_nodes() @@ -59,7 +59,7 @@ class MempoolCompatibilityTest(BitcoinTestFramework): old_node_mempool.rename(new_node_mempool) self.log.info("Start new node and verify mempool contains the tx") - self.start_node(1) + self.start_node(1, extra_args=["-persistmempoolv1=1"]) assert old_tx_hash in new_node.getrawmempool() self.log.info("Add unbroadcasted tx to mempool on new node and shutdown") |