AERE patch 0005: futureEips activation isolated on Osaka, plus protocol-native EIP-2935 Why this patch exists, measured 2026-08-15 on a from-genesis sync: a node built from patches 0001+0003+0004 alone followed chain 2800 to block 9,189,160 and stopped at 9,189,161, the futureEipsTime activation block, with "failed persisting block due to stateroot mismatch". Two independent causes, both fixed here, both in MainnetProtocolSpecs.java: 1. Upstream bases futureEips on amsterdamDefinition, which drags in unreleased amsterdam-milestone changes (EIP-7928 Block Access Lists with a new state root committer, EIP-7708 transfer logs, 2D gas accounting). Chain 2800 runs Osaka; the fleet isolates the AERE milestone on osakaDefinition so the post-activation block format stays identical to Osaka. 2. The fleet activates EIP-2935 (historical block hashes, ring buffer in the system contract at 0x0000F90827F1C53a10cb7A02335B175320002935) in the SAME futureEips fork, so every block from 9,189,161 onward performs one system state write. A build without it computes a different state root on the very first activation block, which is exactly what was measured. Modified upstream file: MainnetProtocolSpecs.java (plus one build.gradle line). The upstream copyright header is unchanged, per Apache License 2.0 section 4(c); the in-diff comments state exactly what changed, per section 4(b). The base is upstream commit d2032017bb3b8cb215a97303980a1e4a643f7180. One deliberate omission: the fleet's own copy of this change also wires an optional Block-STM parallel block processor behind an environment gate. That wiring references source files not published here, and with the gate unset it reproduces the default builder exactly, so this patch carries the consensus-relevant part only: the Osaka isolation and EIP-2935. A build from this patch follows the chain; it does not enable parallel execution. diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index 87f1a6b..545aeb2 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -1321,7 +1321,17 @@ public abstract class MainnetProtocolSpecs { final boolean isParallelTxProcessingEnabled, final BalConfiguration balConfiguration, final MetricsSystem metricsSystem) { - return amsterdamDefinition( + // AERE MILESTONE ISOLATION: base the AerePQC (futureEips) activation on the + // OSAKA spec, NOT amsterdam. Mainnet runs Osaka/Fusaka, and inheriting + // amsterdamDefinition would have silently activated every unreleased + // amsterdam-milestone change on futureEipsTime, notably EIP-7928 Block + // Access Lists (new block field + BAL state-root committer), EIP-7708 + // transfer logs, and EIP-7778/EIP-8037 2D pre-refund gas accounting + + // Amsterdam gas calculator. Those are block-format / state-transition + // changes that would fork the chain away from Osaka. Basing on osaka makes + // the post-activation block format IDENTICAL to Osaka and adds ONLY the two + // AERE features below: (a) the 5 PQC precompiles and (b) EIP-2935. + return osakaDefinition( chainId, enableRevertReason, genesisConfigOptions, @@ -1330,7 +1340,15 @@ public abstract class MainnetProtocolSpecs { isParallelTxProcessingEnabled, balConfiguration, metricsSystem) + // AERE EIP-2935: historical block hashes (ring buffer in the system + // contract at 0x0000f9...2935), wired into the SAME futureEips (AerePQC) + // hard fork as the PQC precompiles so a single futureEipsTime activation + // delivers both. Forced on unconditionally here: the inherited Prague + // definition falls back to FrontierPreExecutionProcessor for QBFT/PoA + // chains without system-contract addresses, which would silently skip + // EIP-2935 history storage. This override restores it, protocol-native. + .preExecutionProcessor(new PraguePreExecutionProcessor()) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::futureEips) .hardforkId(FUTURE_EIPS); } diff --git a/evm/build.gradle b/evm/build.gradle index b416c99..9b4e0a5 100644 --- a/evm/build.gradle +++ b/evm/build.gradle @@ -37,6 +37,7 @@ dependencies { annotationProcessor 'com.google.dagger:dagger-compiler' implementation project(':crypto:algorithms') + implementation 'org.bouncycastle:bcprov-jdk18on' implementation project(':datatypes') implementation project(':ethereum:rlp') implementation project(':util')