mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-01 16:53:52 +02:00
Merge bitcoin/bitcoin#25487: [kernel 3b/n] Decouple {Dump,Load}Mempool from ArgsManager
cb3e9a1e3fMove {Load,Dump}Mempool to kernel namespace (Carl Dong)aa30676541Move DEFAULT_PERSIST_MEMPOOL out of libbitcoinkernel (Carl Dong)06b88ffb8aLoadMempool: Pass in load_path, stop using gArgs (Carl Dong)b857ac60d9test/fuzz: Invoke LoadMempool via CChainState (Carl Dong)b3267258b0Move FopenFn to fsbridge namespace (Carl Dong)ae1e8e3756mempool: Use NodeClock+friends for LoadMempool (Carl Dong)f9e8e5719fmempool: Improve comments for [GS]etLoadTried (Carl Dong)813962da0bscripted-diff: Rename m_is_loaded -> m_load_tried (Carl Dong)413f4bb52bDumpMempool: Pass in dump_path, stop using gArgs (Carl Dong)bd4407817eDumpMempool: Use std::chrono instead of weird int64_t arthmetics (Carl Dong)c84390b741test/mempool_persist: Test manual savemempool when -persistmempool=0 (Carl Dong) Pull request description: This is part of the `libbitcoinkernel` project: #24303, https://github.com/bitcoin/bitcoin/projects/18 ----- This PR moves `{Dump,Load}Mempool` into its own `kernel/mempool_persist` module and introduces `ArgsManager` `node::` helpers in `node/mempool_persist_args`to remove the scattered calls to `GetBoolArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)`. More context can be gleaned from the commit messages. ----- One thing I was reflecting on as I wrote this was that in the long run, I think we should probably invert the validation <-> mempool relationship. Instead of mempool not depending on validation, it might make more sense to have validation not depend on mempool. Not super urgent since `libbitcoinkernel` will include both validation and mempool, but perhaps something for the future. ACKs for top commit: glozow: re ACKcb3e9a1e3fvia `git range-diff 7ae032e...cb3e9a1` MarcoFalke: ACKcb3e9a1e3f🔒 ryanofsky: Code review ACKcb3e9a1e3fTree-SHA512: 979d7237c3abb5a1dd9b5ad3dbf3b954f906a6d8320ed7b923557f41a4472deccae3e8a6bca0018c8e7a3c4a93afecc502acd1e26756f2054f157f1c0edd939d
This commit is contained in:
189
src/kernel/mempool_persist.cpp
Normal file
189
src/kernel/mempool_persist.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
// 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 <kernel/mempool_persist.h>
|
||||
|
||||
#include <clientversion.h>
|
||||
#include <consensus/amount.h>
|
||||
#include <fs.h>
|
||||
#include <logging.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <serialize.h>
|
||||
#include <shutdown.h>
|
||||
#include <streams.h>
|
||||
#include <sync.h>
|
||||
#include <txmempool.h>
|
||||
#include <uint256.h>
|
||||
#include <util/system.h>
|
||||
#include <util/time.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
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")};
|
||||
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
|
||||
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 num;
|
||||
file >> num;
|
||||
while (num) {
|
||||
--num;
|
||||
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<std::chrono::seconds>(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(GenTxid::Txid(tx->GetHash()))) {
|
||||
++already_there;
|
||||
} else {
|
||||
++failed;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
++expired;
|
||||
}
|
||||
if (ShutdownRequested())
|
||||
return false;
|
||||
}
|
||||
std::map<uint256, CAmount> mapDeltas;
|
||||
file >> mapDeltas;
|
||||
|
||||
for (const auto& i : mapDeltas) {
|
||||
pool.PrioritiseTransaction(i.first, i.second);
|
||||
}
|
||||
|
||||
std::set<uint256> 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<uint256, CAmount> mapDeltas;
|
||||
std::vector<TxMempoolInfo> vinfo;
|
||||
std::set<uint256> 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;
|
||||
}
|
||||
|
||||
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
|
||||
|
||||
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<SecondsDouble>(mid - start),
|
||||
Ticks<SecondsDouble>(last - mid));
|
||||
} catch (const std::exception& e) {
|
||||
LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace kernel
|
||||
28
src/kernel/mempool_persist.h
Normal file
28
src/kernel/mempool_persist.h
Normal file
@@ -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 <fs.h>
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user