Follow-up to [DEFUNCT] Cluster Mempool Package RBF sketch. Superseded by Post-clustermempool package RBF: per-chunk processing.
Design for post-clustermempool Package RBF rules.
A new package comes in (consisting of a set of transactions PKG
). Ignore for now how the P2P side happens.
-
- Deduplication: remove from
PKG
any transaction that’s already in the receiver’s mempool.
- Deduplication: remove from
-
- Pre-linearization: linearize (what remains of)
PKG
(so without in-mempool dependencies).
- Pre-linearization: linearize (what remains of)
-
- Pre-eviction: remove from
PKG
any chunk whose feerate is belowmempoolminfee
or belowincremental_relay_feerate
. [DoS protection]
- Pre-eviction: remove from
-
- Gather
CON
, the set of in-mempool conflicts with (what remains of)PKG
. IfCON
is non-empty:
-
- Gather
OLD
: the union of all in-mempool clusters that containCON
or contain ancestors ofPKG
.
- Gather
-
- Compute
NEW = OLD - CON + PKG
.
- Compute
-
- Relay check:
fee(NEW) >= fee(OLD) + incremental_relay_feerate * size(PKG)
. [DoS protection]
- Relay check:
-
- Linearization: linearize all clusters in
NEW
(note that there can be multiple).
- Linearization: linearize all clusters in
-
- Diagram check: verify that the fee-size diagram of
NEW
is nowhere worse than that ofOLD
, and at least better in one place. [incentive compatibility]
- Diagram check: verify that the fee-size diagram of
-
- Tail check: (only if
tail_feerate >= incremental_relay_feerate
): verify thatfee(NEW) >= tail_feerate * (size(NEW) - size(OLD)) + fee(OLD)
. [incentive compatibility]
- Tail check: (only if
- Gather
-
- Verification: verify all transactions in
PKG
using policy/standardness rules, against UTXOs gathered from chain, mempool, andPKG
itself.
- Verification: verify all transactions in
(At this point the package is valid)
-
- Eviction Drop all of
CON
from mempool.
- Eviction Drop all of
-
- Addition One by one, add the transactions of
PKG
to mempool performing consensus validation.
- Addition One by one, add the transactions of
In the above, wherever a linearization occurs, fail the package if it involves a cluster that exceeds cluster count limit. Also fail the package whenever a cluster would be created that exceeds the cluster size limit.
Open questions
-
Q1. Do we need to run the sequence of operations inside (3) separately for each connected component inside
PKG
rather than all of (the remainder of)PKG
at once? Doing so would prevent some situations where there are two subpackages, one making a cluster a lot better, and one making another cluster somewhat worse, in such a way that the overall package is an improvement. On the other hand, this cannot possibly discover all cases where a combination of old and new transactions are better than both just old or just new. -
Q2. More generally, is this “good enough”? One example is this: assume a new package is received consisting of transactions A(feerate 100), B(depends on A, feerate 4), C(depends on A, feerate 5). In the mempool we already have C’(feerate 6). Assuming a sufficiently low
mempoolminfee
, the package (A,B,C) will replace C’ according to the rules above. Yet, if C’ gets relayed again, it would evict C, and you’d end up with (A,B,C’). This isn’t free relay: both replacements are paid for, can only happens once (each), and both strictly improve the mempool. Some degree of subpackage validation could catch this (and/or result in the final version being reached immediately), as could chunk merging ofOLD
withNEW
, but there almost certainly exist more complicated examples where the optimal mix of old and new cannot be found naively.