engine: Restrict no-reorg to the prefix of known finalized#786
Merged
Conversation
Contributor
|
Just a comment to leave somewhere, but I think these types of reorgs going back on the canonical chain can only happen up to the "Justified" hash instead of the finalized one, eg. most validators are malicious and start voting on top of the justified root but empty. |
jihoonsong
added a commit
to jihoonsong/execution-apis
that referenced
this pull request
Apr 24, 2026
This was referenced Apr 25, 2026
10 tasks
daniellehrner
added a commit
to daniellehrner/besu
that referenced
this pull request
Apr 28, 2026
Create a new abstract engine_fcu class for it to not affect previous hardforks including Osaka which currently runs on mainnet Signed-off-by: daniellehrner <daniel.lehrner@consensys.net>
daniellehrner
added a commit
to besu-eth/besu
that referenced
this pull request
Apr 28, 2026
Implement changes from ethereum/execution-apis#786 : Create a new abstract engine_fcu class for it to not affect previous hardforks including Osaka which currently runs on mainnet Signed-off-by: daniellehrner <daniel.lehrner@consensys.net>
12 tasks
Sahil-4555
pushed a commit
to Sahil-4555/erigon
that referenced
this pull request
Apr 30, 2026
… hash (erigontech#20825) closes erigontech#20888 implements ethereum/execution-apis#786 which is needed for glamsterdam-devnet-0 --------- Co-authored-by: Alex Sharov <AskAlexSharov@gmail.com>
edg-l
pushed a commit
to lambdaclass/ethrex
that referenced
this pull request
Apr 30, 2026
Implements ethereum/execution-apis#786 (engine: Restrict no-reorg to the prefix of known finalized) on top of bal-devnet-4 for the glamsterdam-devnet-0 testbed, as requested by EthPandaOps. Spec changes implemented: 1. The no-reorg skip optimization in engine_forkchoiceUpdated is now restricted to the case where the head references a VALID canonical ancestor of the latest known finalized block. Previously ethrex skipped for any canonical ancestor below the current head; that is no longer permitted by the spec for unfinalized ancestors, which must trigger a reorg back. 2. A new -38006 "Too deep reorg" engine error is introduced. It is returned when an FCU would replace more canonical blocks than the client's implementation-specific limit. Mapped through a new InvalidForkChoice::TooDeepReorg variant and a new RpcErr::TooDeepReorg variant carrying JSON-RPC error code -38006. Implementation decisions not specified by the spec: - REORG_DEPTH_LIMIT = 32. The spec leaves this implementation-specific. 32 was chosen because it matches one Ethereum finalization epoch and aligns with the value nethermind picked for the closely related execution-apis PR 770 in their engine-api-glamsterdam branch. - Reorg depth is computed as (latest_block_number - canonical_link_height), where canonical_link_height is the head itself when the head is canonical (canonical-truncate FCU) and the height of head's deepest canonical ancestor otherwise (sidechain reorg). This correctly counts the number of canonical blocks that would be replaced. - The skip optimization fires for head.number <= stored_finalized rather than strict <. Strictly the spec says "ancestor", but treating the finalized block itself as a valid skip target is a no-op in practice. - The change is unconditional and not gated on a fork timestamp. Spec PR 786 edits paris.md, framing the change as a clarification of merge-era semantics rather than a new fork rule, so it applies on all forks. - L2 callers of apply_fork_choice (l2_connection, block_producer, block_fetcher) are intentionally untouched. Their head=safe=finalized pattern always leaves stored_finalized >= head.number, so the new skip rule never fires there, and reorg depth is at most 1. Tests: - The existing test_new_head_with_canonical_ancestor_should_skip smoke test asserted the old behavior. Renamed to new_head_ancestor_of_finalized_should_skip and rewritten to set up an ancestor-of-finalized scenario, which is now the only case that triggers the skip. - All 5 fork-choice smoke tests in test/tests/blockchain pass. - EF blockchain (LEVM + stateless) and state suites pass on the parent branch (verification of the bal-devnet-4 baseline). - Hive engine simulator verification is the next step and should be run before connecting to the devnet. References: - execution-apis PR 786 (merged): restricts no-reorg, adds -38006 - execution-apis PR 770 (closed/superseded): the alternative reorg-depth approach nethermind ships; informs the depth-limit constant choice.
10 tasks
daniellehrner
added a commit
to besu-eth/besu
that referenced
this pull request
Apr 30, 2026
Implement changes from ethereum/execution-apis#786 : Create a new abstract engine_fcu class for it to not affect previous hardforks including Osaka which currently runs on mainnet Signed-off-by: daniellehrner <daniel.lehrner@consensys.net>
Merged
16 tasks
edg-l
pushed a commit
to lambdaclass/ethrex
that referenced
this pull request
May 6, 2026
Implements ethereum/execution-apis#786 (engine: Restrict no-reorg to the prefix of known finalized) on top of bal-devnet-4 for the glamsterdam-devnet-0 testbed, as requested by EthPandaOps. Spec changes implemented: 1. The no-reorg skip optimization in engine_forkchoiceUpdated is now restricted to the case where the head references a VALID canonical ancestor of the latest known finalized block. Previously ethrex skipped for any canonical ancestor below the current head; that is no longer permitted by the spec for unfinalized ancestors, which must trigger a reorg back. 2. A new -38006 "Too deep reorg" engine error is introduced. It is returned when an FCU would replace more canonical blocks than the client's implementation-specific limit. Mapped through a new InvalidForkChoice::TooDeepReorg variant and a new RpcErr::TooDeepReorg variant carrying JSON-RPC error code -38006. Implementation decisions not specified by the spec: - REORG_DEPTH_LIMIT = 32. The spec leaves this implementation-specific. 32 was chosen because it matches one Ethereum finalization epoch and aligns with the value nethermind picked for the closely related execution-apis PR 770 in their engine-api-glamsterdam branch. - Reorg depth is computed as (latest_block_number - canonical_link_height), where canonical_link_height is the head itself when the head is canonical (canonical-truncate FCU) and the height of head's deepest canonical ancestor otherwise (sidechain reorg). This correctly counts the number of canonical blocks that would be replaced. - The skip optimization fires for head.number <= stored_finalized rather than strict <. Strictly the spec says "ancestor", but treating the finalized block itself as a valid skip target is a no-op in practice. - The change is unconditional and not gated on a fork timestamp. Spec PR 786 edits paris.md, framing the change as a clarification of merge-era semantics rather than a new fork rule, so it applies on all forks. - L2 callers of apply_fork_choice (l2_connection, block_producer, block_fetcher) are intentionally untouched. Their head=safe=finalized pattern always leaves stored_finalized >= head.number, so the new skip rule never fires there, and reorg depth is at most 1. Tests: - The existing test_new_head_with_canonical_ancestor_should_skip smoke test asserted the old behavior. Renamed to new_head_ancestor_of_finalized_should_skip and rewritten to set up an ancestor-of-finalized scenario, which is now the only case that triggers the skip. - All 5 fork-choice smoke tests in test/tests/blockchain pass. - EF blockchain (LEVM + stateless) and state suites pass on the parent branch (verification of the bal-devnet-4 baseline). - Hive engine simulator verification is the next step and should be run before connecting to the devnet. References: - execution-apis PR 786 (merged): restricts no-reorg, adds -38006 - execution-apis PR 770 (closed/superseded): the alternative reorg-depth approach nethermind ships; informs the depth-limit constant choice.
edg-l
pushed a commit
to lambdaclass/ethrex
that referenced
this pull request
May 6, 2026
Implements ethereum/execution-apis#786 (engine: Restrict no-reorg to the prefix of known finalized) on top of bal-devnet-4 for the glamsterdam-devnet-0 testbed, as requested by EthPandaOps. Spec changes implemented: 1. The no-reorg skip optimization in engine_forkchoiceUpdated is now restricted to the case where the head references a VALID canonical ancestor of the latest known finalized block. Previously ethrex skipped for any canonical ancestor below the current head; that is no longer permitted by the spec for unfinalized ancestors, which must trigger a reorg back. 2. A new -38006 "Too deep reorg" engine error is introduced. It is returned when an FCU would replace more canonical blocks than the client's implementation-specific limit. Mapped through a new InvalidForkChoice::TooDeepReorg variant and a new RpcErr::TooDeepReorg variant carrying JSON-RPC error code -38006. Implementation decisions not specified by the spec: - REORG_DEPTH_LIMIT = 32. The spec leaves this implementation-specific. 32 was chosen because it matches one Ethereum finalization epoch and aligns with the value nethermind picked for the closely related execution-apis PR 770 in their engine-api-glamsterdam branch. - Reorg depth is computed as (latest_block_number - canonical_link_height), where canonical_link_height is the head itself when the head is canonical (canonical-truncate FCU) and the height of head's deepest canonical ancestor otherwise (sidechain reorg). This correctly counts the number of canonical blocks that would be replaced. - The skip optimization fires for head.number <= stored_finalized rather than strict <. Strictly the spec says "ancestor", but treating the finalized block itself as a valid skip target is a no-op in practice. - The change is unconditional and not gated on a fork timestamp. Spec PR 786 edits paris.md, framing the change as a clarification of merge-era semantics rather than a new fork rule, so it applies on all forks. - L2 callers of apply_fork_choice (l2_connection, block_producer, block_fetcher) are intentionally untouched. Their head=safe=finalized pattern always leaves stored_finalized >= head.number, so the new skip rule never fires there, and reorg depth is at most 1. Tests: - The existing test_new_head_with_canonical_ancestor_should_skip smoke test asserted the old behavior. Renamed to new_head_ancestor_of_finalized_should_skip and rewritten to set up an ancestor-of-finalized scenario, which is now the only case that triggers the skip. - All 5 fork-choice smoke tests in test/tests/blockchain pass. - EF blockchain (LEVM + stateless) and state suites pass on the parent branch (verification of the bal-devnet-4 baseline). - Hive engine simulator verification is the next step and should be run before connecting to the devnet. References: - execution-apis PR 786 (merged): restricts no-reorg, adds -38006 - execution-apis PR 770 (closed/superseded): the alternative reorg-depth approach nethermind ships; informs the depth-limit constant choice.
1 task
edg-l
pushed a commit
to lambdaclass/ethrex
that referenced
this pull request
May 6, 2026
Implements ethereum/execution-apis#786 (engine: Restrict no-reorg to the prefix of known finalized) on top of bal-devnet-4 for the glamsterdam-devnet-0 testbed, as requested by EthPandaOps. Spec changes implemented: 1. The no-reorg skip optimization in engine_forkchoiceUpdated is now restricted to the case where the head references a VALID canonical ancestor of the latest known finalized block. Previously ethrex skipped for any canonical ancestor below the current head; that is no longer permitted by the spec for unfinalized ancestors, which must trigger a reorg back. 2. A new -38006 "Too deep reorg" engine error is introduced. It is returned when an FCU would replace more canonical blocks than the client's implementation-specific limit. Mapped through a new InvalidForkChoice::TooDeepReorg variant and a new RpcErr::TooDeepReorg variant carrying JSON-RPC error code -38006. Implementation decisions not specified by the spec: - REORG_DEPTH_LIMIT = 32. The spec leaves this implementation-specific. 32 was chosen because it matches one Ethereum finalization epoch and aligns with the value nethermind picked for the closely related execution-apis PR 770 in their engine-api-glamsterdam branch. - Reorg depth is computed as (latest_block_number - canonical_link_height), where canonical_link_height is the head itself when the head is canonical (canonical-truncate FCU) and the height of head's deepest canonical ancestor otherwise (sidechain reorg). This correctly counts the number of canonical blocks that would be replaced. - The skip optimization fires for head.number <= stored_finalized rather than strict <. Strictly the spec says "ancestor", but treating the finalized block itself as a valid skip target is a no-op in practice. - The change is unconditional and not gated on a fork timestamp. Spec PR 786 edits paris.md, framing the change as a clarification of merge-era semantics rather than a new fork rule, so it applies on all forks. - L2 callers of apply_fork_choice (l2_connection, block_producer, block_fetcher) are intentionally untouched. Their head=safe=finalized pattern always leaves stored_finalized >= head.number, so the new skip rule never fires there, and reorg depth is at most 1. Tests: - The existing test_new_head_with_canonical_ancestor_should_skip smoke test asserted the old behavior. Renamed to new_head_ancestor_of_finalized_should_skip and rewritten to set up an ancestor-of-finalized scenario, which is now the only case that triggers the skip. - All 5 fork-choice smoke tests in test/tests/blockchain pass. - EF blockchain (LEVM + stateless) and state suites pass on the parent branch (verification of the bal-devnet-4 baseline). - Hive engine simulator verification is the next step and should be run before connecting to the devnet. References: - execution-apis PR 786 (merged): restricts no-reorg, adds -38006 - execution-apis PR 770 (closed/superseded): the alternative reorg-depth approach nethermind ships; informs the depth-limit constant choice.
edg-l
pushed a commit
to lambdaclass/ethrex
that referenced
this pull request
May 7, 2026
Implements ethereum/execution-apis#786 (engine: Restrict no-reorg to the prefix of known finalized) on top of bal-devnet-4 for the glamsterdam-devnet-0 testbed, as requested by EthPandaOps. Spec changes implemented: 1. The no-reorg skip optimization in engine_forkchoiceUpdated is now restricted to the case where the head references a VALID canonical ancestor of the latest known finalized block. Previously ethrex skipped for any canonical ancestor below the current head; that is no longer permitted by the spec for unfinalized ancestors, which must trigger a reorg back. 2. A new -38006 "Too deep reorg" engine error is introduced. It is returned when an FCU would replace more canonical blocks than the client's implementation-specific limit. Mapped through a new InvalidForkChoice::TooDeepReorg variant and a new RpcErr::TooDeepReorg variant carrying JSON-RPC error code -38006. Implementation decisions not specified by the spec: - REORG_DEPTH_LIMIT = 32. The spec leaves this implementation-specific. 32 was chosen because it matches one Ethereum finalization epoch and aligns with the value nethermind picked for the closely related execution-apis PR 770 in their engine-api-glamsterdam branch. - Reorg depth is computed as (latest_block_number - canonical_link_height), where canonical_link_height is the head itself when the head is canonical (canonical-truncate FCU) and the height of head's deepest canonical ancestor otherwise (sidechain reorg). This correctly counts the number of canonical blocks that would be replaced. - The skip optimization fires for head.number <= stored_finalized rather than strict <. Strictly the spec says "ancestor", but treating the finalized block itself as a valid skip target is a no-op in practice. - The change is unconditional and not gated on a fork timestamp. Spec PR 786 edits paris.md, framing the change as a clarification of merge-era semantics rather than a new fork rule, so it applies on all forks. - L2 callers of apply_fork_choice (l2_connection, block_producer, block_fetcher) are intentionally untouched. Their head=safe=finalized pattern always leaves stored_finalized >= head.number, so the new skip rule never fires there, and reorg depth is at most 1. Tests: - The existing test_new_head_with_canonical_ancestor_should_skip smoke test asserted the old behavior. Renamed to new_head_ancestor_of_finalized_should_skip and rewritten to set up an ancestor-of-finalized scenario, which is now the only case that triggers the skip. - All 5 fork-choice smoke tests in test/tests/blockchain pass. - EF blockchain (LEVM + stateless) and state suites pass on the parent branch (verification of the bal-devnet-4 baseline). - Hive engine simulator verification is the next step and should be run before connecting to the devnet. References: - execution-apis PR 786 (merged): restricts no-reorg, adds -38006 - execution-apis PR 770 (closed/superseded): the alternative reorg-depth approach nethermind ships; informs the depth-limit constant choice.
edg-l
pushed a commit
to lambdaclass/ethrex
that referenced
this pull request
May 7, 2026
Implements ethereum/execution-apis#786 (engine: Restrict no-reorg to the prefix of known finalized) on top of bal-devnet-4 for the glamsterdam-devnet-0 testbed, as requested by EthPandaOps. Spec changes implemented: 1. The no-reorg skip optimization in engine_forkchoiceUpdated is now restricted to the case where the head references a VALID canonical ancestor of the latest known finalized block. Previously ethrex skipped for any canonical ancestor below the current head; that is no longer permitted by the spec for unfinalized ancestors, which must trigger a reorg back. 2. A new -38006 "Too deep reorg" engine error is introduced. It is returned when an FCU would replace more canonical blocks than the client's implementation-specific limit. Mapped through a new InvalidForkChoice::TooDeepReorg variant and a new RpcErr::TooDeepReorg variant carrying JSON-RPC error code -38006. Implementation decisions not specified by the spec: - REORG_DEPTH_LIMIT = 32. The spec leaves this implementation-specific. 32 was chosen because it matches one Ethereum finalization epoch and aligns with the value nethermind picked for the closely related execution-apis PR 770 in their engine-api-glamsterdam branch. - Reorg depth is computed as (latest_block_number - canonical_link_height), where canonical_link_height is the head itself when the head is canonical (canonical-truncate FCU) and the height of head's deepest canonical ancestor otherwise (sidechain reorg). This correctly counts the number of canonical blocks that would be replaced. - The skip optimization fires for head.number <= stored_finalized rather than strict <. Strictly the spec says "ancestor", but treating the finalized block itself as a valid skip target is a no-op in practice. - The change is unconditional and not gated on a fork timestamp. Spec PR 786 edits paris.md, framing the change as a clarification of merge-era semantics rather than a new fork rule, so it applies on all forks. - L2 callers of apply_fork_choice (l2_connection, block_producer, block_fetcher) are intentionally untouched. Their head=safe=finalized pattern always leaves stored_finalized >= head.number, so the new skip rule never fires there, and reorg depth is at most 1. Tests: - The existing test_new_head_with_canonical_ancestor_should_skip smoke test asserted the old behavior. Renamed to new_head_ancestor_of_finalized_should_skip and rewritten to set up an ancestor-of-finalized scenario, which is now the only case that triggers the skip. - All 5 fork-choice smoke tests in test/tests/blockchain pass. - EF blockchain (LEVM + stateless) and state suites pass on the parent branch (verification of the bal-devnet-4 baseline). - Hive engine simulator verification is the next step and should be run before connecting to the devnet. References: - execution-apis PR 786 (merged): restricts no-reorg, adds -38006 - execution-apis PR 770 (closed/superseded): the alternative reorg-depth approach nethermind ships; informs the depth-limit constant choice.
edg-l
pushed a commit
to lambdaclass/ethrex
that referenced
this pull request
May 8, 2026
Implements ethereum/execution-apis#786 (engine: Restrict no-reorg to the prefix of known finalized) on top of bal-devnet-4 for the glamsterdam-devnet-0 testbed, as requested by EthPandaOps. Spec changes implemented: 1. The no-reorg skip optimization in engine_forkchoiceUpdated is now restricted to the case where the head references a VALID canonical ancestor of the latest known finalized block. Previously ethrex skipped for any canonical ancestor below the current head; that is no longer permitted by the spec for unfinalized ancestors, which must trigger a reorg back. 2. A new -38006 "Too deep reorg" engine error is introduced. It is returned when an FCU would replace more canonical blocks than the client's implementation-specific limit. Mapped through a new InvalidForkChoice::TooDeepReorg variant and a new RpcErr::TooDeepReorg variant carrying JSON-RPC error code -38006. Implementation decisions not specified by the spec: - REORG_DEPTH_LIMIT = 32. The spec leaves this implementation-specific. 32 was chosen because it matches one Ethereum finalization epoch and aligns with the value nethermind picked for the closely related execution-apis PR 770 in their engine-api-glamsterdam branch. - Reorg depth is computed as (latest_block_number - canonical_link_height), where canonical_link_height is the head itself when the head is canonical (canonical-truncate FCU) and the height of head's deepest canonical ancestor otherwise (sidechain reorg). This correctly counts the number of canonical blocks that would be replaced. - The skip optimization fires for head.number <= stored_finalized rather than strict <. Strictly the spec says "ancestor", but treating the finalized block itself as a valid skip target is a no-op in practice. - The change is unconditional and not gated on a fork timestamp. Spec PR 786 edits paris.md, framing the change as a clarification of merge-era semantics rather than a new fork rule, so it applies on all forks. - L2 callers of apply_fork_choice (l2_connection, block_producer, block_fetcher) are intentionally untouched. Their head=safe=finalized pattern always leaves stored_finalized >= head.number, so the new skip rule never fires there, and reorg depth is at most 1. Tests: - The existing test_new_head_with_canonical_ancestor_should_skip smoke test asserted the old behavior. Renamed to new_head_ancestor_of_finalized_should_skip and rewritten to set up an ancestor-of-finalized scenario, which is now the only case that triggers the skip. - All 5 fork-choice smoke tests in test/tests/blockchain pass. - EF blockchain (LEVM + stateless) and state suites pass on the parent branch (verification of the bal-devnet-4 baseline). - Hive engine simulator verification is the next step and should be run before connecting to the devnet. References: - execution-apis PR 786 (merged): restricts no-reorg, adds -38006 - execution-apis PR 770 (closed/superseded): the alternative reorg-depth approach nethermind ships; informs the depth-limit constant choice.
ilitteri
added a commit
to benbencik/ethrex
that referenced
this pull request
May 13, 2026
…daclass#6574) **Motivation** Bring ethrex up to [bal-devnet-6 spec](https://notes.ethereum.org/@ethpandaops/bal-devnet-6) so we can participate in the devnet. Rolls up the work that landed across `bal-devnet-3` → `bal-devnet-4` → `bal-devnet-5` → `bal-devnet-6`. The original `bal-devnet-6` branch is kept for ongoing devnet work; this `*-pr` branch is the one intended for merge. **Description** - **EIP-7928 (BAL)** — Block Access List support. Fixtures bumped to snøbal-devnet-6 (`v1.1.0`), `BlockAccessIndex` widened from `u16` to `u32`, shadow recorder for per-tx access validation in parallel execution, `SYSTEM_ADDRESS` exclusion. - **EIP-8037 (2D gas)** — full EELS PR lambdaclass#2689 semantics: - `cost_per_state_byte` pinned to 1174 for bal-devnet-4..6. - Top-level / sub-frame `ExceptionalHalt` reclassifies state gas → regular dim (both CALL and CREATE return paths). - REVERT cascade keeps `state_gas_credit_against_drain` elevated so credit burns propagate. - CREATE-TX top-halt formula: `gross_spill − credit_against_drain − already_reclassified` reclassified to regular dim. - EIP-7702 `set_delegation` refund: subtracts from `state_gas_used` / `intrinsic_state_gas_charged` (bal-devnet-7-prep accounting, SELFDESTRUCT-style). See note below. - `credit_against_drain` capped by `regular_gas_reclassified` so phantom-drain credits don't cancel real spill. - `check_2d_gas_allowance` runs per-tx before BAL recording (rejected txs don't pollute the BAL). - **EIP-7976 / EIP-7981** — calldata + access-list floor cost adjustments wired into intrinsic gas + sender refund. - **Engine / Execution-API** — [execution-apis PR 786](ethereum/execution-apis#786) FCU semantics: no-reorg restricted to finalized prefix (point 2), `-38006 TooDeepReorg` returned when the requested reorg depth exceeds ethrex's state-history retention (point 6). - **ef-tests** — runner continues processing blocks after expected-exception (fork-transition tests); 74 bal-devnet-6 Amsterdam fixtures intentionally skipped (see `docs/known_issues.md`). **bal-devnet-7 direction (intentional)** The bal-devnet-6 spec acknowledges as a known-bug that `set_delegation` for an existing authority should subtract the auth refund from `tx_state_gas` (mirroring SELFDESTRUCT) but currently does not. Upstream has a regression test (`9b3961a65 test_snobal_block_gas_used_inflated_by_7702_auth_refund`) that locks in the un-subtracted behavior for bal-devnet-6 verification. This PR carries the bal-devnet-7-prep subtraction so we are already aligned with where EELS is moving; the cost is that 74 snobal-devnet-6 fixtures expect the old un-subtracted accounting and are skipped via `tooling/ef_tests/blockchain/tests/all.rs::SKIPPED_BASE` until fixtures bump to snobal-devnet-7. **Checklist** - [ ] Updated `STORE_SCHEMA_VERSION` (crates/storage/lib.rs) if the PR includes breaking changes to the `Store` requiring a re-sync. *(N/A — no Store schema changes)* --------- Co-authored-by: Tomás Arjovsky <tomas.arjovsky@lambdaclass.com> Co-authored-by: ilitteri <ivanlitteri@hotmail.com> Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> Co-authored-by: MariusVanDerWijden <m.vanderwijden@live.de> Co-authored-by: Stefan <22667037+qu0b@users.noreply.github.com>
jihoonsong
added a commit
to jihoonsong/execution-apis
that referenced
this pull request
May 26, 2026
dicethedev
pushed a commit
to dicethedev/ethrex
that referenced
this pull request
May 28, 2026
…ambdaclass#6676) ## Summary execution-apis PR [lambdaclass#786](ethereum/execution-apis#786) revised paris.md: when `forkchoiceState.headBlockHash` references a VALID ancestor of the latest known finalized block, the response MUST be `{payloadStatus: VALID, payloadId: null}` and the client MUST NOT begin a payload build process. ethrex already had the correct `InvalidForkChoice::NewHeadAlreadyCanonical` detection path in `crates/blockchain/fork_choice.rs` (gate: `head.number <= stored_finalized && head_is_canonical`; the `<=` matches geth's `block.NumberU64() <= finalized.Number.Uint64()` in `eth/catalyst/api.go`, see geth PR [#34767](ethereum/go-ethereum#34767)). The bug was in `crates/networking/rpc/engine/fork_choice.rs`: the `NewHeadAlreadyCanonical` arm returned `Some(head_header)`, which caused `ForkChoiceUpdatedV3::handle` / `ForkChoiceUpdatedV4::handle` to call `build_payload` and set a non-null `payloadId` when `payloadAttributes` was present. Fix: return `None` for the head header so the V3/V4 dispatch's `if let (Some(_), Some(_))` guard short-circuits `build_payload`. The `VALID + latestValidHash = head` response is preserved, matching geth's `valid(nil)` return. ## Test plan - `cargo check -p ethrex-rpc` passes - `cargo clippy -p ethrex-rpc` passes - `cargo test -p ethrex-rpc` passes
jihoonsong
added a commit
to ethereum/consensus-specs
that referenced
this pull request
Jun 1, 2026
Currently with proposer boost reorg enabled, proposer of next slot can suppress fcu call (as laid out by `should_override_forkchoice_update`), if it thinks there is a chance the current head block can be reorged out. This is done so because EL could previously skip processing an `engine_forkchoiceUpdated` call if headBlockHash referenced any ancestor of the EL's current canonical head. With ethereum/execution-apis#786, the EL can only skip an fcU if headBlockHash is an ancestor of the finalized block. Since reorg targets are always within the unfinalized chain, the EL must now process them. This makes `should_override_forkchoice_update` unnecessary. We can just rely on `get_proposer_head` to reorg without doing any prediction before hand. This PR removes `should_override_forkchoice_update` itself and anything references it. Co-authored-by: Jihoon Song <jihoonsong@users.noreply.github.com>
1 task
jihoonsong
added a commit
to jihoonsong/execution-apis
that referenced
this pull request
Jun 9, 2026
benbencik
pushed a commit
to benbencik/ethrex
that referenced
this pull request
Jun 13, 2026
…ambdaclass#6676) ## Summary execution-apis PR [lambdaclass#786](ethereum/execution-apis#786) revised paris.md: when `forkchoiceState.headBlockHash` references a VALID ancestor of the latest known finalized block, the response MUST be `{payloadStatus: VALID, payloadId: null}` and the client MUST NOT begin a payload build process. ethrex already had the correct `InvalidForkChoice::NewHeadAlreadyCanonical` detection path in `crates/blockchain/fork_choice.rs` (gate: `head.number <= stored_finalized && head_is_canonical`; the `<=` matches geth's `block.NumberU64() <= finalized.Number.Uint64()` in `eth/catalyst/api.go`, see geth PR [#34767](ethereum/go-ethereum#34767)). The bug was in `crates/networking/rpc/engine/fork_choice.rs`: the `NewHeadAlreadyCanonical` arm returned `Some(head_header)`, which caused `ForkChoiceUpdatedV3::handle` / `ForkChoiceUpdatedV4::handle` to call `build_payload` and set a non-null `payloadId` when `payloadAttributes` was present. Fix: return `None` for the head header so the V3/V4 dispatch's `if let (Some(_), Some(_))` guard short-circuits `build_payload`. The `VALID + latestValidHash = head` response is preserved, matching geth's `valid(nil)` return. ## Test plan - `cargo check -p ethrex-rpc` passes - `cargo clippy -p ethrex-rpc` passes - `cargo test -p ethrex-rpc` passes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR is an alternative to #770 and introduces the following changes:
-38006: Too deep reorgerror to handle the case when EL client cannot do a reorg due to the depth being beyond client's reorg capability. This depth is supposed to be implementation specificFor detail see discussion in #770 thread.