Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/REST-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ $ curl localhost:19998/rest/getutxos/checkmempool/b2cdfd7b89def827ff8af7cd9bff76

Returns various information about the TX mempool.
Only supports JSON as output format.
* loaded : (boolean) if the mempool is fully loaded
* size : (numeric) the number of transactions in the TX mempool
* bytes : (numeric) size of the TX mempool in bytes
* usage : (numeric) total TX mempool memory usage
Expand Down
3 changes: 3 additions & 0 deletions doc/release-notes-15637.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
RPC changes
-----------
In getmempoolancestors, getmempooldescendants, getmempoolentry and getrawmempool RPCs, to be consistent with the returned value and other RPCs such as getrawtransaction, vsize has been added and size is now deprecated. size will only be returned if dashd is started with `-deprecatedrpc=size`.
8 changes: 4 additions & 4 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ void PrepareShutdown(InitInterfaces& interfaces)
g_txindex.reset();
DestroyAllBlockFilterIndexes();

if (g_is_mempool_loaded && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
DumpMempool();
if (::mempool.IsLoaded() && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
DumpMempool(::mempool);
}

if (fFeeEstimatesInitialized)
Expand Down Expand Up @@ -962,9 +962,9 @@ static void ThreadImport(std::vector<fs::path> vImportFiles)
g_wallet_init_interface.AutoLockMasternodeCollaterals();

if (gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
LoadMempool();
LoadMempool(::mempool);
}
g_is_mempool_loaded = !ShutdownRequested();
::mempool.SetIsLoaded(!ShutdownRequested());
}

void PeriodicStats()
Expand Down
13 changes: 9 additions & 4 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,9 @@ static UniValue getdifficulty(const JSONRPCRequest& request)

static std::string EntryDescriptionString()
{
return " \"size\" : n, (numeric) transaction size in bytes\n"
return " \"vsize\" : n, (numeric) virtual transaction size. This can be different from actual serialized size for high-sigop transactions.\n"
" \"size\" : n, (numeric) (DEPRECATED) same as vsize. Only returned if dashd is started with -deprecatedrpc=size\n"
" size will be completely removed in v0.20.\n"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: not sure this should be stated for us

" \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + " (DEPRECATED)\n"
" \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority (DEPRECATED)\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
Expand Down Expand Up @@ -475,7 +477,8 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool
fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants()));
info.pushKV("fees", fees);

info.pushKV("size", (int)e.GetTxSize());
info.pushKV("vsize", (int)e.GetTxSize());
if (IsDeprecatedRPCEnabled("size")) info.pushKV("size", (int)e.GetTxSize());
info.pushKV("fee", ValueFromAmount(e.GetFee()));
info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee()));
info.pushKV("time", e.GetTime());
Expand Down Expand Up @@ -1725,6 +1728,7 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool)
// Make sure this call is atomic in the pool.
LOCK(pool.cs);
UniValue ret(UniValue::VOBJ);
ret.pushKV("loaded", pool.IsLoaded());
ret.pushKV("size", (int64_t)pool.size());
ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
Expand All @@ -1746,6 +1750,7 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
{},
RPCResult{
"{\n"
" \"loaded\": true|false (boolean) True if the mempool is fully loaded\n"
" \"size\": xxxxx, (numeric) Current tx count\n"
" \"bytes\": xxxxx, (numeric) Sum of all tx sizes\n"
" \"usage\": xxxxx, (numeric) Total memory usage for the mempool\n"
Expand Down Expand Up @@ -2387,11 +2392,11 @@ static UniValue savemempool(const JSONRPCRequest& request)
}.ToString());
}

if (!g_is_mempool_loaded) {
if (!::mempool.IsLoaded()) {
throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
}

if (!DumpMempool()) {
if (!DumpMempool(::mempool)) {
throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
}

Expand Down
2 changes: 1 addition & 1 deletion src/rpc/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ UniValue deriveaddresses(const JSONRPCRequest& request)
},
RPCExamples{
"\nFirst three receive addresses\n"
+ HelpExampleCli("deriveaddresses", "\"pkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#trd0mf0l\" \"[0,2]\"")
+ HelpExampleCli("deriveaddresses", "\"pkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu\" \"[0,2]\"")
}
}.ToString());
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/blockencodings_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);

size_t poolSize = pool.size();
pool.removeRecursive(*block.vtx[2]);
pool.removeRecursive(*block.vtx[2], MemPoolRemovalReason::MANUAL);
BOOST_CHECK_EQUAL(pool.size(), poolSize - 1);

CBlock block2;
Expand Down
22 changes: 12 additions & 10 deletions src/test/mempool_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

BOOST_FIXTURE_TEST_SUITE(mempool_tests, TestingSetup)

static constexpr auto REMOVAL_REASON_DUMMY = MemPoolRemovalReason::MANUAL;

BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
{
// Test CTxMemPool::remove functionality
Expand Down Expand Up @@ -59,13 +61,13 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)

// Nothing in pool, remove should do nothing:
unsigned int poolSize = testPool.size();
testPool.removeRecursive(CTransaction(txParent));
testPool.removeRecursive(CTransaction(txParent), REMOVAL_REASON_DUMMY);
BOOST_CHECK_EQUAL(testPool.size(), poolSize);

// Just the parent:
testPool.addUnchecked(entry.FromTx(txParent));
poolSize = testPool.size();
testPool.removeRecursive(CTransaction(txParent));
testPool.removeRecursive(CTransaction(txParent), REMOVAL_REASON_DUMMY);
BOOST_CHECK_EQUAL(testPool.size(), poolSize - 1);

// Parent, children, grandchildren:
Expand All @@ -77,18 +79,18 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
}
// Remove Child[0], GrandChild[0] should be removed:
poolSize = testPool.size();
testPool.removeRecursive(CTransaction(txChild[0]));
testPool.removeRecursive(CTransaction(txChild[0]), REMOVAL_REASON_DUMMY);
BOOST_CHECK_EQUAL(testPool.size(), poolSize - 2);
// ... make sure grandchild and child are gone:
poolSize = testPool.size();
testPool.removeRecursive(CTransaction(txGrandChild[0]));
testPool.removeRecursive(CTransaction(txGrandChild[0]), REMOVAL_REASON_DUMMY);
BOOST_CHECK_EQUAL(testPool.size(), poolSize);
poolSize = testPool.size();
testPool.removeRecursive(CTransaction(txChild[0]));
testPool.removeRecursive(CTransaction(txChild[0]), REMOVAL_REASON_DUMMY);
BOOST_CHECK_EQUAL(testPool.size(), poolSize);
// Remove parent, all children/grandchildren should go:
poolSize = testPool.size();
testPool.removeRecursive(CTransaction(txParent));
testPool.removeRecursive(CTransaction(txParent), REMOVAL_REASON_DUMMY);
BOOST_CHECK_EQUAL(testPool.size(), poolSize - 5);
BOOST_CHECK_EQUAL(testPool.size(), 0U);

Expand All @@ -101,7 +103,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
// Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be
// put into the mempool (maybe because it is non-standard):
poolSize = testPool.size();
testPool.removeRecursive(CTransaction(txParent));
testPool.removeRecursive(CTransaction(txParent), REMOVAL_REASON_DUMMY);
BOOST_CHECK_EQUAL(testPool.size(), poolSize - 6);
BOOST_CHECK_EQUAL(testPool.size(), 0U);
}
Expand Down Expand Up @@ -283,11 +285,11 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
BOOST_CHECK_EQUAL(pool.size(), 10U);

// Now try removing tx10 and verify the sort order returns to normal
pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx());
pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx(), REMOVAL_REASON_DUMMY);
CheckSort<descendant_score>(pool, snapshotOrder);

pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx());
pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx());
pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx(), REMOVAL_REASON_DUMMY);
pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx(), REMOVAL_REASON_DUMMY);
}

BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
Expand Down
2 changes: 1 addition & 1 deletion src/test/miner_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript&
// Test that packages above the min relay fee do get included, even if one
// of the transactions is below the min relay fee
// Remove the low fee transaction and replace with a higher fee transaction
mempool.removeRecursive(CTransaction(tx));
mempool.removeRecursive(CTransaction(tx), MemPoolRemovalReason::MANUAL);
tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee
hashLowFeeTx = tx.GetHash();
mempool.addUnchecked(entry.Fee(feeToUse+2).FromTx(tx));
Expand Down
12 changes: 12 additions & 0 deletions src/txmempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1627,4 +1627,16 @@ CTxMemPool::EpochGuard::~EpochGuard()
pool.m_has_epoch_guard = false;
}

bool CTxMemPool::IsLoaded() const
{
LOCK(cs);
return m_is_loaded;
}

void CTxMemPool::SetIsLoaded(bool loaded)
{
LOCK(cs);
m_is_loaded = loaded;
}

SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
16 changes: 12 additions & 4 deletions src/txmempool.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,12 +351,12 @@ struct TxMempoolInfo
* this is passed to the notification signal.
*/
enum class MemPoolRemovalReason {
UNKNOWN = 0, //!< Manually removed or unknown reason
EXPIRY, //!< Expired from mempool
SIZELIMIT, //!< Removed in size limiting
REORG, //!< Removed for reorganization
BLOCK, //!< Removed for block
CONFLICT, //!< Removed for conflict with in-block transaction
MANUAL //!< Removed manually
};

class SaltedTxidHasher
Expand Down Expand Up @@ -462,6 +462,8 @@ class CTxMemPool

void trackPackageRemoved(const CFeeRate& rate) EXCLUSIVE_LOCKS_REQUIRED(cs);

bool m_is_loaded GUARDED_BY(cs){false};

public:

static const int ROLLING_FEE_HALFLIFE = 60 * 60 * 12; // public only for testing
Expand Down Expand Up @@ -614,7 +616,7 @@ class CTxMemPool
bool getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value);
bool removeSpentIndex(const uint256 txhash);

void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason);
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void removeConflicts(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
void removeProTxPubKeyConflicts(const CTransaction &tx, const CKeyID &keyId) EXCLUSIVE_LOCKS_REQUIRED(cs);
Expand Down Expand Up @@ -659,7 +661,7 @@ class CTxMemPool
* Set updateDescendants to true when removing a tx that was in a block, so
* that any in-mempool descendants have their ancestor state updated.
*/
void RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN) EXCLUSIVE_LOCKS_REQUIRED(cs);
void RemoveStaged(setEntries& stage, bool updateDescendants, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);

/** When adding transactions from a disconnected block back to the mempool,
* new mempool entries may have children in the mempool (which is generally
Expand Down Expand Up @@ -712,6 +714,12 @@ class CTxMemPool
*/
void GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) const;

/** @returns true if the mempool is fully loaded */
bool IsLoaded() const;

/** Sets the current loaded state */
void SetIsLoaded(bool loaded);

unsigned long size() const
{
LOCK(cs);
Expand Down Expand Up @@ -777,7 +785,7 @@ class CTxMemPool
* transactions in a chain before we've updated all the state for the
* removal.
*/
void removeUnchecked(txiter entry, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN) EXCLUSIVE_LOCKS_REQUIRED(cs);
void removeUnchecked(txiter entry, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
public:
/** EpochGuard: RAII-style guard for using epoch-based graph traversal algorithms.
* When walking ancestors or descendants, we generally want to avoid
Expand Down
19 changes: 9 additions & 10 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);

CBlockPolicyEstimator feeEstimator;
CTxMemPool mempool(&feeEstimator);
std::atomic_bool g_is_mempool_loaded{false};

// Internal stuff
namespace {
Expand Down Expand Up @@ -5269,7 +5268,7 @@ int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::D

static const uint64_t MEMPOOL_DUMP_VERSION = 1;

bool LoadMempool()
bool LoadMempool(CTxMemPool& pool)
{
const CChainParams& chainparams = Params();
int64_t nExpiryTimeout = gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
Expand Down Expand Up @@ -5304,12 +5303,12 @@ bool LoadMempool()

CAmount amountdelta = nFeeDelta;
if (amountdelta) {
mempool.PrioritiseTransaction(tx->GetHash(), amountdelta);
pool.PrioritiseTransaction(tx->GetHash(), amountdelta);
}
CValidationState state;
if (nTime + nExpiryTimeout > nNow) {
LOCK(cs_main);
AcceptToMemoryPoolWithTime(chainparams, mempool, state, tx, nullptr /* pfMissingInputs */, nTime,
AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, nullptr /* pfMissingInputs */, nTime,
false /* bypass_limits */, 0 /* nAbsurdFee */, false /* test_accept */);
if (state.IsValid()) {
++count;
Expand All @@ -5318,7 +5317,7 @@ bool LoadMempool()
// 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 (mempool.exists(tx->GetHash())) {
if (pool.exists(tx->GetHash())) {
++already_there;
} else {
++failed;
Expand All @@ -5334,7 +5333,7 @@ bool LoadMempool()
file >> mapDeltas;

for (const auto& i : mapDeltas) {
mempool.PrioritiseTransaction(i.first, i.second);
pool.PrioritiseTransaction(i.first, i.second);
}
} catch (const std::exception& e) {
LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
Expand All @@ -5345,7 +5344,7 @@ bool LoadMempool()
return true;
}

bool DumpMempool()
bool DumpMempool(const CTxMemPool& pool)
{
int64_t start = GetTimeMicros();

Expand All @@ -5356,11 +5355,11 @@ bool DumpMempool()
LOCK(dump_mutex);

{
LOCK(mempool.cs);
for (const auto &i : mempool.mapDeltas) {
LOCK(pool.cs);
for (const auto &i : pool.mapDeltas) {
mapDeltas[i.first] = i.second;
}
vinfo = mempool.infoAll();
vinfo = pool.infoAll();
}

int64_t mid = GetTimeMicros();
Expand Down
5 changes: 2 additions & 3 deletions src/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ struct BlockHasher
extern CCriticalSection cs_main;
extern CBlockPolicyEstimator feeEstimator;
extern CTxMemPool mempool;
extern std::atomic_bool g_is_mempool_loaded;
typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
typedef std::unordered_multimap<uint256, CBlockIndex*, BlockHasher> PrevBlockMap;
extern uint64_t nLastBlockTx;
Expand Down Expand Up @@ -801,10 +800,10 @@ static const unsigned int REJECT_HIGHFEE = 0x100;
CBlockFileInfo* GetBlockFileInfo(size_t n);

/** Dump the mempool to disk. */
bool DumpMempool();
bool DumpMempool(const CTxMemPool& pool);

/** Load the mempool from disk. */
bool LoadMempool();
bool LoadMempool(CTxMemPool& pool);

//! Check whether the block associated with this index entry is pruned or not.
inline bool IsBlockPruned(const CBlockIndex* pblockindex)
Expand Down
8 changes: 4 additions & 4 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1422,13 +1422,13 @@ void CWallet::BlockConnected(const CBlock& block, const std::vector<CTransaction

for (const CTransactionRef& ptx : vtxConflicted) {
SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
// UNKNOWN because it's a manual removal, not using mempool logic
TransactionRemovedFromMempool(ptx, MemPoolRemovalReason::UNKNOWN);
// MANUAL because it's a manual removal, not using mempool logic
TransactionRemovedFromMempool(ptx, MemPoolRemovalReason::MANUAL);
}
for (size_t i = 0; i < block.vtx.size(); i++) {
SyncTransaction(block.vtx[i], block_hash, i);
// UNKNOWN because it's a manual removal, not using mempool logic
TransactionRemovedFromMempool(block.vtx[i], MemPoolRemovalReason::UNKNOWN);
// MANUAL because it's a manual removal, not using mempool logic
TransactionRemovedFromMempool(block.vtx[i], MemPoolRemovalReason::MANUAL);
}

m_last_block_processed = block_hash;
Expand Down
Loading