For the complete documentation index, see llms.txt. This page is also available as Markdown.

Resource Limits

MegaETH per-transaction and per-block resource limits — compute gas, data size, KV updates, and state growth ceilings with enforcement semantics.

This page specifies the limits MegaETH enforces on transaction execution and block construction. It defines the limit set, the split between pre-execution and runtime enforcement, and the outcomes of transaction-level and block-level violations.

Motivation

The transaction gas_limit alone is insufficient to protect MegaETH from resource-heavy transactions. A transaction may remain within its total gas budget while still producing excessive state growth, too many key-value updates, or too much execution data.

MegaETH therefore enforces independent resource ceilings in addition to the standard gas limit. Without those ceilings, a transaction could remain valid under gas accounting while still imposing disproportionate execution, storage, or networking costs on nodes.

Resource limits also need deterministic block-building semantics. Implementations must agree on which transactions are rejected permanently, which are skipped for the current block, which are included as failed, and when the last transaction that exceeds a block-level runtime limit is still allowed.

Specification

The named constants referenced in this section are defined later in Constants.

Overview

MegaETH enforces seven distinct resource limits:

  1. standard gas limit,

  2. transaction encoded size,

  3. data-availability size,

  4. compute gas,

  5. data size,

  6. KV updates,

  7. state growth.

Limits 1–3 are checked before execution. Limits 4–7 are enforced during execution and accumulated at block level after execution.

For exact counting rules of data size, KV updates, and state growth, see Resource Accounting. For compute gas — the measurement window, metering classes, recording sites, and exceed behavior — see Compute Gas Accounting. For the relationship between total gas, compute gas, and storage gas, see Dual Gas Model.

Limit Set

A node MUST enforce the following limits:

Resource
Phase
Transaction Limit
Block Limit

Gas Limit

Pre-execution

Sequencer-configured

block.gasLimit from block header

Transaction Size

Pre-execution

Sequencer-configured

Sequencer-configured

DA Size

Pre-execution

Sequencer-configured

Sequencer-configured

Compute Gas

Runtime

TX_COMPUTE_GAS_LIMIT

No separate limit

Data Size

Runtime

TX_DATA_LIMIT

BLOCK_DATA_LIMIT

KV Updates

Runtime

TX_KV_UPDATE_LIMIT

BLOCK_KV_UPDATE_LIMIT

State Growth

Runtime

TX_STATE_GROWTH_LIMIT

BLOCK_STATE_GROWTH_LIMIT

The absence of a separate block-level compute gas limit means that cumulative block compute gas is bounded only indirectly by the block gas limit.

Pre-Execution Limits

Standard Gas Limit

A node MUST apply standard Ethereum gas-limit semantics. The transaction's gas_limit field MUST fit within both the sequencer-configured per-transaction gas cap and the remaining block gas budget from the block header.

Transaction Size

A node MUST check the EIP-2718 encoded transaction size before execution. Transactions that exceed the configured transaction-size limit MUST be rejected permanently. Transactions that fit the transaction-level size limit but would cause the block's cumulative encoded transaction size to exceed the configured block-level size limit MUST be skipped for the current block.

DA Size

A node MUST check the compressed data-availability size of each non-deposit transaction before execution. Transactions that exceed the configured transaction-level DA size limit MUST be rejected permanently. Transactions that fit the transaction-level DA size limit but would cause the block's cumulative DA size to exceed the configured block-level DA size limit MUST be skipped for the current block.

Deposit transactions MUST be exempt from DA size limit checks. Their DA size MAY still be tracked for monitoring purposes.

Runtime Transaction-Level Limits

A node MUST enforce the following runtime transaction-level limits during execution:

  • TX_COMPUTE_GAS_LIMIT

  • TX_DATA_LIMIT

  • TX_KV_UPDATE_LIMIT

  • TX_STATE_GROWTH_LIMIT

If any runtime transaction-level limit is exceeded during execution, the transaction MUST:

  1. halt,

  2. preserve its remaining gas,

  3. produce a failed receipt (status = 0),

  4. and still be included in the block.

The failed transaction's actual resource usage MUST still count toward the block's cumulative resource counters.

When a single limit check finds more than one dimension over its limit, the reported dimension MUST be the first in the fixed order: data size, key-value updates, compute gas, state growth.

Step 2 applies to every transaction-level exceed, including the one crossed while recording the KeylessDeploy dispatch overhead. The rescued amount is excluded from the receipt's gas_used and refunded to the sender. See Keyless Deploy Exceed.

The four runtime transaction-level limits MUST NOT be enforced against a system-originated transaction. The node MUST still record such a transaction's resource usage; only the per-transaction halt decision is suppressed. The transaction's standard EVM gas_limit — for the pre-block system calls, floored at 30,000,000 — remains the only bound that can halt it.

Precompile Compute-Gas Bound

A precompile invocation's compute-gas consumption MUST be bounded by the compute gas remaining in the current call frame. A node MUST cap the gas forwarded into a precompile at the minimum of the caller-supplied call gas limit and the remaining compute-gas budget, so a precompile cannot consume more compute gas than remains. A precompile whose minimum cost exceeds that cap MUST fail without performing its computation, halting with PrecompileOOG. On successful or reverting precompile returns, the caller's gas-refund accounting MUST reflect the originally forwarded gas limit minus the precompile's actual spent gas, so the cap does not alter the caller's observed refund on non-halting returns.

Runtime Block-Level Limits

A node MUST maintain cumulative block counters for:

  • data size,

  • KV updates,

  • state growth,

  • and compute gas.

The node MUST update those cumulative counters after transaction execution.

For data size, KV updates, and state growth, the first transaction that causes the cumulative block usage to meet or exceed the block-level limit MUST still be included in the block. Subsequent candidate transactions MUST be skipped before execution once the block is already at or above the corresponding block-level runtime limit.

Although block compute gas usage MAY be tracked, the protocol does not impose a separate block-level compute gas cap.

Two-Phase Block Building Workflow

When constructing a block, a node or sequencer MUST process candidate transactions in the following order:

  1. Perform pre-execution validation.

  2. If a transaction violates a transaction-level pre-execution limit, reject it permanently.

  3. If a transaction would exceed a block-level pre-execution limit, skip it for the current block.

  4. If any stable block-level runtime limit is already reached or exceeded from prior included transactions, skip later candidate transactions that depend on that resource category.

  5. Execute the transaction.

  6. If a runtime transaction-level limit is exceeded, include the transaction as failed.

  7. Update cumulative block counters with the transaction's actual resource usage.

  8. Include the transaction in the block.

Outcomes

Outcome
Cause
Receipt
Block Impact

Success

Transaction completes within all applicable limits

status = 1

Counts toward all relevant block counters

Failed

Runtime transaction-level limit exceeded

status = 0

Still included and counts toward all relevant block counters

Skipped

Current block cannot admit the transaction without violating a block-level limit

No receipt

Not included; may be reconsidered in a later block

Rejected

Transaction-level pre-execution limit exceeded

No receipt

Permanently invalid

Per-Call-Frame Runtime Budgets

Each call frame receives a bounded share of the remaining budget for compute gas, data size, KV updates, and state growth. Each inner call frame receives remaining × FRAME_LIMIT_NUMERATOR / FRAME_LIMIT_DENOMINATOR of its parent call frame's remaining budget. These budgets are system-enforced — the calling contract cannot directly control them. Only total gas (the standard EVM gas parameter in CALL-like opcodes) remains under direct contract control. If a child call frame exceeds its local budget, it MUST revert with MegaLimitExceeded(uint8 kind, uint64 limit). The parent call frame MAY continue execution.

The top-level call frame's budget MUST equal the transaction limit minus any resource usage already recorded before the first frame begins. These deductions include transaction-only intrinsic usage and any DB-dependent pre-execution usage that is resolved before the first frame starts. Each resource dimension deducts only the pre-frame items relevant to it:

  • Data size — base transaction data (110 bytes), calldata byte length, access-list entry sizes, EIP-7702 authorization records, applied EIP-7702 authority account updates, and the caller account update.

  • KV updates — applied EIP-7702 authority account updates and the caller account update.

  • State growth — applied EIP-7702 authorizations that create previously non-existent authority accounts.

  • Compute gas — standard EVM transaction intrinsic gas, enumerated normatively in Transaction Intrinsic Gas.

These deductions ensure that pre-frame costs reduce the budget available to the first call frame, preventing transactions from front-loading pre-frame usage to escape per-frame limits.

Authority State Growth Resolution

A node MUST resolve the state-growth contribution of EIP-7702 authorizations during transaction validation, after the inherited intrinsic-gas validation and before the final gas-limit and fee-affordability checks — the ones that see the dynamic SALT account-creation gas this scan folds in. A transaction whose standard intrinsic gas already exceeds its own gas limit is therefore rejected by the inherited validation without the authority accounts being read at all. The set of authorities and the per-authority effects are derived from the same applied-authorization scan that drives the data-size and KV-update narrowing in Resource Accounting.

Dynamic Authority Account-Creation Gas

For each applied EIP-7702 authorization that materializes a previously non-existent authority account, a node MUST charge dynamic new-account storage gas for that authority using the same SALT bucket pricing as other new-account materialization paths. This charge MUST be folded into the transaction's intrinsic gas so that it is deducted before the first call frame and enforced against the gas limit and fee affordability. A node MUST NOT charge this new-account gas twice when a value-transferring call materializes the same account that an applied authorization materializes.

Authorization List Skip on Pre-Frame Limit Exceed

A type-4 transaction's authorization list is applied — each applied authority's account written — during pre-execution, before the transaction's first call frame begins. A per-transaction limit that pre-frame accounting has already exceeded still halts the transaction at the first frame boundary, but a frame-boundary halt does not roll back writes performed before that frame began. Without a guard, a transaction halting on the state-growth limit could commit more net-new authority accounts than the per-transaction state-growth cap allows.

For a type-4 transaction, if any per-transaction resource limit has already been exceeded at the point where the authorization list would be applied, a node MUST NOT apply any authorization in the list. The skip is all-or-nothing: once any per-transaction limit is exceeded — whether by the authorizations themselves or by the transaction's other pre-frame usage, such as calldata — no authorization in the list is applied, including ones that would fit under the limit. The transaction MUST still halt at the same frame boundary with the same limit-exceeded halt reason it would have reached without the skip. Because no authorization is applied, an already-existing authority forgoes the per-authorization refund it would otherwise earn.

Constants

Constant
Value
Description

TX_COMPUTE_GAS_LIMIT

200,000,000

Maximum compute gas per transaction

TX_DATA_LIMIT

13,107,200

Maximum data size per transaction

BLOCK_DATA_LIMIT

13,107,200

Maximum cumulative block data size

TX_KV_UPDATE_LIMIT

500,000

Maximum KV updates per transaction

BLOCK_KV_UPDATE_LIMIT

500,000

Maximum cumulative block KV updates

TX_STATE_GROWTH_LIMIT

1,000

Maximum state growth per transaction

BLOCK_STATE_GROWTH_LIMIT

1,000

Maximum cumulative block state growth

FRAME_LIMIT_NUMERATOR

98

Numerator of per-call-frame budget forwarding

FRAME_LIMIT_DENOMINATOR

100

Denominator of per-call-frame budget forwarding

Rationale

Why split limits into pre-execution and runtime phases? Gas limit, encoded transaction size, and DA size are known before execution and can be checked cheaply. Compute gas, data size, KV updates, and state growth depend on actual execution and therefore cannot be known precisely in advance.

Why include failed runtime-limited transactions? The node must execute a transaction to know whether it exceeds a runtime limit. If such transactions were excluded from the block, an attacker could force repeated expensive executions at no cost. Including failed transactions ensures that the sender pays for the resources consumed.

Why allow the first transaction to push a block over a runtime block limit? Runtime block limits are known only after execution. Allowing the first over-limit transaction to be included maximizes block utilization while preserving deterministic block-building behavior for later transactions.

Why no separate stable block-level compute gas limit? Cumulative block compute gas is already indirectly constrained by the block gas limit. The stable protocol therefore does not need a second independent block-level compute gas ceiling.

Why cap precompile gas at the remaining compute-gas budget? A precompile whose natural cost exceeds the remaining compute-gas budget would otherwise execute fully and overshoot the budget, with the overshoot detected only after the work was already performed. Capping the forwarded gas at the remaining compute-gas budget converts that overshoot into a fail-fast PrecompileOOG before the computation runs, keeping the compute-gas limit enforceable for precompile work as well as ordinary opcodes.

Security Considerations

If a transaction that exceeds a runtime limit is excluded from the block rather than included as failed, an attacker can force the sequencer to execute expensive but failing transactions at no cost — the sender never pays because the transaction is dropped. Including failed transactions ensures the sender always pays for consumed resources.

Spec History

  • MiniRex introduced compute gas, data size, and KV update limits, with transaction-level data and KV limits set to 25% of the corresponding block limits.

  • Rex changed the stable runtime transaction-level limits to TX_COMPUTE_GAS_LIMIT = 200,000,000, TX_DATA_LIMIT = 13,107,200, TX_KV_UPDATE_LIMIT = 500,000, and introduced state-growth limits.

  • Rex3 retained the stable resource-limit set.

  • Rex4 — added per-call-frame runtime budgets; intrinsic resource costs (always deducted before execution) are now reflected in the top-level frame budget before it is forwarded to child frames.

  • Rex5 — bounded a precompile invocation's compute-gas consumption by the remaining compute-gas budget, failing the precompile with PrecompileOOG rather than letting it overshoot the budget.

  • Rex6 — moved EIP-7702 authority state-growth resolution from pre-execution (after the caller nonce bump) to validation, and added dynamic SALT account-creation gas for each net-new applied authority to the pre-frame intrinsic gas deduction; removed the keyless-deploy exception to gas preservation, so remaining gas is now rescued on every transaction-level exceed; and stopped enforcing the four runtime transaction-level limits against system-originated transactions, whose usage is still recorded.

Last updated