16
16
#include < uint256.h>
17
17
#include < util/fs.h>
18
18
#include < util/fs_helpers.h>
19
+ #include < util/serfloat.h>
19
20
#include < util/signalinterrupt.h>
20
21
#include < util/syserror.h>
21
22
#include < util/time.h>
@@ -38,6 +39,39 @@ namespace node {
38
39
39
40
static const uint64_t MEMPOOL_DUMP_VERSION_NO_XOR_KEY{1 };
40
41
static const uint64_t MEMPOOL_DUMP_VERSION{2 };
42
+ static constexpr uint64_t MEMPOOL_KNOTS_DUMP_VERSION = 0 ;
43
+
44
+ bool LoadMempoolKnots (CTxMemPool& pool, const fs::path& knots_filepath, FopenFn mockable_fopen_function)
45
+ {
46
+ AutoFile file{mockable_fopen_function (knots_filepath, " rb" )};
47
+ if (file.IsNull ()) {
48
+ // Typically missing if there's nothing to save
49
+ return false ;
50
+ }
51
+
52
+ try {
53
+ uint64_t version;
54
+ file >> version;
55
+ if (version != MEMPOOL_KNOTS_DUMP_VERSION) {
56
+ return false ;
57
+ }
58
+
59
+ const unsigned int priority_deltas_count = ReadCompactSize (file);
60
+ uint256 txid;
61
+ uint64_t encoded_priority;
62
+ for (unsigned int i = 0 ; i < priority_deltas_count; ++i) {
63
+ Unserialize (file, txid);
64
+ Unserialize (file, encoded_priority);
65
+ const double priority = DecodeDouble (encoded_priority);
66
+ pool.PrioritiseTransaction (txid, priority, 0 );
67
+ }
68
+ } catch (const std::exception& e) {
69
+ LogInfo (" Failed to deserialize mempool-knots data on file: %s. Continuing anyway.\n " , e.what ());
70
+ return false ;
71
+ }
72
+
73
+ return true ;
74
+ }
41
75
42
76
bool LoadMempool (CTxMemPool& pool, const fs::path& load_path, Chainstate& active_chainstate, ImportMempoolOptions&& opts)
43
77
{
@@ -143,6 +177,12 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active
143
177
return false ;
144
178
}
145
179
180
+ if (opts.load_knots_data ) {
181
+ auto knots_filepath = load_path;
182
+ knots_filepath.replace_filename (" mempool-knots.dat" );
183
+ LoadMempoolKnots (pool, knots_filepath, opts.mockable_fopen_function );
184
+ }
185
+
146
186
LogInfo (" 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);
147
187
return true ;
148
188
}
@@ -152,6 +192,7 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mock
152
192
auto start = SteadyClock::now ();
153
193
154
194
std::map<uint256, CAmount> mapDeltas;
195
+ std::map<uint256, double > priority_deltas;
155
196
std::vector<TxMempoolInfo> vinfo;
156
197
std::set<uint256> unbroadcast_txids;
157
198
@@ -161,6 +202,9 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mock
161
202
{
162
203
LOCK (pool.cs );
163
204
for (const auto &i : pool.mapDeltas ) {
205
+ if (i.second .first ) { // priority delta
206
+ priority_deltas[i.first ] = i.second .first ;
207
+ }
164
208
if (i.second .second ) { // fee delta
165
209
mapDeltas[i.first ] = i.second .second ;
166
210
}
@@ -209,6 +253,39 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mock
209
253
throw std::runtime_error (
210
254
strprintf (" Error closing %s: %s" , fs::PathToString (file_fspath), SysErrorString (errno)));
211
255
}
256
+
257
+ auto knots_filepath = dump_path;
258
+ knots_filepath.replace_filename (" mempool-knots.dat" );
259
+ LogInfo (" Writing %u mempool prioritizations to file...\n " , priority_deltas.size ());
260
+ if (priority_deltas.size ()) {
261
+ auto knots_tmppath = knots_filepath;
262
+ knots_tmppath += " .new" ;
263
+
264
+ AutoFile file{mockable_fopen_function (knots_tmppath, " wb" )};
265
+ if (file.IsNull ()) return false ;
266
+
267
+ uint64_t version = MEMPOOL_KNOTS_DUMP_VERSION;
268
+ file << version;
269
+
270
+ WriteCompactSize (file, priority_deltas.size ());
271
+ for (const auto & [txid, priority] : priority_deltas) {
272
+ Serialize (file, txid);
273
+ const uint64_t encoded_priority = EncodeDouble (priority);
274
+ Serialize (file, encoded_priority);
275
+ }
276
+
277
+ if (!file.Commit ()) throw std::runtime_error (" Commit failed" );
278
+ if (file.fclose () != 0 ) {
279
+ throw std::runtime_error (
280
+ strprintf (" Error closing %s: %s" , fs::PathToString (knots_tmppath), SysErrorString (errno)));
281
+ }
282
+ if (!RenameOver (knots_tmppath, knots_filepath)) {
283
+ throw std::runtime_error (" Rename failed (mempool-knots.dat)" );
284
+ }
285
+ } else {
286
+ fs::remove (knots_filepath);
287
+ }
288
+
212
289
if (!RenameOver (dump_path + " .new" , dump_path)) {
213
290
throw std::runtime_error (" Rename failed" );
214
291
}
@@ -217,6 +294,7 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mock
217
294
LogInfo (" Dumped mempool: %.3fs to copy, %.3fs to dump, %d bytes dumped to file\n " ,
218
295
Ticks<SecondsDouble>(mid - start),
219
296
Ticks<SecondsDouble>(last - mid),
297
+ (priority_deltas.empty () ? 0 : fs::file_size (knots_filepath)) +
220
298
fs::file_size (dump_path));
221
299
} catch (const std::exception& e) {
222
300
LogInfo (" Failed to dump mempool: %s. Continuing anyway.\n " , e.what ());
0 commit comments