Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/Nethermind
Submodule Nethermind updated 43 files
+3 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs
+3 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs
+3 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumBlockChainTests.cs
+3 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs
+0 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunBlockChainTests.cs
+0 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs
+3 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierBlockChainTests.cs
+3 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs
+3 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadBlockChainTests.cs
+3 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs
+3 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulBlockChainTests.cs
+3 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs
+0 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaBlockChainTests.cs
+0 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaEofTests.cs
+0 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaStateTests.cs
+0 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiBlockChainTests.cs
+3 −1 src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs
+1 −0 src/Nethermind/Ethereum.Test.Base/BlockchainTest.cs
+196 −117 src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+1 −0 src/Nethermind/Ethereum.Test.Base/BlockchainTestJson.cs
+4 −9 src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs
+17 −14 src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
+149 −85 src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
+0 −1 src/Nethermind/Ethereum.Test.Base/LoadBlockchainTestFileStrategy.cs
+7 −0 src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs
+36 −0 src/Nethermind/Ethereum.Test.Base/TestEngineNewPayloadsJson.cs
+0 −2 src/Nethermind/Nethermind.Blockchain.Test/BeaconBlockRootHandlerTests.cs
+67 −0 src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs
+4 −4 src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs
+1 −1 src/Nethermind/Nethermind.Blockchain/Blocks/IBlockhashStore.cs
+3 −1 src/Nethermind/Nethermind.Core.Test/Modules/TestMergeModule.cs
+6 −0 src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs
+0 −1 src/Nethermind/Nethermind.Merge.Plugin.Test/ExecutionRequestsProcessorMock.cs
+0 −1 src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs
+17 −0 src/Nethermind/Nethermind.Merge.Plugin/NoEngineRequestTracker.cs
+1 −0 src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs
+1 −0 src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs
+1 −0 src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs
+1 −0 src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs
+1 −0 src/Nethermind/Nethermind.Specs/ReleaseSpec.cs
+0 −2 src/Nethermind/Nethermind.State.Test/StateProviderTests.cs
+10 −9 src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs
+19 −13 src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ namespace Nethermind.Arbitrum.Test.Infrastructure;

public static class FullChainSimulationChainSpecProvider
{
public static ChainSpec Create()
public static ChainSpec Create(ulong initialArbOsVersion = 32)
{
var chainSpec = new ChainSpec
ChainSpec chainSpec = new()
{
Name = "Arbitrum Full Chain Simulation",
DataDir = "arbitrum-local",
Expand Down Expand Up @@ -65,7 +65,7 @@ public static ChainSpec Create()

TerminalTotalDifficulty = UInt256.Parse("0x3c6568f12e8000"),
Parameters = CreateChainParameters(),
EngineChainSpecParametersProvider = CreateEngineProvider(),
EngineChainSpecParametersProvider = CreateEngineProvider(initialArbOsVersion),
Allocations = CreateAllocations()
};

Expand Down Expand Up @@ -140,15 +140,17 @@ private static ChainParameters CreateChainParameters()
Eip7002ContractAddress = new Address("0x00000961ef480eb55e80d19ad83579a64c007002"),
Eip7251ContractAddress = new Address("0x0000bbddc7ce488642fb579f8b00f3a590007251"),
Eip2935ContractAddress = new Address("0x0000f90827f1c53a10cb7a02335b175320002935"),

Eip2935RingBufferSize = 393168
};
}

private static IChainSpecParametersProvider CreateEngineProvider()
private static IChainSpecParametersProvider CreateEngineProvider(ulong initialArbOsVersion = 32)
{
return new TestChainSpecParametersProvider(new ArbitrumChainSpecEngineParameters
{
Enabled = true,
InitialArbOSVersion = 32,
InitialArbOSVersion = initialArbOsVersion,
InitialChainOwner = new Address("0x5E1497dD1f08C87b2d8FE23e9AAB6c1De833D927"),
GenesisBlockNum = 0,
EnableArbOS = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public FullChainSimulationReleaseSpec()
IsEip4844Enabled = false; // Disable blobs gas calculation
IsEip4895Enabled = false; // Disable withdrawals
IsEip3541Enabled = false; // Disable contract code validation

Eip2935RingBufferSize = 393168;
}

/// <summary>
Expand Down
49 changes: 47 additions & 2 deletions src/Nethermind.Arbitrum.Test/Rpc/ArbitrumEthRpcModuleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

using FluentAssertions;
using Nethermind.Abi;
using Nethermind.Arbitrum.Arbos;
using Nethermind.Arbitrum.Data;
using Nethermind.Arbitrum.Test.Infrastructure;
using Nethermind.Blockchain.Find;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Core.Test.Builders;
using Nethermind.Crypto;
Expand All @@ -15,6 +17,7 @@
using Nethermind.Int256;
using Nethermind.JsonRpc;
using Nethermind.JsonRpc.Data;
using Nethermind.Specs.ChainSpecStyle;

namespace Nethermind.Arbitrum.Test.Rpc;

Expand All @@ -30,9 +33,10 @@ public class ArbitrumEthRpcModuleTests
[SetUp]
public void Setup()
{
_chain = ArbitrumRpcTestBlockchain.CreateDefault();
ChainSpec chainSpec = FullChainSimulationChainSpecProvider.Create(40);
_chain = ArbitrumRpcTestBlockchain.CreateDefault(null, chainSpec);

var initMessage = FullChainSimulationInitMessage.CreateDigestInitMessage(92);
DigestInitMessage initMessage = FullChainSimulationInitMessage.CreateDigestInitMessage(92, 40);
_chain.ArbitrumRpcModule.DigestInitMessage(initMessage);

_ethereumEcdsa = new EthereumEcdsa(_chain.SpecProvider.ChainId);
Expand Down Expand Up @@ -275,6 +279,47 @@ public async Task EthEstimateGas_WhenInvalidCallData_ReturnsExecutionError()
result.Result.ResultType.Should().Be(ResultType.Failure);
}

[Test]
public async Task EthGetStorageAt_HistoricalBlockHashes_ReturnsCorrectHashesForAll300Blocks()
{
// Produce 310 blocks to exceed a test threshold
const int targetBlocks = 310;
for (int i = 0; i < targetBlocks; i++)
await ProduceBlockWithBaseFee(1.Wei());

// Get the current head block
Block? head = _chain.BlockTree.Head;
head.Should().NotBeNull();
head!.Number.Should().BeGreaterThan(300);

// Forward loop from block 0 to head, matching Nitro's test logic
// See: arbitrum-nitro/system_tests/historical_block_hash_test.go
for (ulong i = 0; i < (ulong)head.Number; i++)
{
// Calculate the storage index for this block number
UInt256 storageIndex = new(i % (ulong)_chain.ChainSpec.Parameters.Eip2935RingBufferSize);

// Query history storage contract via RPC
ResultWrapper<byte[]> result = _chain.ArbitrumEthRpcModule.eth_getStorageAt(
Eip2935Constants.BlockHashHistoryAddress,
storageIndex,
BlockParameter.Latest);

result.Result.ResultType.Should().Be(ResultType.Success,
$"Block {i}: storage query should succeed");

// Get expected block by number
Block? expectedBlock = _chain.BlockTree.FindBlock((long)i);
expectedBlock.Should().NotBeNull($"Block {i} should exist");

// Verify stored hash matches block i's hash
result.Data.Should().NotBeNullOrEmpty($"Block {i}: storage should contain hash");
Hash256 storedHash = new(result.Data!);
storedHash.Should().Be(expectedBlock!.Hash!,
$"Block {i}: stored hash should match actual block hash");
}
}

private async Task ProduceBlockWithBaseFee(UInt256 baseFee)
{
TestEthDeposit deposit = new(
Expand Down
5 changes: 5 additions & 0 deletions src/Nethermind.Arbitrum/Arbos/ArbosState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ public void UpgradeArbosVersion(ulong targetVersion, bool isFirstTime, IWorldSta
break;

case 40: // ArbosVersion_40
// EIP-2935: Add support for historical block hashes
worldState.CreateAccountIfNotExists(Eip2935Constants.BlockHashHistoryAddress, UInt256.Zero, UInt256.One);
worldState.InsertCode(Eip2935Constants.BlockHashHistoryAddress, Precompiles.HistoryStorageCodeHash,
Precompiles.HistoryStorageCodeArbitrum,
genesisSpec, true);
StylusParams stylusParamsV40 = Programs.GetParams();
stylusParamsV40.UpgradeToArbosVersion(nextArbosVersion);
stylusParamsV40.Save();
Expand Down
13 changes: 13 additions & 0 deletions src/Nethermind.Arbitrum/Arbos/Precompiles.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Frozen;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Evm;

namespace Nethermind.Arbitrum.Arbos;
Expand All @@ -10,6 +11,18 @@ public static class Precompiles
public static readonly byte[] InvalidCode = [(byte)Instruction.INVALID];
public static readonly Hash256 InvalidCodeHash = Keccak.Compute(InvalidCode);

// EIP-2935 - Serve historical block hashes from state (Arbitrum version)
// Differs from the original EIP-2935 in two aspects:
// 1. Buffer size is 393,168 blocks instead of 8191
// 2. Uses arb_block_num (L2 block number) instead of number (L1 block number)
// See: https://github.com/OffchainLabs/sys-asm/blob/main/src/execution_hash/main.eas
// See: https://github.com/OffchainLabs/go-ethereum/blob/57fe4b732d4e640e696da40773f2dacba97e722b/params/protocol_params.go#L221
public static readonly byte[] HistoryStorageCodeArbitrum =
Bytes.FromHexString(
"0x3373fffffffffffffffffffffffffffffffffffffffe1460605760203603605c575f3563a3b1b31d5f5260205f6004601c60645afa15605c575f51600181038211605c57816205ffd0910311605c576205ffd09006545f5260205ff35b5f5ffd5b5f356205ffd0600163a3b1b31d5f5260205f6004601c60645afa15605c575f5103065500");

public static readonly Hash256 HistoryStorageCodeHash = Keccak.Compute(HistoryStorageCodeArbitrum);

public static readonly IReadOnlyDictionary<Address, ulong> PrecompileMinArbOSVersions = new Dictionary<Address, ulong>
{
[ArbosAddresses.ArbosAddress] = 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ private static void ApplyArbitrumOverrides(ReleaseSpec spec, ulong arbosVersion)
spec.IsEip7702Enabled = pragueEnabled;
spec.IsEip2537Enabled = pragueEnabled;

// EIP-2935: Historical block hash storage (ArbOS v40+)
// Arbitrum uses a larger ring buffer (393,168 blocks vs Ethereum's 8,191)
// This provides ~1 day of history at Arbitrum's 0.22s block time
bool eip2935Enabled = arbosVersion >= ArbosVersion.Forty;
spec.IsEip2935Enabled = eip2935Enabled;
spec.IsEip7709Enabled = eip2935Enabled; // BLOCKHASH opcode reads from state

// Disable contract code validation as Arbitrum stores Stylus bytecode
spec.IsEip3541Enabled = false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using Nethermind.Blockchain;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Eip2930;
using Nethermind.Core.Specs;
using Nethermind.Evm;
using Nethermind.Evm.Tracing;
Expand Down Expand Up @@ -419,7 +418,6 @@ private ArbitrumTransactionProcessorResult ProcessArbitrumInternalTransaction(

if (_arbosState!.CurrentArbosVersion >= ArbosVersion.ParentBlockHashSupport)
{
ProcessParentBlockHash(prevHash, _tracingInfo!.Tracer);
}

Dictionary<string, object> callArguments =
Expand Down Expand Up @@ -713,25 +711,6 @@ private ArbitrumTransactionProcessorResult ProcessArbitrumRetryTransaction(
return new(true, TransactionResult.Ok);
}

private void ProcessParentBlockHash(ValueHash256 prevHash, ITxTracer tracer)
{
AccessList.Builder builder = new AccessList.Builder()
.AddAddress(Eip2935Constants.BlockHashHistoryAddress);

Transaction newTransaction = new()
{
SenderAddress = Address.SystemUser,
GasLimit = 30_000_000,
GasPrice = UInt256.Zero,
DecodedMaxFeePerGas = UInt256.Zero,
To = Eip2935Constants.BlockHashHistoryAddress,
AccessList = builder.Build(),
Data = prevHash.Bytes.ToArray()
};

base.Execute(newTransaction, tracer, ExecutionOptions.Commit);
}

private static void TryReapOneRetryable(
ArbosState arbosState,
ulong currentTimestamp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"eip6780TransitionTimestamp": "0x65B97D60",
"eip2537TransitionTimestamp": "0x67C7FD60",
"eip2935TransitionTimestamp": "0x67C7FD60",
"eip2935RingBufferSize": "0x5FFD0",
"eip7702TransitionTimestamp": "0x67C7FD60",
"minHistoryRetentionEpochs": "0x0",
"eip7934MaxRlpBlockSize": "0x0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"eip6780TransitionTimestamp": "0x65B97D60",
"eip2537TransitionTimestamp": "0x67C7FD60",
"eip2935TransitionTimestamp": "0x67C7FD60",
"eip2935RingBufferSize": "0x5FFD0",
"eip7702TransitionTimestamp": "0x67C7FD60"
},
"genesis": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"eip6780TransitionTimestamp": "0x65B97D60",
"eip2537TransitionTimestamp": "0x67C7FD60",
"eip2935TransitionTimestamp": "0x67C7FD60",
"eip2935RingBufferSize": "0x5FFD0",
"eip7702TransitionTimestamp": "0x67C7FD60",
"minHistoryRetentionEpochs": "0x0",
"eip7934MaxRlpBlockSize": "0x0"
Expand All @@ -67,7 +68,7 @@
"seal": {
"ethereum": {
"nonce": "0x1",
"mixHash": "0x0000000000000000000000000000000028000000000000000000000000000000"
"mixHash": "0x0000000000000000000000000000000000000000000000280000000000000000"
}
},
"number": "0x0",
Expand All @@ -82,10 +83,10 @@
"nodes": [],
"accounts": {
"26E554a8acF9003b83495c7f45F06edCB803d4e3": {
"balance": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7"
"balance": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7"
},
"aF24Ca6c2831f4d4F629418b50C227DF0885613A": {
"balance": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7"
"balance": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7"
}
}
}