Mempool Account Transaction Capacity from Historical Activity (MATCHA)


s/o Toni for the artwork

by Thomas, based on ideas and discussions with Vitalik and Toni

Introduction

Frame Transactions (EIP-8141) allow applications to define their own validation and gas payment logic. To keep this programmable validation safe in the public mempool, EIP-8141 limits the validation work for each transaction through MAX_VERIFY_GAS and normally admits at most one pending Frame Transaction per sender. Clients also track validation dependencies so they only revalidate transactions whose dependencies may have changed after a new canonical block.

Keyed Nonces for Frame Transactions (EIP-8250) gives transactions independent nonce keys. This matters for privacy applications, where many users share one sender so their transactions do not expose separate public accounts or fragment the anonymity set. By removing nonce conflicts between unrelated spends, EIP-8250 makes it possible for a future mempool policy to admit several transactions from the same sender.

Relaxing the one transaction limit creates a new DoS vector. An attacker could deploy a fake privacy application and submit many valid spends with different nonce keys, all of which read the same validation setting. A single onchain change to that setting could invalidate the entire pending set and force clients to revalidate and remove every spend. By restoring the setting and resubmitting the spends, the attacker could repeat the attack at little onchain cost relative to the mempool work it creates.

Admitting several transactions also creates a second problem. A malicious user could target an honest privacy application by submitting many valid transactions with low fees. These transactions consume the shared sender’s capacity and prevent other users from entering the mempool. They may remain pending or leave without inclusion, in which case no fee is paid, so fee bids alone cannot provide a hard bound.

In this post, we introduce MATCHA, a local mempool policy for admitting several transactions from one sender while bounding the resulting DoS risk. Each admission beyond the first spends capacity called width, assigned to that sender. A sender earns new width only from the actual gas used by its Frame Transactions in finalized blocks, and spent width is not returned when a transaction leaves the mempool. This bounds repeated mass invalidation.

We also present how the proposed FOCIL extension for Frame Transactions (EIP-8369) would make valid transaction flooding riskier by increasing the chance that the attacker’s transactions are included and the attacker pays for their gas. Clients could strengthen this deterrent with an optional minimum remaining validity period or linearly increasing priority fees.

Goals

The goal of MATCHA is to let clients admit several Frame Transactions with independent EIP-8250 nonce keys from one shared sender, without whitelisting any application, paymaster, verifier, or proof system.

MATCHA must protect the public mempool even if the application is malicious.

Protect the mempool

  • Bound total mempool resource use. The client caps pending transaction data, dependency indexes, signature and proof verification, state reads, revalidation, and cleanup. It may also apply lower limits to each peer, but adding peers or sender addresses does not increase the client’s total limits.

  • Prevent nonce conflicts and double counting the payer balance. No two distinct pending transactions may use the same (sender, nonce_key). The total maximum cost reserved by pending transactions using one payer may not exceed that payer’s balance at the current head.

  • Bound repeated mass invalidation. Admitting an additional transaction, replacing it with different bytes, or rerunning its validation prefix spends width. Inclusion, invalidation, removal, expiry, or reorg does not return that width. Once it runs out, further additional admissions require new finalized activity from the sender.

  • Deter valid transactions that consume shared capacity. FOCIL for Frame Transactions increases the chance that a transaction which remains eligible is included and its payer is charged. Clients may strengthen this deterrent by rejecting transactions close to a predictable expiry or requiring linearly higher fees as more transactions remain pending. Importantly, these policies do not guarantee inclusion or payment, so width and the client’s total limits remain the hard DoS bound.

Note: MATCHA protects mempool resources, not application funds or fairness between users. Its FOCIL deterrence assumes that an honest application makes each user authorize and pay for the gas of their own transaction. Application solvency, settlement safety, and proof design are separate concerns.

How it works

Under EIP-8141 mempool rules, a client normally keeps at most one pending Frame Transaction per sender. MATCHA keeps this transaction as the baseline and may admit additional transactions when they use EIP-8250 nonce keys and satisfy the MATCHA admission profile. The EIP-8141 baseline spends no width, but every additional transaction does. If the baseline leaves while other transactions remain pending, none of them becomes the baseline; it becomes available again only when the sender’s pending set is empty. Frame Transactions that do not satisfy MATCHA continue to follow the “one transaction per sender” policy.

The client uses width only after the validation prefix succeeds and the transaction can be attributed to its sender and payer. All work and storage remain subject to limits shared by the whole client, including transaction data, signature and proof verification, state access, stored records, revalidation, and cleanup. When a limit is reached, the client rejects or defers further work.

Rejection under MATCHA does not make a transaction invalid for inclusion in a block or excuse its omission under FOCIL.

MATCHA does not increase EIP-8141’s validation budget. An application with a larger proof must fit the active budget or use a separately defined public mempool profile.

width

width is the capacity available to a sender for pending Frame Transactions beyond the EIP-8141 baseline. A sender starts with no width and earns it from the actual gas used by its Frame Transactions in newly finalized blocks, up to a local cap. Each finalized block is credited only once:

width[sender] = min(
    width_cap,
    width[sender] + newly_finalized_gas[sender]
)

Each transaction has a charge based on the work budgeted to admit it. admission_gas(tx) covers transaction data, signatures, EIP-8250 nonce checks, the checks in Recent Roots for Frame Transactions (EIP-8272), and EIP-8141 execution through payment approval. For frame execution, it uses the declared execution gas limits, so the stored charge also covers a later revalidation that takes more work than the initial simulation. It excludes later application execution. State gas is bounded separately and is excluded because it does not measure validation work. A safety_factor covers client work that EVM gas does not measure accurately:

charge(tx) = ceil(safety_factor * admission_gas(tx))

The baseline spends no width. Before spending width, an additional transaction must pass the ordinary admission checks and be valid for a child of the current head, including max_fee_per_gas >= next_base_fee. Its sender must then have enough width, and the client deducts the transaction’s charge:

require width[sender] >= charge(tx)
width[sender] = width[sender] - charge(tx)

The remaining rules are:

  • Duplicates, replacements, and revalidation. Exact duplicates of a transaction already pending share one pool record and spend no width. Replacing the baseline also spends no width. Replacing an additional transaction with different bytes spends another charge. Rerunning its validation prefix spends its stored charge before the work begins. If the sender cannot cover that charge, the client removes the transaction without rerunning the prefix.

  • No refunds and local lifetime. Spent width is not returned when a transaction is included, invalidated, or removed. Every pending transaction is removed after a maximum local lifetime, without affecting its onchain validity. A removed transaction must pass admission again, including after a reorg, and spends another charge if it is additional. Rebuilding spends more width; once it runs out, further additional admissions require new finalized activity from the sender.

  • Nonce keys and payer balance. No two distinct pending transactions may use the same (sender, nonce_key). The client reserves each transaction’s maximum cost against the payer’s balance at the current head. After a new head, affected transactions remain unavailable for block construction until their combined reservations fit the new balance. These checks exist only in the client’s mempool.

A change to the payer balance does not by itself require rerunning validation. The client can reuse its earlier result if it confirms that validation would run with the same code and inputs. It must still check nonce keys, recent roots, expiry, fees and the payer’s total reservations at the new head. All these checks remain subject to the client’s resource limits.

Protection against width draining

Irreversible width bounds repeated mempool work, but an attacker can still consume an honest application’s available capacity by submitting valid transactions with very low fees to block concurrent admissions. If the pending set becomes empty, the EIP-8141 baseline becomes available again, but further additional admissions must wait for new finalized activity if the sender has exhausted its width.

MATCHA relies on a consensus extension implementing the FOCIL reference model in EIP-8369 to make this attack risky. If an honest includer selects a transaction eligible under that extension and the inclusion list reaches enough attesters, the builder must include it unless the omission checks establish that it is invalid or does not fit. EIP-8369 evaluates these checks at a position claimed by the builder. In an honest privacy application, inclusion charges the transaction’s user for its gas, and finalization earns fresh width for the shared sender. An additional transaction spends width again whenever it is replaced or its validation is rerun. Only the version that is included earns new width after finalization, so it may replenish less capacity than was spent along the way.

This deterrent is conditional: under Fork-choice enforced Inclusion Lists (FOCIL) (EIP-7805), transaction selection remains with the includer, inclusion lists have finite capacity, and a transaction can become invalid or fee invalid before inclusion. The hard DoS bound therefore remains spent width and the client’s total resource limits, but we think in practice relying on FOCIL might be enough to deter these width draining attacks.

There are also ideas clients could use to strengthen this deterrent with one or both of the following optional policies:

  • Minimum period before expiry. A client may require an additional transaction’s EIP-8141 expiry and every EIP-8272 recent root to remain valid through a target slot chosen by local policy. The longer this period is, the more opportunities FOCIL has to include the transaction, increasing the chance that the attacker has to pay for it.

  • Linear fees using load. A client may also track load, the sum of the charge values of the additional transactions that remain pending. Each new additional transaction must offer a minimum effective priority fee that rises linearly with this load. The client chooses base_price, the starting fee floor. When all charges are equal, the floor is base_price for the first additional transaction, twice base_price for the next, then three times, and so on. When a transaction leaves the mempool, its charge is removed from load even though its spent width is not returned.

    This makes a transaction later in a large batch carry a higher fee offer, so including it can expose the attacker to a cost that grows with the batch. The rule also raises fees for honest users when their shared sender is busy and does not reserve capacity for individual users, so it remains optional and does not replace width as the hard DoS bound.

Next steps

The next step is to implement the core width policy in clients alongside FOCIL for Frame Transactions and test the two attacks MATCHA targets: repeated mass invalidation by a malicious application and width draining against an honest one, including repeated replacements before inclusion. These tests should calibrate the admission charge and capacity limits, measure how quickly eligible transactions are included during congestion, and determine whether FOCIL is sufficient on its own or whether a minimum validity period or linear fees using load justify their added complexity.

The tests should also measure honest throughput: including one transaction changes the shared payer balance and may trigger revalidation of the others before finalization replenishes width. We need to check whether ordinary activity can sustain useful concurrency, and when cheap dependency checks can avoid a full replay.