Miners can call the prioritisetransaction RPC to modify the fees of mempool entries (e.g. to
account for out-of-band fees or prioritise their own transactions). The difference “delta” is an
absolute fee amount which may be positive or negative. The miner can later “cancel” the
priority by calling the RPC again with the inverse value (e.g. 100sat and -100sat).
In CTxMemPool, the delta is stored in 2 places.
Each CTxMemPoolEntry stores a “base” fee and a “modified” fee (base + delta).
mapDeltas entries are never removed from mapDeltas except when the tx is mined in a block or conflicted (since PR #6464).
Mostly it is a feature to allow prioritisetransaction for a tx that isn’t in the mempool
{yet, anymore}. When a tx is resubmitted it retains its priority, or marked as
“definitely accept” before it has ever been seen.
Since PR #8448, mapDeltas is persisted to mempool.dat and loaded on restart.
Note the removal due to block/conflict is only done when CTxMemPool::removeForBlock is called, i.e.
when the block is received. If you load a mempool.dat containing mapDeltas with
transactions that were mined already (e.g. the file was saved prior to the last few blocks), you
don’t delete them.
There is no way to query the node for not-in-mempool mapDeltas. If you add a priority and forget
what the value was, the only way to get that information is to inspect mempool.dat.
Calling prioritisetransaction with an inverse value does not remove it from mapDeltas, it just
sets the value to 0. It disappears on a restart (LoadMempool checks if delta is 0), but that
might not happen for a while.
PR #27501 adds an RPC to get prioritised
transactions (also tells you whether the tx is in mempool or not), helping users to clean up
mapDeltas manually. It also changes CTxMemPool::PrioritiseTransaction so that when a delta is
set to 0, it removes the entry from mapDeltas entirely.
<theStack> the pr enables users of the prioritisetransaction RPC (i.e. miners) the possibility to 1) inspect the current map of prioritised txs with a new RPC and 2) also delete them from the map if delta is zero again
<LarryRuane> mapDeltas allows the node user to artificially modify a transaction's fee which would affect fee estimation, eviction decisions, mining decisions and probably a few other things
<LarryRuane> theStack: yes, and IIUC, this new RPC won't tell us anything we *couldn't* already know, if we kept track somehow separately, but since the node already knows it, it's helpful for it to be able to provide it
<LarryRuane> taking advantage of the behavior of `std::map` that if you access a key that doesn't exist, it gets created as a side-effect -- is that right?
<sipa> LarryRuane: You should think of the RPC as informing bitcoind of the fact that if somehow that transaction gets mined, *you* (the node owner) gets paid out of band.
<glozow> sebastianvanstaa: correct, it is only removed when the tx is confirmed or conflicted by a block. Another case is if its value is 0 and you restart.
<LarryRuane> glozow: that's interesting! they don't really have a way to remove a tx from the mempool, if they want to censor it, so this gives them a means to the same end (not that we like censoring)
<glozow> Yeah they would stay in the mempool unless it fills up and we start evicting the low-feerate transactions. The modified feerate is used in that algo, so we'll evict those "de-prioritised" ones.
<sipa> Of course, ideally miners don't get paid out of band at all for transactions; it removes the ability for the public P2P network to e.g. estimate fees.
<glozow> LarryRuane: Yes, I agree. Ideally the public p2p network is a fair, fee-based auction in which everybody knows what the "going rate" is and has the ability to bid.
<LarryRuane> sipa: so for example if our standardness rules are too tight, that might be a bad thing if it encourages more out-of-band transactions.. but if they're too loose, then there's a possible DoS vector!
<LarryRuane> but i do have a question on this point... if a tx is removed due to it appearing in a block, but then that block is reorged out (rollback), then we would forget its prioritization, right? (but maybe that's rare enough we don't care)
<glozow> Here's the PR that added the removal logic: https://github.com/bitcoin/bitcoin/pull/6464. There is some discussion about when we should/shouldn't remove an entry there.
<LarryRuane> Oh Luke makes a good point on the PR you just linked to, that we need a separate map because if the tx isn't already in the mempool, it may not be able to *enter* on its own fee
<LarryRuane> (was that question to me?) well because if the node shuts down uncleanly, the user won't have to remember all the prioritizations that were done ... but i know non-clean shutdown is very rare
<kevkevin> glozow I just saw that mapDeltas are written out to `mempool.dat` I thought they were separate. Do the `mapDeltas` change `mempool.dat` in anyway?
<theStack> interesting that the mempool serialization was never changed to not serialize 0 fee delta entries in the first place (but only ignore them on loading)
<glozow> LarryRuane: also note that, in that function, `mapDeltas` is a local copy of the mempool's mapDeltas and goes out of scope at the end of the function
<glozow> kevkevin: sebastianvanstaa: kind of. I think the only way to do it is to keep track of every time you've called prioritisetransaction and when the entries would be deleted, then "cancel" the stale ones by setting the delta to 0 and then restarting your node.
<theStack> i'd use the new fancy RPC call to see what the current delta for a given tx is, and then call prioritisetransaction with that value negated to set it to zero again... aaand it's gone
<kevkevin> would it not make sense to also be able to just remove a transaction from the mapDelta and not have to call two rpc's to achive that, not sure if I'm missing why not have the ability to do so
<glozow> jnewbery suggested to me offline that perhaps we could implicitly interpret `prioritisetransaction(txid, 0, delta=0)` as "clear prioritisation." I think that could be an extra simplification.
<LarryRuane> someone earlier asked if probably only miners would use `"prioritisetransaction` .. i noticed that that PRC is in `rpc/mining.cpp` so that tell you something!