Skip to content

RFC Bedrock: Mempool — Transaction Maturity - #415

Draft
madxor wants to merge 1 commit into
Bedrock-RFC-Mempoolfrom
Bedrock-RFC-Mempool-Maturity
Draft

RFC Bedrock: Mempool — Transaction Maturity#415
madxor wants to merge 1 commit into
Bedrock-RFC-Mempoolfrom
Bedrock-RFC-Mempool-Maturity

Conversation

@madxor

@madxor madxor commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

[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.

# Priority Document / Change What to look for
1 Critical Start hereThe Pull Exchange The new mechanism. Verify it cannot be gamed: the witness binds an answer to the transaction body, a negative answer must not transfer the transaction, and a response is accepted only against a nonce the querier itself chose.
2 Critical Start hereSampling and the Threshold The security argument, and the one place a subtle error is fatal: exclusions are per transaction, not per batch. Check the two-sided bound and that the total sample is treated as a security parameter rather than a budget.
3 Critical Confirmation Gates Inclusion, Never Resolution Confirmation is private state. Verify it never reaches retirement or reference resolution, so sampling luck cannot diverge one node's pool from another's.
4 High Who May Attest The attester set is the active SDP snapshot: stake-backed, on-chain, and per-declaration rather than per-unit-stake, which is what lets attesters sign in the clear.
5 High Block Building View The gate itself: only confirmed transactions may be selected, and nothing else about block building changes.
6 Medium Why the Threshold Is What It Is and Confirmation Latency The calibrated triple and the cost it buys. Reproducible with the calculator linked in Discussion.
7 Medium Privacy Considerations The residual leak pull itself creates, and the two normative properties that keep it from restoring the attack.
8 Low Denial of Service Considerations The pull protocol's exposure: constant work per query, bounded amplification, rate limiting.

Status tracker

  • 🚧 Raw (make sure that all below is completed)
    • Template applied
    • Authors filled in
    • Authors agree on the RFC content
  • 📘 Draft (make sure that all below is completed)
    • All dependent specifications added (Notion backlinks checked)
    • Specifications to deprecate added, if applicable
    • Specifications to retire added, if applicable
    • Research Lead assigned, or Project Lead assigned if the Research Lead is an author
    • Relevant Research Domain Experts assigned (cannot be authors)
  • ⚙️ Verified (make sure that all below is completed)
    • Researchers’ comments addressed
    • All logical changes documented
    • All Research reviewers approve the latest version
    • Engineering Lead assigned
    • Relevant Engineering Domain Experts assigned
  • 🔀 Merged (make sure that all below is completed)
    • Engineers’ comments addressed
    • Every change added to the change log
    • All Engineering reviewers approve the latest version
    • Specification version numbers assigned
    • Implementation reviewed and merged
    • Branch updated to master and all conflicts resolved
    • PR merged

Change log

Revision Description Date
v1 Initial PR description 2026-08-24

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_CONFIRMATIONS attestations 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's mempool-pull-confirmation branch; make verify checks the closed forms against the simulated protocol and make evaluate scores 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_DELAY plus typically seven rounds at PULL_INTERVAL), paid in parallel by every node holding the transaction. Query traffic is 32 messages per node per round, batched over up to PULL_MAX_BATCH transactions, so the cost does not scale with the transaction rate. The assumptions still owed evidence are recorded in Open Issues — most importantly that PULL_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

class PullQuery:
    nonce: bytes32                  # fresh, chosen by the querier
    tx_hashes: list[TxHash]         # up to PULL_MAX_BATCH entries

class PullResponse:
    nonce: bytes32
    held: bitmap                    # one bit per queried hash
    witness: hash                   # proof of possession over the held entries
    provider_id: Ed25519PublicKey
    signature: Ed25519Signature

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_SIZE providers excluding only the node itself; each query then names the batch transactions for which that provider is not already excluded — not in that transaction's queried, 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

  • Implement the pull protocol: the PULL_PROTOCOL request/response behaviour, query and response structures, and witness computation over cached body commitments
  • Add confirmation state to the tx mempool (commitment, attesters, queried, received_from, rounds, outstanding-nonce table) and the round scheduler
  • Implement per-transaction sampling exclusions, and confirm no code path excludes the batch-wide union
  • Gate block-building selection on confirmed status, leaving applicability and retirement confirmation-blind
  • Serve pull queries: per-peer rate limiting, snapshot-membership checks, constant-time witness answers
  • Extend mempool persistence with body commitments and pull state
  • Expose confirmed/unconfirmed in the mempool status and metrics endpoints
  • Measure mempool-topic gossip propagation, calibrate PULL_DELAY, and re-run the threshold calibration with the measured hold probability
  • Add or extend tests that exercise the change (witness verification, negative answers, exclusion bookkeeping, restart recovery of attestations, the confirmation gate)
  • Verify the implementation matches this specification

Affected Specifications

Specification Status Note
Mempool Modified Adds the pull confirmation mechanism and the confirmation gate on block building.
Service Declaration Protocol Unchanged, but newly depended upon: the active snapshot is the attester set. Flagged for reviewer attention.
P2P Network Unchanged, but PULL_PROTOCOL is a new libp2p protocol that should be registered there. Flagged for reviewer attention.

🤖 Generated with Claude Code

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant