Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
7510de8
feat(l1): support bal-devnet-4 (bal@v5.7.0)
edg-l Apr 23, 2026
a1d1539
fix(l1): builder/validator parity for Amsterdam (EIP-7928/8037)
edg-l Apr 23, 2026
94d27a3
test(l1): builder/validator parity tests for Amsterdam BAL + 2D gas
edg-l Apr 23, 2026
0c92352
test(l1): bal-devnet-4 follow-up regression guards + doc polish
edg-l Apr 23, 2026
29ba39c
fix(l1): address PR #6521 bot review findings
edg-l Apr 23, 2026
490bdab
fix(l1): add missing is_system_call field in ef_tests Environment lit…
edg-l Apr 23, 2026
a41e941
fix(l1): pin EIP-8037 cost_per_state_byte to 1174 for bal-devnet-4
edg-l Apr 27, 2026
79d851f
chore(l1): bump Amsterdam fixtures to snøbal-devnet-4@v1.0.0
edg-l Apr 27, 2026
94cd56c
feat(l1): make amsterdam header default to slot = 0 if no data in gen…
Arkenan Apr 27, 2026
ad2109e
feat(l1): apply execution-apis PR 786 to engine FCU semantics
ilitteri Apr 25, 2026
27e2f23
fix(l1): gate REORG_DEPTH_LIMIT on finalized prefix per execution-api…
ilitteri Apr 30, 2026
ec55626
chore(l1): bump Amsterdam fixtures to bal@v6.0.0
edg-l Apr 30, 2026
e19974d
test(l1): add builder/validator parity check to blockchain ef-tests
edg-l Apr 30, 2026
efec9bc
chore(l1): bump Amsterdam fixtures to snobal-devnet-6@v1.0.0
ilitteri Apr 30, 2026
cbd6ffa
feat(l1): EIP-8037 PR #2689 — top-level/sub-frame ExceptionalHalt rec…
ilitteri Apr 30, 2026
19742bd
chore(l1): bump Amsterdam fixtures to snobal-devnet-6@v1.1.0
ilitteri Apr 30, 2026
9506a4d
EIP-8037 PR #2689 top-level halt: take max of spill_outstanding and r…
ilitteri Apr 30, 2026
106ffc1
test_runner: continue processing blocks after expected-exception. For…
ilitteri Apr 30, 2026
02cce39
EIP-8037 REVERT cascade: keep state_gas_credit_against_drain elevated…
ilitteri Apr 30, 2026
21f10af
EIP-8037 sub-frame ExceptionalHalt: reclassify credit-cancelled spill…
ilitteri Apr 30, 2026
19c1c8e
EIP-8037 CREATE TX top-halt: reclassify gross_spill - credit_against_…
ilitteri May 1, 2026
ccac538
fix(l1): fix gas mismatch between ethrex and eels (#6558)
ilitteri May 1, 2026
0e0deba
fix(l1): cap credit_against_drain by reclassified to preserve real sp…
qu0b May 1, 2026
246e3c5
EIP-8037 EIP-7702 set_delegation refund: subtract from state_gas_used…
ilitteri May 5, 2026
ba648c8
fix(l1): EIP-8037 CREATE sub-frame halt reclassify credit-cancelled s…
edg-l May 6, 2026
5c4edc2
chore(l1): bump state ef-tests + hive fixtures to snobal-devnet-6@v1.1.0
edg-l May 6, 2026
fa1f4b5
style(l1): cargo fmt eip8037_top_level_failure_tests
edg-l May 6, 2026
9893d5f
fix(l1): build payload on NewHeadAlreadyCanonical with attributes
edg-l May 6, 2026
2eb3d93
fix(l1): EIP-7702 set_delegation only credits state_gas_reservoir
edg-l May 6, 2026
c3a27eb
style(l1): fix clippy 1.91 doc + clone-on-Copy lints
edg-l May 6, 2026
7b4d7df
refactor(l1): drop dead EIP-8037 cost_per_state_byte plumbing
edg-l May 6, 2026
cefdf69
fix(l1): re-apply EIP-7702 set_delegation subtractions from state_gas…
edg-l May 6, 2026
9a2f856
chore(hive): bump Amsterdam BAL fixtures to snobal-devnet-6
edg-l May 7, 2026
ff221f0
fix(test): isolate zkevm fixtures from snobal in blockchain ef-tests
edg-l May 7, 2026
530dd47
chore(test): skip 74 bal-devnet-6 known-failing fixtures and surface …
edg-l May 7, 2026
3f422e4
chore(test): narrow stateless coverage to eip8025_optional_proofs on …
edg-l May 7, 2026
1cdb83b
docs: clarify stateless-narrowing scope in known_issues.md
edg-l May 7, 2026
c472cb1
docs: drop branch-scoped wording and self-referential tracking line
edg-l May 7, 2026
e7adb6e
chore(ci): exclude 8 Engine withdrawal Block Re-Org tests as known-flaky
edg-l May 7, 2026
4329d77
docs: collapse known_issues sections behind <details>/<summary>
edg-l May 7, 2026
35ebc94
chore(ci): rename KNOWN_FLAKY_TESTS → KNOWN_EXCLUDED_TESTS in hive re…
edg-l May 7, 2026
4664137
chore(ci): exclude 32 bal-devnet-6 Amsterdam fixtures from hive consu…
edg-l May 7, 2026
a44e75c
fix(l1): EIP-8037 top-halt drop drain term to fix nested-halt double-…
edg-l May 8, 2026
2496c2b
test(l1): drop EIP-7708/7976/7981/8037 unit tests covered by EELS ef-…
edg-l May 11, 2026
68107af
test(l1): drop builder/validator parity scaffolding from this PR
edg-l May 11, 2026
4783fb2
fix(test): restore main's EIP-7708 unit tests over-aggressively trimmed
edg-l May 11, 2026
ee7764b
fix(l1): scope -38006 TooDeepReorg to state-retention cap, not finali…
edg-l May 11, 2026
aa8cb9b
fix(l1): EIP-7702 set_delegation matches bal-devnet-6 spec exactly
edg-l May 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/config/hive/amsterdam.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Amsterdam (BAL) hive test configuration
# Pinned from ethereum/execution-specs devnets/bal/3 @ 2026-04-14
fixtures: https://github.com/ethereum/execution-spec-tests/releases/download/bal@v5.6.1/fixtures_bal.tar.gz
eels_commit: 5c6e20abf3586f52d9e58393203ca07f2d0151fe
# Pinned to snobal-devnet-6@v1.1.0
fixtures: https://github.com/ethereum/execution-spec-tests/releases/download/snobal-devnet-6%40v1.1.0/fixtures_snobal-devnet-6.tar.gz
eels_commit: e87390b69ca5113f8f99db81dae7e4d6a8420342
78 changes: 62 additions & 16 deletions .github/scripts/check-hive-results.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,64 @@ failed_logs_root="${results_dir}/failed_logs"
rm -rf "${failed_logs_root}"
mkdir -p "${failed_logs_root}"

# Known-flaky tests to ignore (substring match against test case name).
# These are hive framework issues, not ethrex bugs.
KNOWN_FLAKY_TESTS=(
# Tests excluded from the failure count (substring match against test case
# name). Two categories live here:
# 1. Genuinely flaky hive-framework tests, not ethrex bugs.
# 2. bal-devnet-6 fixture-vs-impl mismatch routed through hive's
# consume-engine simulator (mirrors the blockchain-runner skip list
# in tooling/ef_tests/blockchain/tests/all.rs SKIPPED_BASE).
KNOWN_EXCLUDED_TESTS=(
# (1) Flaky — hive-framework instability.
"Invalid Missing Ancestor Syncing ReOrg, Timestamp, EmptyTxs=False, CanonicalReOrg=False, Invalid P8"
"Invalid Missing Ancestor Syncing ReOrg, Timestamp, EmptyTxs=False, CanonicalReOrg=True, Invalid P8"
"Invalid Missing Ancestor Syncing ReOrg, Transaction Value, EmptyTxs=False, CanonicalReOrg=False, Invalid P9"
# (2) bal-devnet-6 known-failing fixtures (Amsterdam fork) routed through
# hive's `eels/consume-engine` simulator. Same root cause as the
# blockchain-runner SKIPPED_BASE: snobal-devnet-6 fixtures expect
# bal-devnet-6 spec semantics, but our impl runs ahead due to
# bal-devnet-7-prep `set_delegation` SELFDESTRUCT-style refund
# subtraction. Anchored on `[fork_Amsterdam` so any Prague/Osaka
# variants of the same EELS test functions still run. Re-enable once
# fixtures bump to snobal-devnet-7 or the bal-devnet-7-prep subtraction
# is reverted.
"test_auth_refund_block_gas_accounting[fork_Amsterdam"
"test_auth_refund_bypasses_one_fifth_cap[fork_Amsterdam"
"test_auth_state_gas_scales_with_cpsb[fork_Amsterdam"
"test_auth_with_calldata_and_access_list[fork_Amsterdam"
"test_auth_with_multiple_sstores[fork_Amsterdam"
"test_authorization_exact_state_gas_boundary[fork_Amsterdam"
"test_authorization_to_precompile_address[fork_Amsterdam"
"test_authorization_with_sstore[fork_Amsterdam"
"test_bal_7702_delegation_clear[fork_Amsterdam"
"test_bal_7702_delegation_create[fork_Amsterdam"
"test_bal_7702_delegation_update[fork_Amsterdam"
"test_bal_7702_double_auth_reset[fork_Amsterdam"
"test_bal_7702_double_auth_swap[fork_Amsterdam"
"test_bal_7702_null_address_delegation_no_code_change[fork_Amsterdam"
"test_bal_all_transaction_types[fork_Amsterdam"
"test_bal_selfdestruct_to_7702_delegation[fork_Amsterdam"
"test_bal_withdrawal_to_7702_delegation[fork_Amsterdam"
"test_duplicate_signer_authorizations[fork_Amsterdam"
"test_existing_account_auth_header_gas_used_uses_worst_case[fork_Amsterdam"
"test_existing_account_refund[fork_Amsterdam"
"test_existing_account_refund_enables_sstore[fork_Amsterdam"
"test_existing_auth_with_reverted_execution_preserves_intrinsic[fork_Amsterdam"
"test_many_authorizations_state_gas[fork_Amsterdam"
"test_mixed_auths_header_gas_used_uses_worst_case[fork_Amsterdam"
"test_mixed_new_and_existing_auths[fork_Amsterdam"
"test_mixed_valid_and_invalid_auths[fork_Amsterdam"
"test_multi_tx_block_auth_refund_and_sstore[fork_Amsterdam"
"test_multiple_refund_types_in_one_tx[fork_Amsterdam"
"test_simple_gas_accounting[fork_Amsterdam"
"test_sstore_state_gas_all_tx_types[fork_Amsterdam"
"test_transfer_with_all_tx_types[fork_Amsterdam"
"test_varying_calldata_costs[fork_Amsterdam"
)

# Build a jq filter that excludes known-flaky tests.
flaky_filter='true'
for pattern in "${KNOWN_FLAKY_TESTS[@]}"; do
flaky_filter="${flaky_filter} and (.name | contains(\"${pattern}\") | not)"
# Build a jq filter that excludes the known-excluded tests.
exclude_filter='true'
for pattern in "${KNOWN_EXCLUDED_TESTS[@]}"; do
exclude_filter="${exclude_filter} and (.name | contains(\"${pattern}\") | not)"
done

for json_file in "${json_files[@]}"; do
Expand All @@ -77,11 +123,11 @@ for json_file in "${json_files[@]}"; do
fi

suite_name="$(jq -r '.name // empty' "${json_file}")"
failed_cases="$(jq '[.testCases[]? | select(.summaryResult.pass != true) | select('"${flaky_filter}"')] | length' "${json_file}")"
failed_cases="$(jq '[.testCases[]? | select(.summaryResult.pass != true) | select('"${exclude_filter}"')] | length' "${json_file}")"

skipped_flaky="$(jq '[.testCases[]? | select(.summaryResult.pass != true) | select(('"${flaky_filter}"') | not)] | length' "${json_file}")"
if [ "${skipped_flaky}" -gt 0 ]; then
echo "Ignoring ${skipped_flaky} known-flaky test(s) in ${suite_name:-$(basename "${json_file}")}"
skipped_excluded="$(jq '[.testCases[]? | select(.summaryResult.pass != true) | select(('"${exclude_filter}"') | not)] | length' "${json_file}")"
if [ "${skipped_excluded}" -gt 0 ]; then
echo "Ignoring ${skipped_excluded} known-excluded test(s) in ${suite_name:-$(basename "${json_file}")}"
fi

if [ "${failed_cases}" -gt 0 ]; then
Expand All @@ -90,7 +136,7 @@ for json_file in "${json_files[@]}"; do
jq -r '
.testCases[]?
| select(.summaryResult.pass != true)
| select('"${flaky_filter}"')
| select('"${exclude_filter}"')
| . as $case
| ($case.summaryResult // {}) as $summary
| ($summary.message // $summary.reason // $summary.error // "") as $message
Expand Down Expand Up @@ -144,9 +190,9 @@ for json_file in "${json_files[@]}"; do
[
.simLog?,
.testDetailsLog?,
(.testCases[]? | select(.summaryResult.pass != true) | select('"${flaky_filter}"') | .clientInfo? | to_entries? // [] | map(.value.logFile? // empty) | .[]),
(.testCases[]? | select(.summaryResult.pass != true) | select('"${flaky_filter}"') | .summaryResult.logFile?),
(.testCases[]? | select(.summaryResult.pass != true) | select('"${flaky_filter}"') | .logFile?)
(.testCases[]? | select(.summaryResult.pass != true) | select('"${exclude_filter}"') | .clientInfo? | to_entries? // [] | map(.value.logFile? // empty) | .[]),
(.testCases[]? | select(.summaryResult.pass != true) | select('"${exclude_filter}"') | .summaryResult.logFile?),
(.testCases[]? | select(.summaryResult.pass != true) | select('"${exclude_filter}"') | .logFile?)
]
| map(select(. != null and . != ""))
| unique
Expand Down Expand Up @@ -216,7 +262,7 @@ for json_file in "${json_files[@]}"; do
.testCases
| to_entries[]
| select(.value.summaryResult.pass != true)
| select(.value | '"${flaky_filter}"')
| select(.value | '"${exclude_filter}"')
| . as $case_entry
| ($case_entry.value.clientInfo? // {}) | to_entries[]
| [
Expand Down
73 changes: 73 additions & 0 deletions .github/workflows/pr-main_l1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,79 @@ jobs:
run: |
make -C tooling/ef_tests/blockchain test

- name: Append Known Issues to job summary
if: ${{ always() && github.event_name != 'merge_group' && hashFiles('docs/known_issues.md') != '' }}
shell: bash
run: |
{
echo "## Known Issues (intentionally skipped)"
echo ""
echo "_Source: [\`docs/known_issues.md\`](https://github.com/${GITHUB_REPOSITORY}/blob/${GITHUB_SHA}/docs/known_issues.md)_"
echo ""
cat docs/known_issues.md
} >> "$GITHUB_STEP_SUMMARY"

known-issues-comment:
name: Post Known Issues sticky comment
runs-on: ubuntu-latest
# Only on PRs from the same repo (forks lack write perms for comments).
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false }}
permissions:
contents: read
pull-requests: write
issues: write
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
sparse-checkout: |
docs/known_issues.md
sparse-checkout-cone-mode: false

- name: Check if known_issues.md exists
id: check
shell: bash
run: |
if [ -s docs/known_issues.md ]; then
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
fi

- name: Build comment body
if: steps.check.outputs.exists == 'true'
shell: bash
run: |
{
echo "<!-- known-issues-comment -->"
echo "## :warning: Known Issues — intentionally skipped tests"
echo ""
echo "_Source: [\`docs/known_issues.md\`](https://github.com/${GITHUB_REPOSITORY}/blob/${GITHUB_SHA}/docs/known_issues.md)_"
echo ""
cat docs/known_issues.md
} > known_issues_comment.md

- name: Find existing comment
if: steps.check.outputs.exists == 'true'
continue-on-error: true
uses: peter-evans/find-comment@v4
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: "github-actions[bot]"
body-includes: "<!-- known-issues-comment -->"

- name: Create or update comment
if: steps.check.outputs.exists == 'true'
uses: peter-evans/create-or-update-comment@v5
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.pull_request.number }}
body-path: known_issues_comment.md
edit-mode: replace

docker_build:
name: Build Docker
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*.pdb

tooling/ef_tests/blockchain/vectors
tooling/ef_tests/blockchain/vectors_zkevm

tooling/ef_tests/state/vectors

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ run-hive-eels-rlp: ## Run hive EELS RLP tests
run-hive-eels-blobs: ## Run hive EELS Blobs tests
$(MAKE) run-hive-eels EELS_SIM=ethereum/eels/execute-blobs

AMSTERDAM_FIXTURES_URL ?= https://github.com/ethereum/execution-spec-tests/releases/download/bal@v5.6.1/fixtures_bal.tar.gz
AMSTERDAM_FIXTURES_BRANCH ?= devnets/bal/3
AMSTERDAM_FIXTURES_URL ?= $(shell cat tooling/ef_tests/blockchain/.fixtures_url_amsterdam)
AMSTERDAM_FIXTURES_BRANCH ?= devnets/snobal/6
run-hive-eels-amsterdam: build-image setup-hive ## 🧪 Run hive EELS Amsterdam Engine tests
- cd hive && ./hive --client-file $(HIVE_CLIENT_FILE) --client ethrex --sim ethereum/eels/consume-engine --sim.limit ".*fork_Amsterdam.*" --sim.parallelism $(SIM_PARALLELISM) --sim.loglevel $(SIM_LOG_LEVEL) --sim.buildarg fixtures=$(AMSTERDAM_FIXTURES_URL) --sim.buildarg branch=$(AMSTERDAM_FIXTURES_BRANCH)

Expand Down
7 changes: 7 additions & 0 deletions crates/blockchain/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,10 @@ pub const MIN_GAS_LIMIT: u64 = 5000;
// === EIP-7825 constants ===
// https://eips.ethereum.org/EIPS/eip-7825
pub const POST_OSAKA_GAS_LIMIT_CAP: u64 = 16777216;

// === EIP-7981 / EIP-7976 constants (Amsterdam+) ===
// access_list_bytes * STANDARD_TOKEN_COST(4) * TOTAL_COST_FLOOR_PER_TOKEN(16) = access_list_bytes * 64
// Per address entry: 20 bytes * 64 = 1280
pub const TX_ACCESS_LIST_ADDRESS_DATA_GAS_AMSTERDAM: u64 = 1280;
// Per storage key entry: 32 bytes * 64 = 2048
pub const TX_ACCESS_LIST_STORAGE_KEY_DATA_GAS_AMSTERDAM: u64 = 2048;
2 changes: 2 additions & 0 deletions crates/blockchain/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ pub enum InvalidForkChoice {
InvalidAncestor(BlockHash),
#[error("Cannot find link between Head and the canonical chain")]
UnlinkedHead,
#[error("Reorg depth {reorg_depth} exceeds the client's limit of {limit}")]
TooDeepReorg { reorg_depth: u64, limit: u64 },

// TODO(#5564): handle arbitrary reorgs
#[error("State root of the new head is not reachable from the database")]
Expand Down
55 changes: 53 additions & 2 deletions crates/blockchain/fork_choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@ use crate::{
is_canonical,
};

/// Maximum number of canonical blocks ethrex can revert in a single forkchoice update.
///
/// This is an implementation cap, not a spec policy. ethrex's state-history retention
/// keeps the last ~128 blocks of state diffs, so reorgs deeper than this cannot be
/// undone regardless of finalization status — the data simply isn't there.
///
/// The spec (execution-apis PR 786, "engine: Restrict no-reorg to the prefix of known
/// finalized") only forbids reorging past the finalized prefix. The finalized check is
/// applied first; this cap is a secondary guard for the implementation limit.
///
/// Reference values across ELs (devnet branches, 2026-04-30):
/// - besu (main): 90_000 — effectively unlimited
/// - erigon (glamsterdam-devnet-0): 96, env-configurable via `MAX_REORG_DEPTH`
/// - geth / nethermind / reth: no engine-API rejection; trust the CL's fork choice
pub const REORG_DEPTH_LIMIT: u64 = 128;
Comment thread
edg-l marked this conversation as resolved.

/// Applies new fork choice data to the current blockchain. It performs validity checks:
/// - The finalized, safe and head hashes must correspond to already saved blocks.
/// - The saved blocks should be in the correct order (finalized <= safe <= head).
Expand Down Expand Up @@ -57,9 +73,15 @@ pub async fn apply_fork_choice(
};

let latest = store.get_latest_block_number().await?;
let head_is_canonical = is_canonical(store, head.number, head_hash).await?;

// If the head block is an already present head ancestor, skip the update.
if is_canonical(store, head.number, head_hash).await? && head.number < latest {
// execution-apis PR 786: the no-reorg skip is only allowed when there is a known
// finalized block and the head references a VALID ancestor of it. Skipping for
// unfinalized canonical ancestors is no longer permitted - those must trigger a reorg.
if let Some(stored_finalized) = store.get_finalized_block_number().await?
&& head.number <= stored_finalized
&& head_is_canonical
{
return Err(InvalidForkChoice::NewHeadAlreadyCanonical);
}

Expand Down Expand Up @@ -98,6 +120,35 @@ pub async fn apply_fork_choice(
));
}

// execution-apis PR 786 point 6: -38006 TooDeepReorg is returned when the reorg
// depth exceeds the limitation specific to the client software. ethrex's limit
// is its state-history retention: we keep the last REORG_DEPTH_LIMIT blocks of
// state diffs, so reorgs deeper than that cannot be unwound. We do not reject
// reorgs that would cross the finalized prefix — the spec's only requirement on
// finalized is point 2 (skip-when-ancestor-of-finalized, handled above) and
// point 5 (-38002 for disconnected safe/finalized). The CL is authoritative on
// fork choice and an EL must honor what the CL sends if it physically can.
//
// The shared canonical ancestor is `head` itself when head is canonical (the
// FCU truncates the canonical chain), or one below the lowest sidechain block
// in `new_canonical_blocks` otherwise.
let canonical_link_height = if head_is_canonical {
head.number
} else {
new_canonical_blocks
.last()
.map(|(n, _)| *n)
.unwrap_or(head.number)
.saturating_sub(1)
};
let reorg_depth = latest.saturating_sub(canonical_link_height);
if reorg_depth > REORG_DEPTH_LIMIT {
return Err(InvalidForkChoice::TooDeepReorg {
reorg_depth,
limit: REORG_DEPTH_LIMIT,
});
}

let Some(link_header) = store.get_block_header_by_hash(link_block_hash)? else {
// Probably unreachable, but we return this error just in case.
error!("Link block not found although it was just retrieved from the DB");
Expand Down
25 changes: 25 additions & 0 deletions crates/blockchain/mempool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use ethrex_common::{
},
};
use ethrex_storage::error::StoreError;
use ethrex_vm::{intrinsic_gas_dimensions, intrinsic_gas_floor};
use tracing::warn;

#[derive(Debug, Default)]
Expand Down Expand Up @@ -512,6 +513,30 @@ pub fn transaction_intrinsic_gas(
header: &BlockHeader,
config: &ChainConfig,
) -> Result<u64, MempoolError> {
// Amsterdam (EIP-8037): the VM splits intrinsic into (regular, state) and uses
// `REGULAR_GAS_CREATE = 9000` + `STATE_BYTES_PER_NEW_ACCOUNT * cpsb` for CREATE
// instead of the legacy `TX_CREATE_GAS_COST = 53000`. Mempool admission must
// match VM charge or we spuriously reject (or admit) transactions.
//
// The VM enforces `gas_limit >= max(intrinsic_regular + intrinsic_state,
// floor)` via two separate checks in `validate_gas_allowance` +
// `validate_min_gas_limit`. Apply the same max here so we don't admit
// txs whose calldata floor exceeds the weighted intrinsic — those would
// pass mempool and then fail at block inclusion, polluting the pool.
if config.is_amsterdam_activated(header.timestamp) {
let fork = config.fork(header.timestamp);
let (regular, state) = intrinsic_gas_dimensions(tx, fork, header.gas_limit)
.map_err(|_| MempoolError::TxGasOverflowError)?;
let intrinsic = regular
.checked_add(state)
.ok_or(MempoolError::TxGasOverflowError)?;
let floor = intrinsic_gas_floor(tx, fork).map_err(|_| MempoolError::TxGasOverflowError)?;
// Block-level gas = max(regular_dim, state_dim); regular_dim itself is
// `max(tx_regular, calldata_floor)` per EIP-7778. Use the same max so
// admission mirrors the VM's effective minimum.
return Ok(intrinsic.max(floor));
}

let is_contract_creation = tx.is_contract_creation();

let mut gas = if is_contract_creation {
Expand Down
Loading
Loading