RFC Bedrock: Mempool — Transaction Maturity - #415
Draft
madxor wants to merge 1 commit into
Draft
Conversation
The mempool disseminates a transaction by push but learns nothing about how far it got, so a node cannot distinguish a transaction the whole network holds from one it alone was handed. That is the distinction the tagging attack exploits, and the Blend Protocol defers its mitigation to the mempool: a node should hold "an attestation that the transaction was seen by the majority of the network". This adds that attestation. After a propagation delay a node queries randomly sampled providers from the active Service Declaration Protocol snapshot, asking which of a batch of transactions they hold. A positive answer is signed and carries a witness over the querier's nonce and the provider's cached body commitments, so a provider that does not hold the transaction cannot claim it does, and answering costs a constant amount of work rather than one proportional to transaction size. A transaction that collects PULL_CONFIRMATIONS attestations from distinct providers is confirmed, and only confirmed transactions may be selected into a proposal — which closes the tagging channel at its source, since a selectively delivered transaction never confirms and therefore never appears in a block. Confirmation gates selection and nothing else: it never enters retirement or reference resolution, so a node's private sampling luck cannot diverge its pool from its peers' or change which proposals it can reconstruct. Block validity is unchanged, and a leader that ignores the gate harms only its own anonymity, so no enforcement is required. The triple (32 providers per round, 8 rounds, threshold 133) is calibrated against a withholding adversary holding one third of the declared set, with exact hypergeometric tails: security failure 2.3e-10, liveness failure 7.1e-7. Sampling exclusions are per transaction rather than per batch, and the total sample is a security parameter rather than a budget — raising it at a fixed threshold favours the adversary. The residual observable pull creates — a query reveals to the queried provider that the querier holds the transaction — is documented along with the two properties that keep it from restoring the attack: every node queries about every transaction it holds, continuously from admission, so query behaviour carries no leadership or stake signal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[RFC-PR] Mempool: Transaction Maturity
Reviewer Orientation
Read Motivation first — the whole change follows from one gap: a node that has pushed a transaction learns nothing about how far it got, and that ignorance is what the tagging attack exploits. This PR is stacked on the mempool base specification and modifies only that document.
Status tracker
Change log
Motivation
The mempool disseminates a transaction by pushing it into a gossipsub mesh, and then knows nothing more. A node cannot distinguish a transaction the whole network holds from one it alone was handed — and that distinction is exactly what the tagging attack turns into a deanonymisation: deliver a transaction to one node, watch which proposal first carries it, and the proposer is identified. Repeated, this measures a node's proposal rate and therefore its stake.
The Blend Protocol states plainly that its own network-level protection is not sufficient on its own, and defers the other half to the mempool: the mitigation is "designing a mempool in such a way that the node has an attestation that the transaction was seen by the majority of the network". No such attestation has ever been designed. Until it exists, one of the two mechanisms Blend says are jointly required is simply missing.
The same ignorance also leaves transaction maturity — the assumption block construction makes, that a referenced transaction has had time to reach every node — as an assumption rather than something a leader can check.
Proposal
Add a pull half to mempool dissemination, and gate block-building selection on it.
After a propagation delay, a node queries randomly sampled providers from the active Service Declaration Protocol snapshot, asking which of a batch of transactions they hold. A positive answer is signed and carries a witness proving possession. A transaction that collects
PULL_CONFIRMATIONSattestations from distinct providers is confirmed, and only confirmed transactions may be selected into a proposal.That closes the tagging channel at its source: a selectively delivered transaction never confirms, so it is never offered for selection, so it never appears in a proposal, so it never identifies a proposer. It also converts transaction maturity from an assumption into evidence a leader actually holds.
Confirmation is a local inclusion gate, not a consensus rule. Block validity is unchanged, and a leader that ignores the gate produces a perfectly valid block — it has only forfeited its own anonymity.
Discussion
Why the gate is advisory rather than enforced
Making an attestation a block-validity condition would let a validator reject proposals over its own private sampling state, which is precisely the view-dependence that reference resolution is designed to exclude. Since the only party protected by the gate is the proposer, the only party harmed by skipping it is the proposer, and no enforcement is needed. Consensus, serialization and block wire behaviour are untouched.
Calibrating the threshold
The threshold is squeezed from both sides. Too low and an adversary's own providers can confirm a tagged transaction; too high and a genuinely broadcast transaction cannot confirm. Both counts are hypergeometric — sampling is without replacement from a finite declared set — and two properties fall out that a naive estimate misses: the total sample is a security parameter, since more draws at a fixed threshold give the adversary more chances to accumulate; and a withholding adversary sets the liveness cost, because refusing to attest cannot confirm a tagged transaction but does remove the adversary's share of every sample from the attesting pool.
The published triple —
PULL_SAMPLE_SIZE = 32,PULL_MAX_ROUNDS = 8,PULL_CONFIRMATIONS = 133— is calibrated at 5 000 active declarations, adversarial fraction exactly one third (1667 providers; the adversary count rounds up), hold probability 0.99, withholding adversary: security failure 2.3 × 10⁻¹⁰, liveness failure 7.1 × 10⁻⁷, both reproduced under exact integer arithmetic. Above f = 1/2 no threshold satisfies both bounds at any sample size. The calculator, simulator and verification suite live on the research repository'smempool-pull-confirmationbranch;make verifychecks the closed forms against the simulated protocol andmake evaluatescores any candidate triple.Accepted residual leak
Pull creates an observable of its own: a query tells the queried provider that the querier holds the named transactions. This yields only the first link of the tagging chain. Every node queries about every transaction it holds, continuously from admission, so query behaviour is uncorrelated with leadership and carries no stake signal — and both of those properties are normative for exactly that reason. Routing queries through Blend, or mixing in cover queries, would shrink the leak further and is left open.
Costs
Confirmation adds roughly twenty-five seconds from submission to inclusion eligibility (
PULL_DELAYplus typically seven rounds atPULL_INTERVAL), paid in parallel by every node holding the transaction. Query traffic is 32 messages per node per round, batched over up toPULL_MAX_BATCHtransactions, so the cost does not scale with the transaction rate. The assumptions still owed evidence are recorded in Open Issues — most importantly thatPULL_DELAY, and therefore the hold probability the calibration takes as input, has never been measured against real gossip propagation.Details
The specification is the single source of truth; the entries below name each mechanism in review order.
1. The pull exchange
The witness is a hash over the querier's nonce and the provider's cached per-transaction body commitments. It stops an uninformed provider from answering "yes", and it is taken over cached commitments rather than over bodies so that a 32-byte query entry can never compel work proportional to a 2 MiB transaction. Acceptance requires the responder to be the sampled provider — activity judged against the snapshot the query sampled from, never re-judged later — a matching outstanding nonce, a valid signature, and a witness the querier reproduces from its own copies.
Two rules protect the measurement itself: a negative answer must not transfer the transaction, or pull would confirm whatever it asked about; and the sample must be drawn from local randomness, since a chain-derived seed would tell an adversary whom a node will ask.
2. Sampling, exclusions and the threshold
Each round samples
PULL_SAMPLE_SIZEproviders excluding only the node itself; each query then names the batch transactions for which that provider is not already excluded — not in that transaction'squeried, and not among the peers it arrived from. Exclusion is per transaction, not per batch: excluding the batch-wide union would grow monotonically, cover the whole declaration set within a few hundred rounds, and halt confirmation for everything on the node.3. The confirmation gate
Only confirmed transactions may be selected into a proposal. Confirmation never enters applicability, retirement or reference resolution — an unconfirmed transaction stays pending, stays gossiped, and still resolves another leader's reference to it.
4. State and persistence
Per-transaction pull state (
commitment,attesters,queried,received_from,rounds) plus an ephemeral outstanding-nonce table that a restart deliberately voids. All of it is persisted for every pending transaction, confirmed ones included — confirmed status is derived from the attester set, so persisting only unconfirmed transactions would strip confirmed ones of the evidence that made them confirmed — and all of it is cleared at retirement.Implementation
PULL_PROTOCOLrequest/response behaviour, query and response structures, and witness computation over cached body commitmentscommitment,attesters,queried,received_from,rounds, outstanding-nonce table) and the round schedulerPULL_DELAY, and re-run the threshold calibration with the measured hold probabilityAffected Specifications
PULL_PROTOCOLis a new libp2p protocol that should be registered there. Flagged for reviewer attention.🤖 Generated with Claude Code