Bitcoin ABC 0.32.6
P2P Digital Currency
mempool_persist.cpp
Go to the documentation of this file.
1// Copyright (c) 2022 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
6
7#include <consensus/amount.h>
8#include <logging.h>
10#include <serialize.h>
11#include <streams.h>
12#include <sync.h>
13#include <txmempool.h>
14#include <uint256.h>
15#include <util/fs.h>
16#include <util/fs_helpers.h>
18#include <util/time.h>
19#include <validation.h>
20
21#include <chrono>
22#include <cstdint>
23#include <cstdio>
24#include <exception>
25#include <functional>
26#include <map>
27#include <memory>
28#include <set>
29#include <stdexcept>
30#include <utility>
31#include <vector>
32
34
35namespace kernel {
36static const uint64_t MEMPOOL_DUMP_VERSION = 1;
37
38bool LoadMempool(CTxMemPool &pool, const fs::path &load_path,
39 Chainstate &active_chainstate,
40 FopenFn mockable_fopen_function) {
41 if (load_path.empty()) {
42 return false;
43 }
44
45 AutoFile file{mockable_fopen_function(load_path, "rb")};
46 if (file.IsNull()) {
48 "Failed to open mempool file from disk. Continuing anyway.\n");
49 return false;
50 }
51
52 int64_t count = 0;
53 int64_t expired = 0;
54 int64_t failed = 0;
55 int64_t already_there = 0;
56 int64_t unbroadcast = 0;
57 auto now = NodeClock::now();
58
59 try {
60 uint64_t version;
61 file >> version;
62 if (version != MEMPOOL_DUMP_VERSION) {
63 return false;
64 }
65
66 uint64_t num;
67 file >> num;
68 while (num) {
69 --num;
71 int64_t nTime;
72 int64_t nFeeDelta;
73 file >> tx;
74 file >> nTime;
75 file >> nFeeDelta;
76
77 Amount amountdelta = nFeeDelta * SATOSHI;
78 if (amountdelta != Amount::zero()) {
79 pool.PrioritiseTransaction(tx->GetId(), amountdelta);
80 }
81 if (nTime >
82 TicksSinceEpoch<std::chrono::seconds>(now - pool.m_expiry)) {
84 const auto &accepted =
85 AcceptToMemoryPool(active_chainstate, tx, nTime,
86 /*bypass_limits=*/false,
87 /*test_accept=*/false);
88 if (accepted.m_result_type ==
90 ++count;
91 } else {
92 // mempool may contain the transaction already, e.g. from
93 // wallet(s) having loaded it while we were processing
94 // mempool transactions; consider these as valid, instead of
95 // failed, but mark them as 'already there'
96 if (pool.exists(tx->GetId())) {
97 ++already_there;
98 } else {
99 ++failed;
100 }
101 }
102 } else {
103 ++expired;
104 }
105
106 if (active_chainstate.m_chainman.m_interrupt) {
107 return false;
108 }
109 }
110 std::map<TxId, Amount> mapDeltas;
111 file >> mapDeltas;
112
113 for (const auto &i : mapDeltas) {
114 pool.PrioritiseTransaction(i.first, i.second);
115 }
116
117 std::set<TxId> unbroadcast_txids;
118 file >> unbroadcast_txids;
119 unbroadcast = unbroadcast_txids.size();
120 for (const auto &txid : unbroadcast_txids) {
121 // Ensure transactions were accepted to mempool then add to
122 // unbroadcast set.
123 if (pool.get(txid) != nullptr) {
124 pool.AddUnbroadcastTx(txid);
125 }
126 }
127 } catch (const std::exception &e) {
128 LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing "
129 "anyway.\n",
130 e.what());
131 return false;
132 }
133
134 LogPrintf("Imported mempool transactions from disk: %i succeeded, %i "
135 "failed, %i expired, %i already there, %i waiting for initial "
136 "broadcast\n",
137 count, failed, expired, already_there, unbroadcast);
138 return true;
139}
140
141bool DumpMempool(const CTxMemPool &pool, const fs::path &dump_path,
142 FopenFn mockable_fopen_function, bool skip_file_commit) {
143 auto start = SteadyClock::now();
144
145 std::map<uint256, Amount> mapDeltas;
146 std::vector<TxMempoolInfo> vinfo;
147 std::set<TxId> unbroadcast_txids;
148
149 static Mutex dump_mutex;
150 LOCK(dump_mutex);
151
152 {
153 LOCK(pool.cs);
154 for (const auto &i : pool.mapDeltas) {
155 mapDeltas[i.first] = i.second;
156 }
157
158 vinfo = pool.infoAll();
159 unbroadcast_txids = pool.GetUnbroadcastTxs();
160 }
161
162 auto mid = SteadyClock::now();
163
164 try {
165 AutoFile file{mockable_fopen_function(dump_path + ".new", "wb")};
166 if (file.IsNull()) {
167 return false;
168 }
169
170 uint64_t version = MEMPOOL_DUMP_VERSION;
171 file << version;
172
173 file << uint64_t(vinfo.size());
174 for (const auto &i : vinfo) {
175 file << *(i.tx);
176 file << int64_t(count_seconds(i.m_time));
177 file << i.nFeeDelta;
178 mapDeltas.erase(i.tx->GetId());
179 }
180
181 file << mapDeltas;
182
183 LogPrintf("Writing %d unbroadcast transactions to disk.\n",
184 unbroadcast_txids.size());
185 file << unbroadcast_txids;
186
187 if (!skip_file_commit && !FileCommit(file.Get())) {
188 throw std::runtime_error("FileCommit failed");
189 }
190 file.fclose();
191 if (!RenameOver(dump_path + ".new", dump_path)) {
192 throw std::runtime_error("Rename failed");
193 }
194 auto last = SteadyClock::now();
195
196 LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n",
197 Ticks<SecondsDouble>(mid - start),
198 Ticks<SecondsDouble>(last - mid));
199 } catch (const std::exception &e) {
200 LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
201 return false;
202 }
203 return true;
204}
205
206} // namespace kernel
static constexpr Amount SATOSHI
Definition: amount.h:148
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:430
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:221
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:317
const std::chrono::seconds m_expiry
Definition: txmempool.h:355
std::vector< TxMempoolInfo > infoAll() const
Definition: txmempool.cpp:535
bool exists(const TxId &txid) const
Definition: txmempool.h:530
std::set< TxId > GetUnbroadcastTxs() const
Returns transactions in unbroadcast set.
Definition: txmempool.h:569
CTransactionRef get(const TxId &txid) const
Definition: txmempool.cpp:676
void PrioritiseTransaction(const TxId &txid, const Amount nFeeDelta)
Affect CreateNewBlock prioritisation of transactions.
Definition: txmempool.cpp:706
void AddUnbroadcastTx(const TxId &txid)
Adds a transaction to the unbroadcast set.
Definition: txmempool.h:556
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:733
ChainstateManager & m_chainman
The chainstate manager that owns this chainstate.
Definition: validation.h:795
const util::SignalInterrupt & m_interrupt
Definition: validation.h:1321
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
bool RenameOver(fs::path src, fs::path dest)
Definition: fs_helpers.cpp:273
bool FileCommit(FILE *file)
Ensure file contents are fully committed to disk, using a platform-specific feature analogous to fsyn...
Definition: fs_helpers.cpp:126
#define LogPrintf(...)
Definition: logging.h:424
std::function< FILE *(const fs::path &, const char *)> FopenFn
Definition: fs.h:203
Definition: init.h:28
bool DumpMempool(const CTxMemPool &pool, const fs::path &dump_path, FopenFn mockable_fopen_function, bool skip_file_commit)
static const uint64_t MEMPOOL_DUMP_VERSION
bool LoadMempool(CTxMemPool &pool, const fs::path &load_path, Chainstate &active_chainstate, FopenFn mockable_fopen_function)
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
Definition: amount.h:21
static constexpr Amount zero() noexcept
Definition: amount.h:34
@ VALID
Fully validated, valid.
static time_point now() noexcept
Return current system time or mocked time, if set.
Definition: time.cpp:71
#define LOCK(cs)
Definition: sync.h:306
static int count
Definition: tests.c:31
constexpr int64_t count_seconds(std::chrono::seconds t)
Definition: time.h:57
MempoolAcceptResult AcceptToMemoryPool(Chainstate &active_chainstate, const CTransactionRef &tx, int64_t accept_time, bool bypass_limits, bool test_accept, unsigned int heightOverride)
Try to add a transaction to the mempool.