Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2022-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <node/mempool_persist.h>7#include <clientversion.h>8#include <consensus/amount.h>9#include <primitives/transaction.h>10#include <random.h>11#include <serialize.h>12#include <streams.h>13#include <sync.h>14#include <txmempool.h>15#include <uint256.h>16#include <util/fs.h>17#include <util/fs_helpers.h>18#include <util/log.h>19#include <util/obfuscation.h>20#include <util/signalinterrupt.h>21#include <util/syserror.h>22#include <util/time.h>23#include <validation.h>25#include <cstdint>26#include <cstdio>27#include <exception>28#include <functional>29#include <map>30#include <memory>31#include <set>32#include <stdexcept>33#include <utility>34#include <vector>36using fsbridge::FopenFn;38namespace node {40static const uint64_t MEMPOOL_DUMP_VERSION_NO_XOR_KEY{1};41static const uint64_t MEMPOOL_DUMP_VERSION{2};43bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active_chainstate, ImportMempoolOptions&& opts)44{45if (load_path.empty()) return false;47AutoFile file{opts.mockable_fopen_function(load_path, "rb")};48if (file.IsNull()) {49LogInfo("Failed to open mempool file. Continuing anyway.\n");50return false;51}53int64_t count = 0;54int64_t expired = 0;55int64_t failed = 0;56int64_t already_there = 0;57int64_t unbroadcast = 0;58const auto now{NodeClock::now()};60try {61uint64_t version;62file >> version;64if (version == MEMPOOL_DUMP_VERSION_NO_XOR_KEY) {65file.SetObfuscation({});66} else if (version == MEMPOOL_DUMP_VERSION) {67Obfuscation obfuscation;68file >> obfuscation;69file.SetObfuscation(obfuscation);70} else {71return false;72}74uint64_t total_txns_to_load;75file >> total_txns_to_load;76uint64_t txns_tried = 0;77LogInfo("Loading %u mempool transactions from file...\n", total_txns_to_load);78int next_tenth_to_report = 0;79while (txns_tried < total_txns_to_load) {80const int percentage_done(100.0 * txns_tried / total_txns_to_load);81if (next_tenth_to_report < percentage_done / 10) {82LogInfo("Progress loading mempool transactions from file: %d%% (tried %u, %u remaining)\n",83percentage_done, txns_tried, total_txns_to_load - txns_tried);84next_tenth_to_report = percentage_done / 10;85}86++txns_tried;88CTransactionRef tx;89int64_t nTime;90int64_t nFeeDelta;91file >> TX_WITH_WITNESS(tx);92file >> nTime;93file >> nFeeDelta;95if (opts.use_current_time) {96nTime = TicksSinceEpoch<std::chrono::seconds>(now);97}99CAmount amountdelta = nFeeDelta;100if (amountdelta && opts.apply_fee_delta_priority) {101pool.PrioritiseTransaction(tx->GetHash(), amountdelta);102}103if (nTime > TicksSinceEpoch<std::chrono::seconds>(now - pool.m_opts.expiry)) {104LOCK(cs_main);105const auto& accepted = AcceptToMemoryPool(active_chainstate, tx, nTime, /*bypass_limits=*/false, /*test_accept=*/false);106if (accepted.m_result_type == MempoolAcceptResult::ResultType::VALID) {107++count;108} else {109// mempool may contain the transaction already, e.g. from110// wallet(s) having loaded it while we were processing111// mempool transactions; consider these as valid, instead of112// failed, but mark them as 'already there'113if (pool.exists(tx->GetHash())) {114++already_there;115} else {116++failed;117}118}119} else {120++expired;121}122if (active_chainstate.m_chainman.m_interrupt)123return false;124}125std::map<Txid, CAmount> mapDeltas;126file >> mapDeltas;128if (opts.apply_fee_delta_priority) {129for (const auto& i : mapDeltas) {130pool.PrioritiseTransaction(i.first, i.second);131}132}134std::set<Txid> unbroadcast_txids;135file >> unbroadcast_txids;136if (opts.apply_unbroadcast_set) {137unbroadcast = unbroadcast_txids.size();138for (const auto& txid : unbroadcast_txids) {139// Ensure transactions were accepted to mempool then add to140// unbroadcast set.141if (pool.get(txid) != nullptr) pool.AddUnbroadcastTx(txid);142}143}144} catch (const std::exception& e) {145LogInfo("Failed to deserialize mempool data on file: %s. Continuing anyway.\n", e.what());146return false;147}149LogInfo("Imported mempool transactions from file: %i succeeded, %i failed, %i expired, %i already there, %i waiting for initial broadcast\n", count, failed, expired, already_there, unbroadcast);150return true;151}153bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mockable_fopen_function, bool skip_file_commit)154{155auto start = SteadyClock::now();157std::map<Txid, CAmount> mapDeltas;158std::vector<TxMempoolInfo> vinfo;159std::set<Txid> unbroadcast_txids;161static Mutex dump_mutex;162LOCK(dump_mutex);164{165LOCK(pool.cs);166for (const auto &i : pool.mapDeltas) {167mapDeltas[i.first] = i.second;168}169vinfo = pool.infoAll();170unbroadcast_txids = pool.GetUnbroadcastTxs();171}173auto mid = SteadyClock::now();175const fs::path file_fspath{dump_path + ".new"};176AutoFile file{mockable_fopen_function(file_fspath, "wb")};177if (file.IsNull()) {178return false;179}181try {182const uint64_t version{pool.m_opts.persist_v1_dat ? MEMPOOL_DUMP_VERSION_NO_XOR_KEY : MEMPOOL_DUMP_VERSION};183file << version;185if (!pool.m_opts.persist_v1_dat) {186const Obfuscation obfuscation{FastRandomContext{}.randbytes<Obfuscation::KEY_SIZE>()};187file << obfuscation;188file.SetObfuscation(obfuscation);189} else {190file.SetObfuscation({});191}193uint64_t mempool_transactions_to_write(vinfo.size());194file << mempool_transactions_to_write;195LogInfo("Writing %u mempool transactions to file...\n", mempool_transactions_to_write);196for (const auto& i : vinfo) {197file << TX_WITH_WITNESS(*(i.tx));198file << int64_t{count_seconds(i.m_time)};199file << int64_t{i.nFeeDelta};200mapDeltas.erase(i.tx->GetHash());201}203file << mapDeltas;205LogInfo("Writing %d unbroadcast transactions to file.\n", unbroadcast_txids.size());206file << unbroadcast_txids;208if (!skip_file_commit && !file.Commit()) {209(void)file.fclose();210throw std::runtime_error("Commit failed");211}212if (file.fclose() != 0) {213throw std::runtime_error(214strprintf("Error closing %s: %s", fs::PathToString(file_fspath), SysErrorString(errno)));215}216if (!RenameOver(dump_path + ".new", dump_path)) {217throw std::runtime_error("Rename failed");218}219auto last = SteadyClock::now();221LogInfo("Dumped mempool: %.3fs to copy, %.3fs to dump, %d bytes dumped to file\n",222Ticks<SecondsDouble>(mid - start),223Ticks<SecondsDouble>(last - mid),224fs::file_size(dump_path));225} catch (const std::exception& e) {226LogInfo("Failed to dump mempool: %s. Continuing anyway.\n", e.what());227(void)file.fclose();228return false;229}230return true;231}233} // namespace node