Skip to content

add -invertmempool option #107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: 28.x-knots
Choose a base branch
from
Draft
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 src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-loadblock=<file>", "Imports blocks from external file on startup", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-lowmem=<n>", strprintf("If system available memory falls below <n> MiB, flush caches (0 to disable, default: %s)", g_low_memory_threshold / 1024 / 1024), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-maxmempool=<n>", strprintf("Keep the transaction memory pool below <n> megabytes (default: %u)", DEFAULT_MAX_MEMPOOL_SIZE_MB), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-invertmempool", strprintf("Start pruning high fees txs when mempool get full (default: %u)", DEFAULT_INVERT_MEMPOOL), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-maxorphantx=<n>", strprintf("Keep at most <n> unconnectable transactions in memory (default: %u)", DEFAULT_MAX_ORPHAN_TRANSACTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-mempoolexpiry=<n>", strprintf("Do not keep transactions in the mempool longer than <n> hours (default: %u)", DEFAULT_MEMPOOL_EXPIRY_HOURS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-minimumchainwork=<hex>", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet3: %s, testnet4: %s, signet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnet4ChainParams->GetConsensus().nMinimumChainWork.GetHex(), signetChainParams->GetConsensus().nMinimumChainWork.GetHex()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
Expand Down
3 changes: 3 additions & 0 deletions src/kernel/mempool_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ enum class TRUCPolicy { Reject, Accept, Enforce };

/** Default for -maxmempool, maximum megabytes of mempool memory usage */
static constexpr unsigned int DEFAULT_MAX_MEMPOOL_SIZE_MB{300};
/** Default for -invertmempool */
static constexpr unsigned int DEFAULT_INVERT_MEMPOOL{false};
/** Default for -maxmempool when blocksonly is set */
static constexpr unsigned int DEFAULT_BLOCKSONLY_MAX_MEMPOOL_SIZE_MB{5};
/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */
Expand Down Expand Up @@ -52,6 +54,7 @@ struct MemPoolOptions {
/* The ratio used to determine how often sanity checks will run. */
int check_ratio{0};
int64_t max_size_bytes{DEFAULT_MAX_MEMPOOL_SIZE_MB * 1'000'000};
bool invert_mempool{DEFAULT_INVERT_MEMPOOL};
std::chrono::seconds expiry{std::chrono::hours{DEFAULT_MEMPOOL_EXPIRY_HOURS}};
CFeeRate incremental_relay_feerate{DEFAULT_INCREMENTAL_RELAY_FEE};
/** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
Expand Down
2 changes: 2 additions & 0 deletions src/node/mempool_args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& argsman, const CChainP
mempool_opts.check_ratio = argsman.GetIntArg("-checkmempool", mempool_opts.check_ratio);

if (auto mb = argsman.GetIntArg("-maxmempool")) mempool_opts.max_size_bytes = *mb * 1'000'000;

if (auto invert = argsman.GetBoolArg("-invertmempool")) mempool_opts.invert_mempool = *invert;

if (auto hours = argsman.GetIntArg("-mempoolexpiry")) mempool_opts.expiry = std::chrono::hours{*hours};

Expand Down
6 changes: 5 additions & 1 deletion src/rpc/mempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,11 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool, const std::optional<MempoolHi
ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
ret.pushKV("maxmempool", pool.m_opts.max_size_bytes);
ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), pool.m_opts.min_relay_feerate).GetFeePerK()));
if (pool.m_opts.invert_mempool) {
ret.pushKV("mempoolmaxfee", ValueFromAmount(pool.GetMaxFee().GetFeePerK()));
} else {
ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), pool.m_opts.min_relay_feerate).GetFeePerK()));
}
ret.pushKV("minrelaytxfee", ValueFromAmount(pool.m_opts.min_relay_feerate.GetFeePerK()));
ret.pushKV("incrementalrelayfee", ValueFromAmount(pool.m_opts.incremental_relay_feerate.GetFeePerK()));
ret.pushKV("dustrelayfee", ValueFromAmount(pool.m_opts.dust_relay_feerate.GetFeePerK()));
Expand Down
31 changes: 25 additions & 6 deletions src/txmempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,18 @@ CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
return std::max(CFeeRate(llround(rollingMinimumFeeRate)), m_opts.incremental_relay_feerate);
}

CFeeRate CTxMemPool::GetMaxFee(size_t sizelimit) const {
LOCK(cs);
CFeeRate maxFeeRate(0);
for (const auto& entry : mapTx) {
CFeeRate entryFeeRate(entry.GetModifiedFee(), entry.GetTxSize());
if (entryFeeRate > maxFeeRate) {
maxFeeRate = entryFeeRate;
}
}
return maxFeeRate;
}

void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
AssertLockHeld(cs);
if (rate.GetFeePerK() > rollingMinimumFeeRate) {
Expand All @@ -1236,12 +1248,15 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends
unsigned nTxnRemoved = 0;
CFeeRate maxFeeRateRemoved(0);
while (!mapTx.empty() && DynamicMemoryUsage() > sizelimit) {
indexed_transaction_set::index<descendant_score>::type::iterator it = mapTx.get<descendant_score>().begin();
indexed_transaction_set::index<descendant_score>::type& index = mapTx.get<descendant_score>();
indexed_transaction_set::index<descendant_score>::type::iterator it;

if (m_opts.invert_mempool) {
it = std::prev(index.end());
} else {
it = index.begin();
}

// We set the new mempool min fee to the feerate of the removed set, plus the
// "minimum reasonable fee rate" (ie some value under which we consider txn
// to have 0 fee). This way, we don't allow txn to enter mempool with feerate
// equal to txn which were removed with no block in between.
CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants());
removed += m_opts.incremental_relay_feerate;
trackPackageRemoved(removed);
Expand All @@ -1268,9 +1283,13 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends
}
}

if (maxFeeRateRemoved > CFeeRate(0)) {
if (maxFeeRateRemoved > CFeeRate(0) && !m_opts.invert_mempool) {
LogPrint(BCLog::MEMPOOL, "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString());
}

if (m_opts.invert_mempool) {
LogPrint(BCLog::MEMPOOL, "Removed %u txn, rolling maxmimum fee bumped to %s\n", nTxnRemoved, GetMaxFee().ToString());
}
}

uint64_t CTxMemPool::CalculateDescendantMaximum(txiter entry) const {
Expand Down
6 changes: 6 additions & 0 deletions src/txmempool.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ class CTxMemPool
bool m_load_tried GUARDED_BY(cs){false};

CFeeRate GetMinFee(size_t sizelimit) const;

CFeeRate GetMaxFee(size_t sizelimit) const;

public:

Expand Down Expand Up @@ -639,6 +641,10 @@ class CTxMemPool
CFeeRate GetMinFee() const {
return GetMinFee(m_opts.max_size_bytes);
}

CFeeRate GetMaxFee() const {
return GetMaxFee(m_opts.max_size_bytes);
}

/** Remove transactions from the mempool until its dynamic size is <= sizelimit.
* pvNoSpendsRemaining, if set, will be populated with the list of outpoints
Expand Down