diff --git a/Makefile b/Makefile index 1bff18273..780861c4f 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,17 @@ clean-run-sepolia-verify: ## Clean .data and start Nethermind Arbitrum node (Sep @$(MAKE) clean @$(MAKE) run-sepolia-verify +run-mainnet: ## Start Nethermind Arbitrum node (Mainnet) without cleaning .data + @echo "Starting Nethermind Arbitrum node (Mainnet) with metrics..." + cd $(BUILD_OUTPUT_DIR) && dotnet nethermind.dll -c arbitrum-mainnet-archive \ + --data-dir $(ROOT_DIR)/.data \ + --Snapshot.Enabled true \ + --Snapshot.DownloadUrl "https://drive.usercontent.google.com/download?id=1Pf2jTRqgy41dZ-phpyDBvKHqrnQniKgJ&export=download&authuser=1&confirm=t&uuid=55e02503-d00b-4efa-8eb1-9cfaab8d49c8&at=AKSUxGMRmuAIU5MHSL33qOFtwc1q:1760799619104" + +clean-run-mainnet: ## Clean .data and start Nethermind Arbitrum node (Mainnet) + @$(MAKE) clean + @$(MAKE) run-mainnet + run-sepolia-monitoring: ## Start monitoring stack and Nethermind Arbitrum node (Sepolia) @echo "Starting monitoring stack..." @./start-monitoring.sh diff --git a/src/Nethermind b/src/Nethermind index 6b9f037be..677263728 160000 --- a/src/Nethermind +++ b/src/Nethermind @@ -1 +1 @@ -Subproject commit 6b9f037bece6840a8bcad6d5a79af6f87bb60a92 +Subproject commit 677263728ed9d9f2a933667557974ecfb38673b9 diff --git a/src/Nethermind.Arbitrum.Test/Execution/ArbitrumTransactionProcessorTests.cs b/src/Nethermind.Arbitrum.Test/Execution/ArbitrumTransactionProcessorTests.cs index d190ccc68..12bf2b659 100644 --- a/src/Nethermind.Arbitrum.Test/Execution/ArbitrumTransactionProcessorTests.cs +++ b/src/Nethermind.Arbitrum.Test/Execution/ArbitrumTransactionProcessorTests.cs @@ -4,6 +4,7 @@ using Nethermind.Arbitrum.Arbos; using Nethermind.Arbitrum.Arbos.Compression; using Nethermind.Arbitrum.Arbos.Storage; +using Nethermind.Arbitrum.Config; using Nethermind.Arbitrum.Core; using Nethermind.Arbitrum.Data.Transactions; using Nethermind.Arbitrum.Evm; @@ -1633,8 +1634,8 @@ public void ArbitrumTransaction_WithArbitrumBlockHeader_ProcessesCorrectly() genesis.Header.BaseFeePerGas = blockBaseFee; - // NEW: Create ArbitrumBlockHeader with original base fee stored - ArbitrumBlockHeader arbitrumHeader = new ArbitrumBlockHeader(genesis.Header, originalBaseFee); + ArbitrumChainSpecEngineParameters chainSpecParams = new() { GenesisBlockNum = 0 }; + ArbitrumBlockHeader arbitrumHeader = new(genesis.Header, originalBaseFee, (long)chainSpecParams.GenesisBlockNum!); arbitrumHeader.BaseFeePerGas = 0; // Set to 0 for EVM execution (NoBaseFee behavior) BlockExecutionContext blCtx = new(arbitrumHeader, fullChainSimulationSpecProvider.GetSpec(arbitrumHeader)); @@ -1798,11 +1799,10 @@ public void ArbitrumTransaction_WithArbitrumBlockHeader_UsesOriginalBaseFeeForGa _logManager ); - UInt256 blockBaseFee = (UInt256)1500; UInt256 originalBaseFee = (UInt256)3000; - // Create ArbitrumBlockHeader with original base fee stored - ArbitrumBlockHeader arbitrumHeader = new ArbitrumBlockHeader(genesis.Header, originalBaseFee); + ArbitrumChainSpecEngineParameters chainSpecParams = new() { GenesisBlockNum = 0 }; + ArbitrumBlockHeader arbitrumHeader = new(genesis.Header, originalBaseFee, (long)chainSpecParams.GenesisBlockNum!); arbitrumHeader.BaseFeePerGas = 0; // Set to 0 for EVM execution (NoBaseFee behavior) BlockExecutionContext blCtx = new(arbitrumHeader, fullChainSimulationSpecProvider.GetSpec(arbitrumHeader)); @@ -1879,8 +1879,8 @@ public void ArbitrumBlockHeader_StoresOriginalBaseFeeCorrectly() genesis.Header.BaseFeePerGas = blockBaseFee; - // Create ArbitrumBlockHeader - ArbitrumBlockHeader arbitrumHeader = new(genesis.Header, originalBaseFee); + ArbitrumChainSpecEngineParameters chainSpecParams = new() { GenesisBlockNum = 0 }; + ArbitrumBlockHeader arbitrumHeader = new(genesis.Header, originalBaseFee, (long)chainSpecParams.GenesisBlockNum!); // Verify it copies all properties correctly arbitrumHeader.ParentHash.Should().Be(genesis.Header.ParentHash); diff --git a/src/Nethermind.Arbitrum.Test/Infrastructure/ArbitrumRpcTestBlockchain.cs b/src/Nethermind.Arbitrum.Test/Infrastructure/ArbitrumRpcTestBlockchain.cs index fb91fe3ad..a7c5c26cb 100644 --- a/src/Nethermind.Arbitrum.Test/Infrastructure/ArbitrumRpcTestBlockchain.cs +++ b/src/Nethermind.Arbitrum.Test/Infrastructure/ArbitrumRpcTestBlockchain.cs @@ -271,7 +271,8 @@ private static ArbitrumRpcTestBlockchain CreateInternal(ArbitrumRpcTestBlockchai chain.Container.Resolve(), chain.Container.Resolve(), chain.Container.Resolve(), - chain.Container.Resolve().SecondsPerSlot + chain.Container.Resolve().SecondsPerSlot, + chain.Container.Resolve() ); return chain; diff --git a/src/Nethermind.Arbitrum.Test/Rpc/ArbitrumRpcModuleTests.cs b/src/Nethermind.Arbitrum.Test/Rpc/ArbitrumRpcModuleTests.cs index ec06331ef..344e8837d 100644 --- a/src/Nethermind.Arbitrum.Test/Rpc/ArbitrumRpcModuleTests.cs +++ b/src/Nethermind.Arbitrum.Test/Rpc/ArbitrumRpcModuleTests.cs @@ -130,7 +130,7 @@ public async Task ResultAtMessageIndex_BlockNotFound_ReturnsFailResult() Assert.Multiple(() => { Assert.That(result.Result.ResultType, Is.EqualTo(ResultType.Failure)); - Assert.That(result.Result.Error, Does.Contain(ArbitrumRpcErrors.BlockNotFound)); + Assert.That(result.Result.Error, Does.Contain(ArbitrumRpcErrors.BlockNotFound((long)blockNumber))); }); } diff --git a/src/Nethermind.Arbitrum/ArbitrumPlugin.cs b/src/Nethermind.Arbitrum/ArbitrumPlugin.cs index 1c9be09b5..706d6135a 100644 --- a/src/Nethermind.Arbitrum/ArbitrumPlugin.cs +++ b/src/Nethermind.Arbitrum/ArbitrumPlugin.cs @@ -8,13 +8,19 @@ using Nethermind.Api.Steps; using Nethermind.Arbitrum.Arbos; using Nethermind.Arbitrum.Config; +using Nethermind.Arbitrum.Core; using Nethermind.Arbitrum.Evm; using Nethermind.Arbitrum.Execution; using Nethermind.Arbitrum.Execution.Transactions; using Nethermind.Arbitrum.Genesis; +using Nethermind.Arbitrum.Init; using Nethermind.Arbitrum.Modules; using Nethermind.Arbitrum.Precompiles; using Nethermind.Arbitrum.Stylus; +using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; +using Nethermind.Blockchain.Headers; +using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Consensus; using Nethermind.Consensus.Processing; @@ -22,6 +28,8 @@ using Nethermind.Core; using Nethermind.Core.Container; using Nethermind.Core.Specs; +using Nethermind.Db; +using Nethermind.Db.Blooms; using Nethermind.Db.Rocks.Config; using Nethermind.Evm; using Nethermind.Evm.State; @@ -32,8 +40,10 @@ using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules; using Nethermind.JsonRpc.Modules.Eth; +using Nethermind.Logging; using Nethermind.Serialization.Rlp; using Nethermind.Specs.ChainSpecStyle; +using Nethermind.State.Repositories; namespace Nethermind.Arbitrum; @@ -174,6 +184,7 @@ protected override void Load(ContainerBuilder builder) .AddStep(typeof(ArbitrumInitializeBlockchain)) .AddStep(typeof(ArbitrumInitializeWasmDb)) .AddStep(typeof(ArbitrumInitializeStylusNative)) + .AddStep(typeof(ArbitrumInitializeGenesis)) .AddDatabase(WasmDb.DbName) .AddDecorator() @@ -186,6 +197,8 @@ protected override void Load(ContainerBuilder builder) return new WasmStore(wasmDb, new StylusTargetConfig(), cacheTag: 1); }) + .AddSingleton() + .AddSingleton() .AddSingleton() diff --git a/src/Nethermind.Arbitrum/Config/ArbitrumInitializeBlockchain.cs b/src/Nethermind.Arbitrum/Config/ArbitrumInitializeBlockchain.cs index 09dd302a0..09f02d213 100644 --- a/src/Nethermind.Arbitrum/Config/ArbitrumInitializeBlockchain.cs +++ b/src/Nethermind.Arbitrum/Config/ArbitrumInitializeBlockchain.cs @@ -3,9 +3,7 @@ using Nethermind.TxPool; namespace Nethermind.Arbitrum.Config; - public class ArbitrumInitializeBlockchain(ArbitrumNethermindApi api, IChainHeadInfoProvider chainHeadInfoProvider) : InitializeBlockchain(api, chainHeadInfoProvider) { protected override IBlockProductionPolicy CreateBlockProductionPolicy() => AlwaysStartBlockProductionPolicy.Instance; - } diff --git a/src/Nethermind.Arbitrum/Core/ArbitrumBlockHeader.cs b/src/Nethermind.Arbitrum/Core/ArbitrumBlockHeader.cs index 2e2f0f084..f787bf67e 100644 --- a/src/Nethermind.Arbitrum/Core/ArbitrumBlockHeader.cs +++ b/src/Nethermind.Arbitrum/Core/ArbitrumBlockHeader.cs @@ -9,9 +9,11 @@ namespace Nethermind.Arbitrum.Core; public class ArbitrumBlockHeader : BlockHeader { + private readonly long _genesisBlockNumber; + public override long GenesisBlockNumber => _genesisBlockNumber; public UInt256 OriginalBaseFee { get; set; } - public ArbitrumBlockHeader(BlockHeader original, UInt256 originalBaseFee) : base( + public ArbitrumBlockHeader(BlockHeader original, UInt256 originalBaseFee, long genesisBlockNumber) : base( original.ParentHash ?? Hash256.Zero, original.UnclesHash ?? Hash256.Zero, original.Beneficiary ?? Address.Zero, @@ -25,6 +27,7 @@ public ArbitrumBlockHeader(BlockHeader original, UInt256 originalBaseFee) : base original.ParentBeaconBlockRoot, original.RequestsHash) { + _genesisBlockNumber = genesisBlockNumber; OriginalBaseFee = originalBaseFee; Author = original.Author; diff --git a/src/Nethermind.Arbitrum/Core/ArbitrumBlockTree.cs b/src/Nethermind.Arbitrum/Core/ArbitrumBlockTree.cs new file mode 100644 index 000000000..87c143ffb --- /dev/null +++ b/src/Nethermind.Arbitrum/Core/ArbitrumBlockTree.cs @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Arbitrum.Config; +using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; +using Nethermind.Blockchain.Headers; +using Nethermind.Blockchain.Synchronization; +using Nethermind.Core.Specs; +using Nethermind.Db; +using Nethermind.Db.Blooms; +using Nethermind.Logging; +using Nethermind.State.Repositories; + +namespace Nethermind.Arbitrum.Core; + +public class ArbitrumBlockTree( + IBlockStore blockStore, + IHeaderStore headerStore, + IDbProvider dbProvider, + IBadBlockStore badBlockStore, + IChainLevelInfoRepository chainLevelInfoRepository, + ISpecProvider specProvider, + IBloomStorage bloomStorage, + ISyncConfig syncConfig, + ILogManager logManager, + ArbitrumChainSpecEngineParameters chainSpecParams) + : BlockTree( + blockStore, + headerStore, + dbProvider.BlockInfosDb, + dbProvider.MetadataDb, + badBlockStore, + chainLevelInfoRepository, + specProvider, + bloomStorage, + syncConfig, + logManager, + (long)chainSpecParams.GenesisBlockNum!) +{ +} diff --git a/src/Nethermind.Arbitrum/Genesis/ArbitrumInitializeGenesis.cs b/src/Nethermind.Arbitrum/Genesis/ArbitrumInitializeGenesis.cs new file mode 100644 index 000000000..56ab79c69 --- /dev/null +++ b/src/Nethermind.Arbitrum/Genesis/ArbitrumInitializeGenesis.cs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Api.Steps; +using Nethermind.Arbitrum.Config; +using Nethermind.Blockchain; +using Nethermind.Core; +using Nethermind.Evm.State; +using Nethermind.Init.Steps; +using Nethermind.Logging; + +namespace Nethermind.Arbitrum.Init; + +[RunnerStepDependencies(typeof(InitDatabase))] +public class ArbitrumInitializeGenesis : IStep +{ + private readonly ArbitrumNethermindApi _api; + private readonly IArbitrumSpecHelper _specHelper; + private readonly ILogger _logger; + + public ArbitrumInitializeGenesis(ArbitrumNethermindApi api, IArbitrumSpecHelper specHelper) + { + _api = api; + _specHelper = specHelper; + _logger = _api.LogManager.GetClassLogger(); + } + + public Task Execute(CancellationToken cancellationToken) + { + if (!_specHelper.Enabled) + return Task.CompletedTask; + + long arbitrumGenesisBlockNum = (long)_specHelper.GenesisBlockNum; + + if (arbitrumGenesisBlockNum == 0) + { + _logger.Info("Arbitrum genesis block number is 0, skipping initialization"); + return Task.CompletedTask; + } + + Block? arbitrumGenesisBlock = _api.BlockTree!.FindBlock(arbitrumGenesisBlockNum, BlockTreeLookupOptions.None); + + if (arbitrumGenesisBlock is null) + { + throw new InvalidOperationException( + $"Arbitrum genesis block {arbitrumGenesisBlockNum} not found in BlockTree. " + + "Ensure the snapshot was downloaded correctly before this step."); + } + + _logger.Info($"Arbitrum genesis block {arbitrumGenesisBlockNum} already exists (hash: {arbitrumGenesisBlock.Hash})"); + + // Re-establish state registration by running the state initialization + _logger.Info("Re-initializing genesis state registration..."); + + IWorldState worldState = _api.WorldStateManager.GlobalWorldState; + using (worldState.BeginScope(IWorldState.PreGenesis)) + { + worldState.CommitTree(arbitrumGenesisBlockNum); + _logger.Info($"State tree committed for genesis block {arbitrumGenesisBlockNum}"); + } + + return Task.CompletedTask; + } +} diff --git a/src/Nethermind.Arbitrum/Modules/ArbitrumEthModuleFactory.cs b/src/Nethermind.Arbitrum/Modules/ArbitrumEthModuleFactory.cs index 0a851c835..113cef4c7 100644 --- a/src/Nethermind.Arbitrum/Modules/ArbitrumEthModuleFactory.cs +++ b/src/Nethermind.Arbitrum/Modules/ArbitrumEthModuleFactory.cs @@ -1,12 +1,10 @@ // SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using Nethermind.Arbitrum.Evm; using Nethermind.Blockchain; using Nethermind.Blockchain.Receipts; using Nethermind.Config; using Nethermind.Core.Specs; -using Nethermind.Evm; using Nethermind.Facade; using Nethermind.Facade.Eth; using Nethermind.JsonRpc; @@ -19,83 +17,48 @@ using Nethermind.State; using Nethermind.TxPool; using Nethermind.Wallet; -using System; +using Nethermind.Arbitrum.Config; namespace Nethermind.Arbitrum.Modules; -public class ArbitrumEthModuleFactory : ModuleFactoryBase +public class ArbitrumEthModuleFactory( + ITxPool txPool, + ITxSender txSender, + IWallet wallet, + IBlockTree blockTree, + IJsonRpcConfig jsonRpcConfig, + ILogManager logManager, + IStateReader stateReader, + IBlockchainBridgeFactory blockchainBridgeFactory, + ISpecProvider specProvider, + IReceiptStorage receiptStorage, + IGasPriceOracle gasPriceOracle, + IEthSyncingInfo ethSyncingInfo, + IFeeHistoryOracle feeHistoryOracle, + IProtocolsManager protocolsManager, + IForkInfo forkInfo, + IBlocksConfig blocksConfig, + ArbitrumChainSpecEngineParameters chainSpecParams) : ModuleFactoryBase { - private readonly ITxPool _txPool; - private readonly ITxSender _txSender; - private readonly IWallet _wallet; - private readonly IBlockTree _blockTree; - private readonly IJsonRpcConfig _jsonRpcConfig; - private readonly ILogManager _logManager; - private readonly IStateReader _stateReader; - private readonly IBlockchainBridgeFactory _blockchainBridgeFactory; - private readonly ISpecProvider _specProvider; - private readonly IReceiptStorage _receiptStorage; - private readonly IGasPriceOracle _gasPriceOracle; - private readonly IEthSyncingInfo _ethSyncingInfo; - private readonly IFeeHistoryOracle _feeHistoryOracle; - private readonly IProtocolsManager _protocolsManager; - private readonly IForkInfo _forkInfo; - private readonly ulong? _secondsPerSlot; - - public ArbitrumEthModuleFactory( - ITxPool txPool, - ITxSender txSender, - IWallet wallet, - IBlockTree blockTree, - IJsonRpcConfig jsonRpcConfig, - ILogManager logManager, - IStateReader stateReader, - IBlockchainBridgeFactory blockchainBridgeFactory, - ISpecProvider specProvider, - IReceiptStorage receiptStorage, - IGasPriceOracle gasPriceOracle, - IEthSyncingInfo ethSyncingInfo, - IFeeHistoryOracle feeHistoryOracle, - IProtocolsManager protocolsManager, - IForkInfo forkInfo, - IBlocksConfig blocksConfig) - { - _txPool = txPool; - _txSender = txSender; - _wallet = wallet; - _blockTree = blockTree; - _jsonRpcConfig = jsonRpcConfig; - _logManager = logManager; - _stateReader = stateReader; - _blockchainBridgeFactory = blockchainBridgeFactory; - _specProvider = specProvider; - _receiptStorage = receiptStorage; - _gasPriceOracle = gasPriceOracle; - _ethSyncingInfo = ethSyncingInfo; - _feeHistoryOracle = feeHistoryOracle; - _protocolsManager = protocolsManager; - _forkInfo = forkInfo; - _secondsPerSlot = blocksConfig.SecondsPerSlot; - } - public override IEthRpcModule Create() { return new ArbitrumEthRpcModule( - _jsonRpcConfig, - _blockchainBridgeFactory.CreateBlockchainBridge(), - _blockTree, - _receiptStorage, - _stateReader, - _txPool, - _txSender, - _wallet, - _logManager, - _specProvider, - _gasPriceOracle, - _ethSyncingInfo, - _feeHistoryOracle, - _protocolsManager, - _forkInfo, - _secondsPerSlot); + jsonRpcConfig, + blockchainBridgeFactory.CreateBlockchainBridge(), + blockTree, + receiptStorage, + stateReader, + txPool, + txSender, + wallet, + logManager, + specProvider, + gasPriceOracle, + ethSyncingInfo, + feeHistoryOracle, + protocolsManager, + forkInfo, + blocksConfig.SecondsPerSlot, + chainSpecParams); } } diff --git a/src/Nethermind.Arbitrum/Modules/ArbitrumEthRpcModule.cs b/src/Nethermind.Arbitrum/Modules/ArbitrumEthRpcModule.cs index c315de7f7..eb1a54185 100644 --- a/src/Nethermind.Arbitrum/Modules/ArbitrumEthRpcModule.cs +++ b/src/Nethermind.Arbitrum/Modules/ArbitrumEthRpcModule.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Arbitrum.Config; using Nethermind.Arbitrum.Core; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; @@ -30,6 +31,8 @@ namespace Nethermind.Arbitrum.Modules [RpcModule(ModuleType.Eth)] public class ArbitrumEthRpcModule : EthRpcModule { + private readonly ArbitrumChainSpecEngineParameters _chainSpecParams; + public ArbitrumEthRpcModule( IJsonRpcConfig rpcConfig, IBlockchainBridge blockchainBridge, @@ -46,9 +49,11 @@ public ArbitrumEthRpcModule( IFeeHistoryOracle feeHistoryOracle, IProtocolsManager protocolsManager, IForkInfo forkInfo, - ulong? secondsPerSlot) + ulong? secondsPerSlot, + ArbitrumChainSpecEngineParameters chainSpecParams) : base(rpcConfig, blockchainBridge, blockFinder, receiptFinder, stateReader, txPool, txSender, wallet, logManager, specProvider, gasPriceOracle, ethSyncingInfo, feeHistoryOracle, protocolsManager, forkInfo, secondsPerSlot) { + _chainSpecParams = chainSpecParams; } public override ResultWrapper eth_call( @@ -64,7 +69,7 @@ public override ResultWrapper eth_call( UInt256 originalBaseFee = searchResult.Object.BaseFeePerGas; - return new ArbitrumCallTxExecutor(_blockchainBridge, _blockFinder, _rpcConfig, originalBaseFee) + return new ArbitrumCallTxExecutor(_blockchainBridge, _blockFinder, _rpcConfig, originalBaseFee, _chainSpecParams) .Execute(transactionCall, blockParameter, stateOverride, searchResult); } @@ -81,7 +86,7 @@ public override ResultWrapper eth_call( UInt256 originalBaseFee = searchResult.Object.BaseFeePerGas; - return new ArbitrumEstimateGasTxExecutor(_blockchainBridge, _blockFinder, _rpcConfig, originalBaseFee) + return new ArbitrumEstimateGasTxExecutor(_blockchainBridge, _blockFinder, _rpcConfig, originalBaseFee, _chainSpecParams) .Execute(transactionCall, blockParameter, stateOverride, searchResult); } @@ -98,7 +103,7 @@ public override ResultWrapper eth_call( UInt256 originalBaseFee = searchResult.Object.BaseFeePerGas; - return new ArbitrumCreateAccessListTxExecutor(_blockchainBridge, _blockFinder, _rpcConfig, originalBaseFee, optimize) + return new ArbitrumCreateAccessListTxExecutor(_blockchainBridge, _blockFinder, _rpcConfig, originalBaseFee, _chainSpecParams, optimize) .Execute(transactionCall, blockParameter, null, searchResult); } @@ -106,10 +111,12 @@ private abstract class ArbitrumTxExecutor( IBlockchainBridge blockchainBridge, IBlockFinder blockFinder, IJsonRpcConfig rpcConfig, - UInt256 originalBaseFee) + UInt256 originalBaseFee, + ArbitrumChainSpecEngineParameters chainSpecParams) : ExecutorBase(blockchainBridge, blockFinder, rpcConfig) { protected readonly UInt256 _originalBaseFee = originalBaseFee; + protected readonly ArbitrumChainSpecEngineParameters _chainSpecParams = chainSpecParams; public override ResultWrapper Execute( TransactionForRpc transactionCall, @@ -141,7 +148,7 @@ protected override Transaction Prepare(TransactionForRpc call) protected override ResultWrapper Execute(BlockHeader header, Transaction tx, Dictionary? stateOverride, CancellationToken token) { // Create ArbitrumBlockHeader with original base fee - ArbitrumBlockHeader arbitrumHeader = new(header, _originalBaseFee); + ArbitrumBlockHeader arbitrumHeader = new(header, _originalBaseFee, (long)_chainSpecParams.GenesisBlockNum!); // Set base fee to 0 for EVM execution (like Ethereum's NoBaseFee) arbitrumHeader.BaseFeePerGas = 0; @@ -161,8 +168,9 @@ private class ArbitrumCallTxExecutor( IBlockchainBridge blockchainBridge, IBlockFinder blockFinder, IJsonRpcConfig rpcConfig, - UInt256 originalBaseFee) - : ArbitrumTxExecutor(blockchainBridge, blockFinder, rpcConfig, originalBaseFee) + UInt256 originalBaseFee, + ArbitrumChainSpecEngineParameters chainSpecParams) + : ArbitrumTxExecutor(blockchainBridge, blockFinder, rpcConfig, originalBaseFee, chainSpecParams) { protected override ResultWrapper ExecuteTx(BlockHeader header, Transaction tx, Dictionary? stateOverride, CancellationToken token) { @@ -178,8 +186,9 @@ private class ArbitrumEstimateGasTxExecutor( IBlockchainBridge blockchainBridge, IBlockFinder blockFinder, IJsonRpcConfig rpcConfig, - UInt256 originalBaseFee) - : ArbitrumTxExecutor(blockchainBridge, blockFinder, rpcConfig, originalBaseFee) + UInt256 originalBaseFee, + ArbitrumChainSpecEngineParameters chainSpecParams) + : ArbitrumTxExecutor(blockchainBridge, blockFinder, rpcConfig, originalBaseFee, chainSpecParams) { private readonly int _errorMargin = rpcConfig.EstimateErrorMargin; @@ -201,8 +210,9 @@ private class ArbitrumCreateAccessListTxExecutor( IBlockFinder blockFinder, IJsonRpcConfig rpcConfig, UInt256 originalBaseFee, + ArbitrumChainSpecEngineParameters chainSpecParams, bool optimize = true) - : ArbitrumTxExecutor(blockchainBridge, blockFinder, rpcConfig, originalBaseFee) + : ArbitrumTxExecutor(blockchainBridge, blockFinder, rpcConfig, originalBaseFee, chainSpecParams) { protected override ResultWrapper ExecuteTx(BlockHeader header, Transaction tx, Dictionary? stateOverride, CancellationToken token) { diff --git a/src/Nethermind.Arbitrum/Modules/ArbitrumRpcErrors.cs b/src/Nethermind.Arbitrum/Modules/ArbitrumRpcErrors.cs index a6a262674..d9092df4a 100644 --- a/src/Nethermind.Arbitrum/Modules/ArbitrumRpcErrors.cs +++ b/src/Nethermind.Arbitrum/Modules/ArbitrumRpcErrors.cs @@ -6,11 +6,12 @@ namespace Nethermind.Arbitrum.Modules public static class ArbitrumRpcErrors { public const string Overflow = "Overflow occurred while calculating block number"; - public const string BlockNotFound = "Block not found or not synced"; public const string InternalError = "Internal error processing request"; + public static string BlockNotFound(long blockNumber) => + $"Block {blockNumber} not found or not synced"; + public static string FormatNullParameters() => "Parameters cannot be null"; } } - diff --git a/src/Nethermind.Arbitrum/Modules/ArbitrumRpcModule.cs b/src/Nethermind.Arbitrum/Modules/ArbitrumRpcModule.cs index f721d2fdf..12f508f27 100644 --- a/src/Nethermind.Arbitrum/Modules/ArbitrumRpcModule.cs +++ b/src/Nethermind.Arbitrum/Modules/ArbitrumRpcModule.cs @@ -107,7 +107,7 @@ public async Task> ResultAtMessageIndex(ulong messa BlockHeader? blockHeader = blockTree.FindHeader(blockNumberResult.Data, BlockTreeLookupOptions.None); if (blockHeader == null) - return ResultWrapper.Fail(ArbitrumRpcErrors.BlockNotFound); + return ResultWrapper.Fail(ArbitrumRpcErrors.BlockNotFound(blockNumberResult.Data)); if (Logger.IsTrace) Logger.Trace($"Found block header for block {blockNumberResult.Data}: hash={blockHeader.Hash}"); diff --git a/src/Nethermind.Arbitrum/Properties/chainspec/arbitrum-mainnet.json b/src/Nethermind.Arbitrum/Properties/chainspec/arbitrum-mainnet.json new file mode 100644 index 000000000..881073ed1 --- /dev/null +++ b/src/Nethermind.Arbitrum/Properties/chainspec/arbitrum-mainnet.json @@ -0,0 +1,89 @@ +{ + "name": "Arbitrum One", + "dataDir": "arbitrum-mainnet", + "engine": { + "Arbitrum": { + "initialArbOSVersion": 6, + "initialChainOwner": "0xd345e41ae2cb00311956aa7109fc801ae8c81a52", + "genesisBlockNum": 22207817, + "enableArbOS": true, + "allowDebugPrecompiles": false, + "dataAvailabilityCommittee": false + } + }, + "params": { + "gasLimitBoundDivisor": "0x400", + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID": "0xa4b1", + "forkBlock": "0x0", + "maxCodeSize": "0x6000", + "maxCodeSizeTransition": "0x0", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", + "eip155Transition": "0x0", + "eip140Transition": "0x0", + "eip211Transition": "0x0", + "eip214Transition": "0x0", + "eip658Transition": "0x0", + "eip145Transition": "0x0", + "eip1014Transition": "0x0", + "eip1052Transition": "0x0", + "eip1283Transition": "0x0", + "eip1283DisableTransition": "0x0", + "eip152Transition": "0x0", + "eip1108Transition": "0x0", + "eip1344Transition": "0x0", + "eip1884Transition": "0x0", + "eip2028Transition": "0x0", + "eip2200Transition": "0x0", + "eip2565Transition": "0x0", + "eip2929Transition": "0x0", + "eip2930Transition": "0x0", + "eip1559Transition": "0x0", + "eip3198Transition": "0x0", + "eip3529Transition": "0x0", + "eip3541Transition": "0x0", + "terminalTotalDifficulty": "3C6568F12E8000", + "mergeForkIdTransition": "0x0", + "beaconChainGenesisTimestamp": "0x62b07d60", + "eip3651TransitionTimestamp": "0x65DA8599", + "eip3855TransitionTimestamp": "0x65DA8599", + "eip3860TransitionTimestamp": "0x65DA8599", + "eip4844TransitionTimestamp": "0x65F28F89", + "eip1153TransitionTimestamp": "0x65F28F89", + "eip4788TransitionTimestamp": "0x65F28F89", + "eip5656TransitionTimestamp": "0x65F28F89", + "eip6780TransitionTimestamp": "0x65F28F89", + "eip2537TransitionTimestamp": "0x65F28F89", + "rip7212TransitionTimestamp": "0x66F3C9DA", + "eip2935TransitionTimestamp": "0x684D4B90", + "eip7702TransitionTimestamp": "0x684D4B90" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000060000000000000000" + } + }, + "stateRoot": "0x7f2bfc4481d02bfcfc606ebb949384ef78d03a0f30a2dc9cccd652eb80926ae1", + "number": "0x1529DD9", + "difficulty": "0x1", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x6310F0F6", + "parentHash": "0xa903d86321a537beab1a892c387c3198a6dd75dbd4a68346b04642770d20d8fe", + "extraData": "0x", + "gasLimit": "0x1000000000000", + "baseFeePerGas": "0x5f5e100" + }, + "nodes": [], + "accounts": { + "0000000000000000000000000000000000000000": { + "balance": "0x1" + } + } +} diff --git a/src/Nethermind.Arbitrum/Properties/configs/arbitrum-mainnet-archive.json b/src/Nethermind.Arbitrum/Properties/configs/arbitrum-mainnet-archive.json new file mode 100644 index 000000000..aac76bf27 --- /dev/null +++ b/src/Nethermind.Arbitrum/Properties/configs/arbitrum-mainnet-archive.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", + "Init": { + "ChainSpecPath": "chainspec/arbitrum-mainnet.json", + "BaseDbPath": "nethermind_db/arbitrum-mainnet-archive", + "LogFileName": "arbitrum-mainnet-archive.log" + }, + "TxPool": { + "BlobsSupport": "Disabled" + }, + "Discovery": { + "DiscoveryVersion": "V5" + }, + "JsonRpc": { + "Enabled": true, + "Port": 20545, + "EnginePort": 20551, + "UnsecureDevNoRpcAuthentication": true, + "AdditionalRpcUrls": [ + "http://localhost:28551|http;ws|net;eth;subscribe;web3;client;debug" + ], + "EnabledModules": [ + "Admin", + "Clique", + "Consensus", + "Db", + "Debug", + "Deposit", + "Erc20", + "Eth", + "Evm", + "Net", + "Nft", + "Parity", + "Personal", + "Proof", + "Subscribe", + "Trace", + "TxPool", + "Vault", + "Web3", + "Arbitrum" + ] + }, + "Pruning": { + "Mode": "None", + "MaxUnpersistedBlockCount": 4800, + "MinUnpersistedBlockCount": 72, + "MaxBufferedCommitCount": 0 + }, + "Blocks": { + "PreWarmStateOnBlockProcessing": false, + "BuildBlocksOnMainState": true + }, + "Metrics": { + "NodeName": "Nethermind Arbitrum One Archive" + }, + "Merge": { + "Enabled": true + }, + "Arbitrum": { + "BlockProcessingTimeout": 10000 + } +} diff --git a/src/Nethermind.Arbitrum/Properties/configs/arbitrum-mainnet.json b/src/Nethermind.Arbitrum/Properties/configs/arbitrum-mainnet.json new file mode 100644 index 000000000..de1ed420e --- /dev/null +++ b/src/Nethermind.Arbitrum/Properties/configs/arbitrum-mainnet.json @@ -0,0 +1,67 @@ +{ + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", + "Init": { + "ChainSpecPath": "chainspec/arbitrum-mainnet.json", + "BaseDbPath": "nethermind_db/arbitrum-mainnet", + "LogFileName": "arbitrum-mainnet.log" + }, + "TxPool": { + "BlobsSupport": "Disabled" + }, + "Sync": { + "NetworkingEnabled": false, + "FastSync": true, + "SnapSync": true, + "FastSyncCatchUpHeightDelta": "10000000000", + "PivotNumber": 260000000, + "PivotHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "Discovery": { + "DiscoveryVersion": "V5" + }, + "JsonRpc": { + "Enabled": true, + "Port": 20545, + "EnginePort": 20551, + "UnsecureDevNoRpcAuthentication": true, + "AdditionalRpcUrls": [ + "http://localhost:28551|http;ws|net;eth;subscribe;web3;client;debug" + ], + "EnabledModules": [ + "Admin", + "Clique", + "Consensus", + "Db", + "Debug", + "Deposit", + "Erc20", + "Eth", + "Evm", + "Net", + "Nft", + "Parity", + "Personal", + "Proof", + "Subscribe", + "Trace", + "TxPool", + "Vault", + "Web3", + "Arbitrum" + ] + }, + "Pruning": { + "PruningBoundary": 192 + }, + "Blocks": { + "SecondsPerSlot": 2, + "PreWarmStateOnBlockProcessing": false, + "BuildBlocksOnMainState": true + }, + "Metrics": { + "NodeName": "Nethermind Arbitrum One" + }, + "Merge": { + "Enabled": true + } +} diff --git a/src/Nethermind.Arbitrum/Properties/launchSettings.json b/src/Nethermind.Arbitrum/Properties/launchSettings.json index 17bcbfbda..6b2438bd4 100644 --- a/src/Nethermind.Arbitrum/Properties/launchSettings.json +++ b/src/Nethermind.Arbitrum/Properties/launchSettings.json @@ -26,6 +26,24 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } + }, + "Arbitrum Mainnet": { + "commandName": "Executable", + "executablePath": "dotnet", + "commandLineArgs": "$(SolutionDir)/Nethermind/src/Nethermind/artifacts/bin/Nethermind.Runner/$(Configuration)/nethermind.dll -c arbitrum-mainnet --data-dir .data", + "workingDirectory": "$(SolutionDir)/Nethermind/src/Nethermind/artifacts/bin/Nethermind.Runner/$(Configuration)/", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Arbitrum Mainnet Archive": { + "commandName": "Executable", + "executablePath": "dotnet", + "commandLineArgs": "$(SolutionDir)/Nethermind/src/Nethermind/artifacts/bin/Nethermind.Runner/$(Configuration)/nethermind.dll -c arbitrum-mainnet-archive --data-dir .data", + "workingDirectory": "$(SolutionDir)/Nethermind/src/Nethermind/artifacts/bin/Nethermind.Runner/$(Configuration)/", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } } } }