Skip to content

Commit 101c642

Browse files
committed
Merge #8448: Store mempool and prioritization data to disk
582068a Add mempool.dat to doc/files.md (Pieter Wuille) 3f78562 Add DumpMempool and LoadMempool (Pieter Wuille) ced7c94 Add AcceptToMemoryPoolWithTime function (Pieter Wuille) c3efb58 Add feedelta to TxMempoolInfo (Pieter Wuille)
2 parents 273bde3 + 582068a commit 101c642

File tree

6 files changed

+147
-7
lines changed

6 files changed

+147
-7
lines changed

doc/files.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* db.log: wallet database log file
1111
* debug.log: contains debug information and general logging generated by bitcoind or bitcoin-qt
1212
* fee_estimates.dat: stores statistics used to estimate minimum transaction fees and priorities required for confirmation; since 0.10.0
13+
* mempool.dat: dump of the mempool's transactions; since 0.14.0.
1314
* peers.dat: peer IP address database (custom format); since 0.7.0
1415
* wallet.dat: personal wallet (BDB) with keys and transactions
1516
* .cookie: session RPC authentication cookie (written at start when cookie authentication is used, deleted on shutdown): since 0.12.0

src/init.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ void Shutdown()
207207

208208
StopTorControl();
209209
UnregisterNodeSignals(GetNodeSignals());
210+
DumpMempool();
210211

211212
if (fFeeEstimatesInitialized)
212213
{
@@ -659,6 +660,8 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
659660
LogPrintf("Stopping after block import\n");
660661
StartShutdown();
661662
}
663+
664+
LoadMempool();
662665
}
663666

664667
/** Sanity checks

src/main.cpp

Lines changed: 124 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,7 @@ std::string FormatStateMessage(const CValidationState &state)
11351135
}
11361136

11371137
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree,
1138-
bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
1138+
bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
11391139
std::vector<uint256>& vHashTxnToUncache)
11401140
{
11411141
const uint256 hash = tx.GetHash();
@@ -1308,7 +1308,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
13081308
}
13091309
}
13101310

1311-
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOpsCost, lp);
1311+
CTxMemPoolEntry entry(tx, nFees, nAcceptTime, dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOpsCost, lp);
13121312
unsigned int nSize = entry.GetTxSize();
13131313

13141314
// Check that the transaction doesn't have an excessive number of
@@ -1572,18 +1572,24 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
15721572
return true;
15731573
}
15741574

1575-
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
1576-
bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
1575+
bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
1576+
bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
15771577
{
15781578
std::vector<uint256> vHashTxToUncache;
1579-
bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
1579+
bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
15801580
if (!res) {
15811581
BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache)
15821582
pcoinsTip->Uncache(hashTx);
15831583
}
15841584
return res;
15851585
}
15861586

1587+
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
1588+
bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
1589+
{
1590+
return AcceptToMemoryPoolWithTime(pool, state, tx, fLimitFree, pfMissingInputs, GetTime(), fOverrideMempoolLimit, nAbsurdFee);
1591+
}
1592+
15871593
/** Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock */
15881594
bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow)
15891595
{
@@ -6929,6 +6935,119 @@ int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::D
69296935
return VersionBitsStateSinceHeight(chainActive.Tip(), params, pos, versionbitscache);
69306936
}
69316937

6938+
static const uint64_t MEMPOOL_DUMP_VERSION = 1;
6939+
6940+
bool LoadMempool(void)
6941+
{
6942+
int64_t nExpiryTimeout = GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
6943+
FILE* filestr = fopen((GetDataDir() / "mempool.dat").string().c_str(), "r");
6944+
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
6945+
if (file.IsNull()) {
6946+
LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n");
6947+
return false;
6948+
}
6949+
6950+
int64_t count = 0;
6951+
int64_t skipped = 0;
6952+
int64_t failed = 0;
6953+
int64_t nNow = GetTime();
6954+
6955+
try {
6956+
uint64_t version;
6957+
file >> version;
6958+
if (version != MEMPOOL_DUMP_VERSION) {
6959+
return false;
6960+
}
6961+
uint64_t num;
6962+
file >> num;
6963+
double prioritydummy = 0;
6964+
while (num--) {
6965+
CTransaction tx;
6966+
int64_t nTime;
6967+
int64_t nFeeDelta;
6968+
file >> tx;
6969+
file >> nTime;
6970+
file >> nFeeDelta;
6971+
6972+
CAmount amountdelta = nFeeDelta;
6973+
if (amountdelta) {
6974+
mempool.PrioritiseTransaction(tx.GetHash(), tx.GetHash().ToString(), prioritydummy, amountdelta);
6975+
}
6976+
CValidationState state;
6977+
if (nTime + nExpiryTimeout > nNow) {
6978+
LOCK(cs_main);
6979+
AcceptToMemoryPoolWithTime(mempool, state, tx, true, NULL, nTime);
6980+
if (state.IsValid()) {
6981+
++count;
6982+
} else {
6983+
++failed;
6984+
}
6985+
} else {
6986+
++skipped;
6987+
}
6988+
}
6989+
std::map<uint256, CAmount> mapDeltas;
6990+
file >> mapDeltas;
6991+
6992+
for (const auto& i : mapDeltas) {
6993+
mempool.PrioritiseTransaction(i.first, i.first.ToString(), prioritydummy, i.second);
6994+
}
6995+
} catch (const std::exception& e) {
6996+
LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
6997+
return false;
6998+
}
6999+
7000+
LogPrintf("Imported mempool transactions from disk: %i successes, %i failed, %i expired\n", count, failed, skipped);
7001+
return true;
7002+
}
7003+
7004+
void DumpMempool(void)
7005+
{
7006+
int64_t start = GetTimeMicros();
7007+
7008+
std::map<uint256, CAmount> mapDeltas;
7009+
std::vector<TxMempoolInfo> vinfo;
7010+
7011+
{
7012+
LOCK(mempool.cs);
7013+
for (const auto &i : mempool.mapDeltas) {
7014+
mapDeltas[i.first] = i.second.first;
7015+
}
7016+
vinfo = mempool.infoAll();
7017+
}
7018+
7019+
int64_t mid = GetTimeMicros();
7020+
7021+
try {
7022+
FILE* filestr = fopen((GetDataDir() / "mempool.dat.new").string().c_str(), "w");
7023+
if (!filestr) {
7024+
return;
7025+
}
7026+
7027+
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
7028+
7029+
uint64_t version = MEMPOOL_DUMP_VERSION;
7030+
file << version;
7031+
7032+
file << (uint64_t)vinfo.size();
7033+
for (const auto& i : vinfo) {
7034+
file << *(i.tx);
7035+
file << (int64_t)i.nTime;
7036+
file << (int64_t)i.nFeeDelta;
7037+
mapDeltas.erase(i.tx->GetHash());
7038+
}
7039+
7040+
file << mapDeltas;
7041+
FileCommit(file.Get());
7042+
file.fclose();
7043+
RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat");
7044+
int64_t last = GetTimeMicros();
7045+
LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", (mid-start)*0.000001, (last-mid)*0.000001);
7046+
} catch (const std::exception& e) {
7047+
LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
7048+
}
7049+
}
7050+
69327051
class CMainCleanup
69337052
{
69347053
public:

src/main.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,10 @@ void PruneAndFlush();
291291
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
292292
bool* pfMissingInputs, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
293293

294+
/** (try to) add transaction to memory pool with a specified acceptance time **/
295+
bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
296+
bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
297+
294298
/** Convert CValidationState to a human-readable message for logging */
295299
std::string FormatStateMessage(const CValidationState &state);
296300

@@ -529,6 +533,12 @@ static const unsigned int REJECT_ALREADY_KNOWN = 0x101;
529533
/** Transaction conflicts with a transaction already known */
530534
static const unsigned int REJECT_CONFLICT = 0x102;
531535

536+
/** Dump the mempool to disk. */
537+
void DumpMempool();
538+
539+
/** Load the mempool from disk. */
540+
bool LoadMempool();
541+
532542
// The following things handle network-processing logic
533543
// (and should be moved to a separate file)
534544

src/txmempool.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,10 @@ void CTxMemPool::queryHashes(vector<uint256>& vtxid)
833833
}
834834
}
835835

836+
static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) {
837+
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize()), it->GetModifiedFee() - it->GetFee()};
838+
}
839+
836840
std::vector<TxMempoolInfo> CTxMemPool::infoAll() const
837841
{
838842
LOCK(cs);
@@ -841,7 +845,7 @@ std::vector<TxMempoolInfo> CTxMemPool::infoAll() const
841845
std::vector<TxMempoolInfo> ret;
842846
ret.reserve(mapTx.size());
843847
for (auto it : iters) {
844-
ret.push_back(TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize())});
848+
ret.push_back(GetInfo(it));
845849
}
846850

847851
return ret;
@@ -862,7 +866,7 @@ TxMempoolInfo CTxMemPool::info(const uint256& hash) const
862866
indexed_transaction_set::const_iterator i = mapTx.find(hash);
863867
if (i == mapTx.end())
864868
return TxMempoolInfo();
865-
return TxMempoolInfo{i->GetSharedTx(), i->GetTime(), CFeeRate(i->GetFee(), i->GetTxSize())};
869+
return GetInfo(i);
866870
}
867871

868872
CFeeRate CTxMemPool::estimateFee(int nBlocks) const

src/txmempool.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,9 @@ struct TxMempoolInfo
329329

330330
/** Feerate of the transaction. */
331331
CFeeRate feeRate;
332+
333+
/** The fee delta. */
334+
int64_t nFeeDelta;
332335
};
333336

334337
/**

0 commit comments

Comments
 (0)