EIP-8131 - Add Auth Data to EIP-7623 Floor

Created 2025-01-21
Status Draft
Category Core
Type Standards Track
Authors
Requires

Abstract

This EIP includes EIP-7702 authorization data in the EIP-7623 floor calculation, preventing circumvention of floor pricing through authorization lists. This effectively reduces the worst-case block size by ~16%.

Motivation

EIP-7702 authorization tuples are priced for execution (PER_EMPTY_ACCOUNT_COST = 25,000 gas per authorization) but do not contribute to the EIP-7623 floor calculation.

Under EIP-7976 floor pricing, this enables circumventing the floor by combining all-non-zero calldata with authorization data at a 25%/75% (calldata/auths) gas split.

Specification

Parameter Value Source
TOTAL_COST_FLOOR_PER_TOKEN 16 EIP-7976
FLOOR_COST_PER_AUTH 6464 101 bytes × 4 tokens × 16 gas
PER_EMPTY_ACCOUNT_COST 25000 EIP-7702

The EIP-7623 floor calculation is modified to include authorization data:

tokens_in_calldata = zero_bytes_in_calldata + nonzero_bytes_in_calldata * 4

floor_gas = (
    TX_BASE_COST
    + TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata
    + FLOOR_COST_PER_AUTH * num_authorizations
)

The gas used calculation becomes:

tx.gasUsed = (
    21000
    +
    max(
        STANDARD_TOKEN_COST * tokens_in_calldata
        + execution_gas_used
        + isContractCreation * (32000 + INITCODE_WORD_COST * words(calldata))
        + access_list_cost
        + PER_EMPTY_ACCOUNT_COST * num_authorizations,
        TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata
        + FLOOR_COST_PER_AUTH * num_authorizations
    )
)

A transaction is invalid if its gas_limit is less than tx.gasUsed evaluated with execution_gas_used = 0.

Rationale

Flat Cost Per Authorization

Each authorization is charged a flat FLOOR_COST_PER_AUTH = 6464 gas toward the floor, derived from:

This conservative approach avoids byte-level zero/non-zero accounting while ensuring authorization data is properly reflected in the floor calculation.

Worst-Case Reduction

At the floor under EIP-7976 every byte costs 64 gas regardless of value, so the optimal attacker uses all-non-zero calldata (incompressible under snappy) at the standard rate of 16 gas/byte and spends the remainder on auths. The break-even split is (64 − 16) / 64 = 75% on auths and 25% on calldata. At a 60M gas limit:

# pre-EIP-8131 worst case (auth bypass, all-non-zero cd):
(0.75 * 60_000_000 * 101 / 25_000 + 0.25 * 60_000_000 / 16) / 1024**2    1.067 MB

# post-EIP-8131 worst case (pure floor, all-non-zero cd):
60_000_000 / 64 / 1024**2                                                0.894 MB

# reduction: 1 − 0.894 / 1.067 ≈ 16%

Floor-Only Modification

Authorization costs are added to the floor calculation only, not to intrinsic gas. This differs from EIP-7981 (access lists) because:

With this change:

Backwards Compatibility

This is a backwards incompatible gas repricing that requires a scheduled network upgrade.

Requires updates to gas estimation in wallets and nodes. Normal usage patterns remain largely unaffected since authorization execution cost typically dominates the floor contribution.

Test Cases

Case 1: Transaction with Authorizations Only

Old floor: 21,000 gas New floor: 21,000 + 10 × 6,464 = 85,640 gas Intrinsic: 21,000 + 10 × 25,000 = 271,000 gas Result: Pay intrinsic (271,000) — execution dominates, EIP-8131 has no effect

Case 2: Bypass Attempt (Now Blocked)

Old floor: 21,000 + 100,000 × 64 = 6,421,000 gas New floor: 21,000 + 100,000 × 64 + 225 × 6,464 = 7,875,400 gas Intrinsic: 21,000 + 100,000 × 16 + 225 × 25,000 = 7,246,000 gas Pre-EIP-8131: max(7,246,000, 6,421,000) = 7,246,000 (intrinsic wins, floor bypassed) Post-EIP-8131: max(7,246,000, 7,875,400) = 7,875,400 (floor wins, bypass blocked)

Reference Implementation

FLOOR_COST_PER_AUTH = 6464  # 101 bytes * 4 tokens/byte * 16 gas/token


def calculate_intrinsic_cost(tx: Transaction) -> Tuple[Uint, Uint]:
    """
    Calculate intrinsic gas cost and floor gas cost.
    Returns (intrinsic_gas, floor_gas).
    """
    # Calldata tokens
    calldata_zero = sum(1 for b in tx.data if b == 0)
    tokens_in_calldata = Uint(calldata_zero + (len(tx.data) - calldata_zero) * 4)

    # Authorization costs
    num_authorizations = Uint(0)
    auth_exec_cost = Uint(0)
    if isinstance(tx, SetCodeTransaction):
        num_authorizations = Uint(len(tx.authorizations))
        auth_exec_cost = PER_EMPTY_ACCOUNT_COST * num_authorizations

    # Floor: calldata + flat cost per authorization
    floor_gas = (
        TX_BASE_COST
        + tokens_in_calldata * TOTAL_COST_FLOOR_PER_TOKEN
        + num_authorizations * FLOOR_COST_PER_AUTH
    )

    # Intrinsic: calldata + create + access list + authorization execution cost
    calldata_cost = tokens_in_calldata * STANDARD_TOKEN_COST
    create_cost = TX_CREATE_COST + init_code_cost(tx.data) if is_create(tx) else 0
    intrinsic_gas = (
        TX_BASE_COST
        + calldata_cost
        + create_cost
        + access_list_cost
        + auth_exec_cost
    )

    return intrinsic_gas, floor_gas

Security Considerations

This EIP closes a loophole that allows circumventing EIP-7623 floor pricing. Without this fix, adversaries can achieve larger blocks than intended by combining calldata with authorization data.

Interaction with EIP-7981

If EIP-7981 is also adopted, both EIPs work together: access list tokens and authorization tokens are both included in the floor calculation. There are no conflicts.

Copyright

Copyright and related rights waived via CC0.