diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs index aadcf1750a2..863eeeb3c44 100644 --- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs +++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus; @@ -142,7 +143,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? IStateReader stateReader = new StateReader(trieStore, codeDb, _logManager); IReceiptStorage receiptStorage = NullReceiptStorage.Instance; - IBlockhashProvider blockhashProvider = new BlockhashProvider(blockTree, _logManager); + IBlockhashProvider blockhashProvider = new BlockhashProvider(blockTree, specProvider, stateProvider, _logManager); ITxValidator txValidator = new TxValidator(TestBlockchainIds.ChainId); IHeaderValidator headerValidator = new HeaderValidator(blockTree, Sealer, specProvider, _logManager); IUnclesValidator unclesValidator = new UnclesValidator(blockTree, headerValidator, _logManager); @@ -166,6 +167,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? stateProvider, receiptStorage, NullWitnessCollector.Instance, + new BlockhashStore(blockTree, specProvider, stateProvider), _logManager); IBlockchainProcessor blockchainProcessor = new BlockchainProcessor( diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.TestAccountAbstractionRpcBlockchain.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.TestAccountAbstractionRpcBlockchain.cs index c56265edd8a..5200ddeaa66 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.TestAccountAbstractionRpcBlockchain.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.TestAccountAbstractionRpcBlockchain.cs @@ -12,6 +12,7 @@ using Nethermind.AccountAbstraction.Executor; using Nethermind.AccountAbstraction.Source; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Contracts.Json; using Nethermind.Consensus; using Nethermind.Consensus.Comparers; @@ -190,6 +191,7 @@ protected override BlockProcessor CreateBlockProcessor() State, ReceiptStorage, NullWitnessCollector.Instance, + new BlockhashStore(BlockTree, SpecProvider, State), LogManager); AbiParameterConverter.RegisterFactory(new AbiTypeFactory(new AbiTuple())); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs index 50c870d1040..097883c8720 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs @@ -23,6 +23,7 @@ using System.Threading.Tasks; using System.Threading; using FluentAssertions; +using Nethermind.Blockchain.Blocks; using Nethermind.Consensus.Processing; using Nethermind.Consensus.Rewards; using Nethermind.Core.Test.Blockchain; @@ -49,6 +50,7 @@ public void Prepared_block_contains_author_field() stateProvider, NullReceiptStorage.Instance, NullWitnessCollector.Instance, + Substitute.For(), LimboLogs.Instance); BlockHeader header = Build.A.BlockHeader.WithAuthor(TestItem.AddressD).TestObject; @@ -80,6 +82,7 @@ public void Can_store_a_witness() stateProvider, NullReceiptStorage.Instance, witnessCollector, + Substitute.For(), LimboLogs.Instance); BlockHeader header = Build.A.BlockHeader.WithAuthor(TestItem.AddressD).TestObject; @@ -109,6 +112,7 @@ public void Recovers_state_on_cancel() stateProvider, NullReceiptStorage.Instance, NullWitnessCollector.Instance, + Substitute.For(), LimboLogs.Instance); BlockHeader header = Build.A.BlockHeader.WithNumber(1).WithAuthor(TestItem.AddressD).TestObject; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs index 9728dfb5475..763d0f43d30 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs @@ -1,17 +1,41 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Blockchain.Blocks; +using Nethermind.Blockchain.Find; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; +using Nethermind.Db; using Nethermind.Logging; +using Nethermind.Specs; +using Nethermind.Specs.Forks; +using Nethermind.Specs.Test; +using Nethermind.State; +using Nethermind.Trie.Pruning; using NUnit.Framework; namespace Nethermind.Blockchain.Test { - [TestFixture] + [TestFixture, Parallelizable(ParallelScope.All)] public class BlockhashProviderTests { + private static IWorldState CreateWorldState() + { + var trieStore = new TrieStore(new MemDb(), LimboLogs.Instance); + var worldState = new WorldState(trieStore, new MemDb(), LimboLogs.Instance); + worldState.CreateAccount(Eip2935Constants.BlockHashHistoryAddress, 0, 1); + worldState.Commit(Frontier.Instance); + return worldState; + } + private static BlockhashProvider CreateBlockHashProvider(IBlockFinder tree, IReleaseSpec spec) + { + IWorldState worldState = CreateWorldState(); + BlockhashProvider provider = new(tree, new TestSpecProvider(spec), worldState, LimboLogs.Instance); + return provider; + } + [Test, Timeout(Timeout.MaxTestTime)] public void Can_get_parent_only_headers() { @@ -21,10 +45,10 @@ public void Can_get_parent_only_headers() BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(chainLength).TestObject; - BlockhashProvider provider = new(tree, LimboLogs.Instance); + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); BlockHeader? head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None); Block current = Build.A.Block.WithParent(head!).TestObject; - Hash256 result = provider.GetBlockhash(current.Header, chainLength - 1); + Hash256? result = provider.GetBlockhash(current.Header, chainLength - 1); Assert.That(result, Is.EqualTo(head?.Hash)); } @@ -36,10 +60,10 @@ public void Can_lookup_up_to_256_before_with_headers_only() Block genesis = Build.A.Block.Genesis.TestObject; BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(chainLength).TestObject; - BlockhashProvider provider = new(tree, LimboLogs.Instance); + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; Block current = Build.A.Block.WithParent(head).TestObject; - Hash256 result = provider.GetBlockhash(current.Header, chainLength - 256); + Hash256? result = provider.GetBlockhash(current.Header, chainLength - 256); Assert.That(result, Is.EqualTo(tree.FindHeader(256, BlockTreeLookupOptions.None)!.Hash)); } @@ -51,10 +75,10 @@ public void Can_lookup_up_to_256_before_with_headers_only_and_competing_branches Block genesis = Build.A.Block.Genesis.TestObject; BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(out Block headBlock, chainLength).OfChainLength(out Block _, chainLength, 1).TestObject; - BlockhashProvider provider = new(tree, LimboLogs.Instance); + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); Block current = Build.A.Block.WithParent(headBlock).TestObject; long lookupNumber = chainLength - 256; - Hash256 result = provider.GetBlockhash(current.Header, lookupNumber); + Hash256? result = provider.GetBlockhash(current.Header, lookupNumber); Assert.NotNull(result); } @@ -66,12 +90,12 @@ public void Can_lookup_up_to_256_before_soon_after_fast_sync() Block genesis = Build.A.Block.Genesis.TestObject; BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(out Block headBlock, chainLength).OfChainLength(out Block _, chainLength, 1).TestObject; - BlockhashProvider provider = new(tree, LimboLogs.Instance); + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); Block current = Build.A.Block.WithParent(headBlock).TestObject; tree.SuggestBlock(current); tree.UpdateMainChain(current); long lookupNumber = chainLength - 256; - Hash256 result = provider.GetBlockhash(current.Header, lookupNumber); + Hash256? result = provider.GetBlockhash(current.Header, lookupNumber); Assert.NotNull(result); } @@ -83,7 +107,7 @@ public void Can_lookup_up_to_256_before_some_blocks_after_fast_sync() Block genesis = Build.A.Block.Genesis.TestObject; BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(out Block headBlock, chainLength).OfChainLength(out Block _, chainLength, 1).TestObject; - BlockhashProvider provider = new(tree, LimboLogs.Instance); + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); Block current = Build.A.Block.WithParent(headBlock).TestObject; for (int i = 0; i < 6; i++) @@ -94,7 +118,7 @@ public void Can_lookup_up_to_256_before_some_blocks_after_fast_sync() } long lookupNumber = current.Number - 256; - Hash256 result = provider.GetBlockhash(current.Header, lookupNumber); + Hash256? result = provider.GetBlockhash(current.Header, lookupNumber); Assert.NotNull(result); } @@ -113,9 +137,9 @@ public void Can_handle_non_main_chain_in_fast_sync() current = Build.A.Block.WithParent(current).TestObject; } - BlockhashProvider provider = new(tree, LimboLogs.Instance); + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - Hash256 result = provider.GetBlockhash(current.Header, 509); + Hash256? result = provider.GetBlockhash(current.Header, 509); Assert.NotNull(result); } @@ -128,10 +152,10 @@ public void Can_get_parent_hash() BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; - BlockhashProvider provider = new(tree, LimboLogs.Instance); + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; Block current = Build.A.Block.WithParent(head).TestObject; - Hash256 result = provider.GetBlockhash(current.Header, chainLength - 1); + Hash256? result = provider.GetBlockhash(current.Header, chainLength - 1); Assert.That(result, Is.EqualTo(head.Hash)); } @@ -143,10 +167,10 @@ public void Cannot_ask_for_self() Block genesis = Build.A.Block.Genesis.TestObject; BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; - BlockhashProvider provider = new(tree, LimboLogs.Instance); + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; Block current = Build.A.Block.WithParent(head).TestObject; - Hash256 result = provider.GetBlockhash(current.Header, chainLength); + Hash256? result = provider.GetBlockhash(current.Header, chainLength); Assert.Null(result); } @@ -158,10 +182,10 @@ public void Cannot_ask_about_future() Block genesis = Build.A.Block.Genesis.TestObject; BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; - BlockhashProvider provider = new(tree, LimboLogs.Instance); + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; Block current = Build.A.Block.WithParent(head).TestObject; - Hash256 result = provider.GetBlockhash(current.Header, chainLength + 1); + Hash256? result = provider.GetBlockhash(current.Header, chainLength + 1); Assert.Null(result); } @@ -173,10 +197,10 @@ public void Can_lookup_up_to_256_before() Block genesis = Build.A.Block.Genesis.TestObject; BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; - BlockhashProvider provider = new(tree, LimboLogs.Instance); + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; Block current = Build.A.Block.WithParent(head).TestObject; - Hash256 result = provider.GetBlockhash(current.Header, chainLength - 256); + Hash256? result = provider.GetBlockhash(current.Header, chainLength - 256); Assert.That(result, Is.EqualTo(tree.FindHeader(256, BlockTreeLookupOptions.None)!.Hash)); } @@ -188,10 +212,10 @@ public void No_lookup_more_than_256_before() Block genesis = Build.A.Block.Genesis.TestObject; BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; - BlockhashProvider provider = new(tree, LimboLogs.Instance); + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; Block current = Build.A.Block.WithParent(head).TestObject; - Hash256 result = provider.GetBlockhash(current.Header, chainLength - 257); + Hash256? result = provider.GetBlockhash(current.Header, chainLength - 257); Assert.Null(result); } @@ -203,11 +227,65 @@ public void UInt_256_overflow() Block genesis = Build.A.Block.Genesis.TestObject; BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; - BlockhashProvider provider = new(tree, LimboLogs.Instance); + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; Block current = Build.A.Block.WithParent(head).TestObject; - Hash256 result = provider.GetBlockhash(current.Header, 127); + Hash256? result = provider.GetBlockhash(current.Header, 127); Assert.That(result, Is.EqualTo(head.Hash)); } + + [Timeout(Timeout.MaxTestTime)] + [TestCase(1)] + [TestCase(512)] + [TestCase(8192)] + [TestCase(8193)] + public void Eip2935_init_block_history_and_then_get_hash(int chainLength) + { + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(chainLength).TestObject; + + BlockHeader? head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None); + // number = chainLength + Block current = Build.A.Block.WithParent(head!).TestObject; + tree.SuggestHeader(current.Header); + + IWorldState worldState = CreateWorldState(); + var specToUse = new OverridableReleaseSpec(Prague.Instance) + { + Eip2935TransitionTimestamp = current.Timestamp + }; + var specProvider = new CustomSpecProvider( + (new ForkActivation(0, genesis.Timestamp), Frontier.Instance), + (new ForkActivation(0, current.Timestamp), specToUse)); + BlockhashProvider provider = new(tree, specProvider, worldState, LimboLogs.Instance); + BlockhashStore store = new(tree, specProvider, worldState); + + store.ApplyHistoryBlockHashes(current.Header); + worldState.Commit(specToUse); + + Hash256? result = provider.GetBlockhash(current.Header, chainLength - 1); + Assert.That(result, Is.EqualTo(head?.Hash)); + AssertGenesisHash(provider, current.Header, genesis.Hash!); + + head = current.Header; + // number = chainLength + 1 + current = Build.A.Block.WithParent(head!).TestObject; + tree.SuggestHeader(current.Header); + + store.ApplyHistoryBlockHashes(current.Header); + result = provider.GetBlockhash(current.Header, chainLength); + Assert.That(result, Is.EqualTo(head?.Hash)); + + AssertGenesisHash(provider, current.Header, genesis.Hash!); + } + + private static void AssertGenesisHash(BlockhashProvider provider, BlockHeader currentHeader, Hash256 genesisHash) + { + Hash256? result = provider.GetBlockhash(currentHeader, 0); + if (currentHeader.Number > Eip2935Constants.RingBufferSize) + Assert.That(result, Is.Null); + else + Assert.That(result, Is.EqualTo(genesisHash)); + } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs index 71409777e35..9360f8af091 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs @@ -3,6 +3,7 @@ using System.Threading; using FluentAssertions; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Config; using Nethermind.Consensus.Processing; @@ -55,7 +56,7 @@ public void Test() dbProvider.RegisteredDbs[DbNames.Code], LimboLogs.Instance); StateReader stateReader = new(trieStore, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - BlockhashProvider blockhashProvider = new(blockTree, LimboLogs.Instance); + BlockhashProvider blockhashProvider = new(blockTree, specProvider, stateProvider, LimboLogs.Instance); VirtualMachine virtualMachine = new( blockhashProvider, specProvider, @@ -73,6 +74,7 @@ public void Test() stateProvider, NullReceiptStorage.Instance, NullWitnessCollector.Instance, + new BlockhashStore(blockTree, specProvider, stateProvider), LimboLogs.Instance); BlockchainProcessor blockchainProcessor = new( blockTree, diff --git a/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs index e252a296774..55354baf565 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using FluentAssertions; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus.Comparers; using Nethermind.Consensus.Processing; @@ -56,7 +57,7 @@ public void Setup() new TxValidator(specProvider.ChainId), LimboLogs.Instance, transactionComparerProvider.GetDefaultComparer()); - BlockhashProvider blockhashProvider = new(_blockTree, LimboLogs.Instance); + BlockhashProvider blockhashProvider = new(_blockTree, specProvider, stateProvider, LimboLogs.Instance); VirtualMachine virtualMachine = new( blockhashProvider, specProvider, @@ -75,6 +76,7 @@ public void Setup() stateProvider, NullReceiptStorage.Instance, new WitnessCollector(memDbProvider.StateDb, LimboLogs.Instance), + new BlockhashStore(_blockTree, MainnetSpecProvider.Instance, stateProvider), LimboLogs.Instance); _blockchainProcessor = new BlockchainProcessor( _blockTree, diff --git a/src/Nethermind/Nethermind.Blockchain/BlockhashProvider.cs b/src/Nethermind/Nethermind.Blockchain/BlockhashProvider.cs index 065211ac7a2..663d44bc62d 100644 --- a/src/Nethermind/Nethermind.Blockchain/BlockhashProvider.cs +++ b/src/Nethermind/Nethermind.Blockchain/BlockhashProvider.cs @@ -3,28 +3,43 @@ using System; using System.IO; +using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Specs; using Nethermind.Evm; using Nethermind.Logging; +using Nethermind.State; namespace Nethermind.Blockchain { public class BlockhashProvider : IBlockhashProvider { private static readonly int _maxDepth = 256; - private readonly IBlockTree _blockTree; + private readonly IBlockFinder _blockTree; + private readonly ISpecProvider _specProvider; + private readonly IBlockhashStore _blockhashStore; private readonly ILogger _logger; - public BlockhashProvider(IBlockTree blockTree, ILogManager? logManager) + public BlockhashProvider(IBlockFinder blockTree, ISpecProvider specProvider, IWorldState worldState, ILogManager? logManager) { _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree)); + _specProvider = specProvider; + _blockhashStore = new BlockhashStore(blockTree, specProvider, worldState); _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); } - public Hash256 GetBlockhash(BlockHeader currentBlock, in long number) + public Hash256? GetBlockhash(BlockHeader currentBlock, in long number) { + IReleaseSpec? spec = _specProvider.GetSpec(currentBlock); + + if (spec.IsBlockHashInStateAvailable) + { + return _blockhashStore.GetBlockHashFromState(currentBlock, number); + } + long current = currentBlock.Number; if (number >= current || number < current - Math.Min(current, _maxDepth)) { diff --git a/src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs b/src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs new file mode 100644 index 00000000000..c3697f828d1 --- /dev/null +++ b/src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText:2023 Demerzel Solutions Limited +// SPDX-License-Identifier:LGPL-3.0-only + +using System; +using System.IO; +using System.Runtime.CompilerServices; +using Nethermind.Blockchain.Find; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; +using Nethermind.Core.Specs; +using Nethermind.Int256; +using Nethermind.State; + +[assembly: InternalsVisibleTo("Nethermind.Blockchain.Test")] +[assembly: InternalsVisibleTo("Nethermind.Merge.Plugin.Test")] +namespace Nethermind.Blockchain.Blocks; + +public class BlockhashStore(IBlockFinder blockFinder, ISpecProvider specProvider, IWorldState worldState) + : IBlockhashStore +{ + private static readonly byte[] EmptyBytes = [0]; + + public void ApplyHistoryBlockHashes(BlockHeader blockHeader) + { + IReleaseSpec spec = specProvider.GetSpec(blockHeader); + if (!spec.IsEip2935Enabled || blockHeader.IsGenesis || blockHeader.ParentHash is null) return; + + Address? eip2935Account = spec.Eip2935ContractAddress ?? Eip2935Constants.BlockHashHistoryAddress; + if (!worldState.AccountExists(eip2935Account)) return; + + // TODO: find a better way to handle this - no need to have this check everytime + // this would just be true on the fork block + BlockHeader parentHeader = blockFinder.FindParentHeader(blockHeader, BlockTreeLookupOptions.None); + if (parentHeader is not null && parentHeader!.Timestamp < spec.Eip2935TransitionTimestamp) + InitHistoryOnForkBlock(blockHeader, eip2935Account); + else + AddParentBlockHashToState(blockHeader, eip2935Account); + } + + public Hash256? GetBlockHashFromState(BlockHeader currentHeader, long requiredBlockNumber) + { + IReleaseSpec? spec = specProvider.GetSpec(currentHeader); + if (requiredBlockNumber >= currentHeader.Number || + requiredBlockNumber + Eip2935Constants.RingBufferSize < currentHeader.Number) + { + return null; + } + var blockIndex = new UInt256((ulong)(requiredBlockNumber % Eip2935Constants.RingBufferSize)); + Address? eip2935Account = spec.Eip2935ContractAddress ?? Eip2935Constants.BlockHashHistoryAddress; + StorageCell blockHashStoreCell = new(eip2935Account, blockIndex); + ReadOnlySpan data = worldState.Get(blockHashStoreCell); + return data.SequenceEqual(EmptyBytes) ? null : new Hash256(data); + } + + private void InitHistoryOnForkBlock(BlockHeader currentBlock, Address eip2935Account) + { + long current = currentBlock.Number; + BlockHeader header = currentBlock; + for (var i = 0; i < Math.Min(Eip2935Constants.RingBufferSize, current); i++) + { + AddParentBlockHashToState(header, eip2935Account); + header = blockFinder.FindParentHeader(header, BlockTreeLookupOptions.TotalDifficultyNotNeeded); + if (header is null) + { + throw new InvalidDataException( + "Parent header cannot be found when initializing BlockHashInState history"); + } + } + } + + private void AddParentBlockHashToState(BlockHeader blockHeader, Address eip2935Account) + { + Hash256 parentBlockHash = blockHeader.ParentHash; + var blockIndex = new UInt256((ulong)((blockHeader.Number - 1) % Eip2935Constants.RingBufferSize)); + StorageCell blockHashStoreCell = new(eip2935Account, blockIndex); + worldState.Set(blockHashStoreCell, parentBlockHash!.BytesToArray()); + } +} diff --git a/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockhashStore.cs b/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockhashStore.cs new file mode 100644 index 00000000000..457a5115780 --- /dev/null +++ b/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockhashStore.cs @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Specs; + +namespace Nethermind.Blockchain.Blocks; + +public interface IBlockhashStore +{ + public void ApplyHistoryBlockHashes(BlockHeader blockHeader); + public Hash256? GetBlockHashFromState(BlockHeader currentBlockHeader, long requiredBlockNumber); +} diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs index b4b0386a81e..ce0e1996581 100644 --- a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus; using Nethermind.Consensus.Clique; @@ -115,7 +116,7 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f transactionComparerProvider.GetDefaultComparer()); _pools[privateKey] = txPool; - BlockhashProvider blockhashProvider = new(blockTree, LimboLogs.Instance); + BlockhashProvider blockhashProvider = new(blockTree, specProvider, stateProvider, LimboLogs.Instance); _blockTrees.Add(privateKey, blockTree); SnapshotManager snapshotManager = new(_cliqueConfig, blocksDb, blockTree, _ethereumEcdsa, nodeLogManager); @@ -137,6 +138,7 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f stateProvider, NullReceiptStorage.Instance, NullWitnessCollector.Instance, + new BlockhashStore(blockTree, goerliSpecProvider, stateProvider), nodeLogManager); BlockchainProcessor processor = new(blockTree, blockProcessor, new AuthorRecoveryStep(snapshotManager), stateReader, nodeLogManager, BlockchainProcessor.Options.NoReceipts); @@ -156,6 +158,7 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f minerStateProvider, NullReceiptStorage.Instance, NullWitnessCollector.Instance, + new BlockhashStore(blockTree, goerliSpecProvider, minerStateProvider), nodeLogManager); BlockchainProcessor minerProcessor = new(blockTree, minerBlockProcessor, new AuthorRecoveryStep(snapshotManager), stateReader, nodeLogManager, BlockchainProcessor.Options.NoReceipts); diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs index 42885a70090..53a6836ff8f 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs @@ -3,6 +3,7 @@ using System; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus.AuRa.Validators; @@ -14,6 +15,7 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.Evm; using Nethermind.Evm.Tracing; using Nethermind.Logging; using Nethermind.State; @@ -24,7 +26,7 @@ namespace Nethermind.Consensus.AuRa public class AuRaBlockProcessor : BlockProcessor { private readonly ISpecProvider _specProvider; - private readonly IBlockTree _blockTree; + private readonly IBlockFinder _blockTree; private readonly AuRaContractGasLimitOverride? _gasLimitOverride; private readonly ContractRewriter? _contractRewriter; private readonly ITxFilter _txFilter; @@ -38,7 +40,7 @@ public class AuRaBlockProcessor : BlockProcessor IWorldState stateProvider, IReceiptStorage receiptStorage, ILogManager logManager, - IBlockTree blockTree, + IBlockFinder blockTree, IWithdrawalProcessor withdrawalProcessor, IAuRaValidator? auRaValidator, ITxFilter? txFilter = null, @@ -52,6 +54,7 @@ public class AuRaBlockProcessor : BlockProcessor stateProvider, receiptStorage, NullWitnessCollector.Instance, + new BlockhashStore(blockTree, specProvider, stateProvider), logManager, withdrawalProcessor) { diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs index c416e75cea0..9d0690a118b 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs @@ -6,6 +6,7 @@ using Nethermind.Api; using Nethermind.Api.Extensions; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Config; using Nethermind.Consensus.Comparers; @@ -107,6 +108,7 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd producerEnv.StateProvider, NullReceiptStorage.Instance, NullWitnessCollector.Instance, + new BlockhashStore(getFromApi.BlockTree, getFromApi.SpecProvider, producerEnv.StateProvider), getFromApi.LogManager, new BlockProductionWithdrawalProcessor(new WithdrawalProcessor(producerEnv.StateProvider, getFromApi.LogManager))); diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs index 7220b3c2bba..98875c1f159 100644 --- a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs @@ -6,6 +6,7 @@ using Nethermind.Api; using Nethermind.Api.Extensions; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Config; using Nethermind.Consensus.Processing; @@ -77,6 +78,7 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd producerEnv.StateProvider, NullReceiptStorage.Instance, NullWitnessCollector.Instance, + new BlockhashStore(getFromApi.BlockTree, getFromApi.SpecProvider, producerEnv.StateProvider), getFromApi.LogManager); IBlockchainProcessor producerChainProcessor = new BlockchainProcessor( diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs index f388bf592c2..953d570cfe6 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs @@ -7,6 +7,8 @@ using System.Runtime.InteropServices; using System.Threading; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; +using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus.BeaconBlockRoot; using Nethermind.Consensus.Rewards; @@ -39,7 +41,7 @@ public partial class BlockProcessor : IBlockProcessor private readonly IBlockValidator _blockValidator; private readonly IRewardCalculator _rewardCalculator; private readonly IBlockProcessor.IBlockTransactionsExecutor _blockTransactionsExecutor; - + private readonly IBlockhashStore _blockhashStore; private const int MaxUncommittedBlocks = 64; /// @@ -56,6 +58,7 @@ public partial class BlockProcessor : IBlockProcessor IWorldState? stateProvider, IReceiptStorage? receiptStorage, IWitnessCollector? witnessCollector, + IBlockhashStore? blockHashStore, ILogManager? logManager, IWithdrawalProcessor? withdrawalProcessor = null, IReceiptsRootCalculator? receiptsRootCalculator = null) @@ -70,8 +73,8 @@ public partial class BlockProcessor : IBlockProcessor _rewardCalculator = rewardCalculator ?? throw new ArgumentNullException(nameof(rewardCalculator)); _blockTransactionsExecutor = blockTransactionsExecutor ?? throw new ArgumentNullException(nameof(blockTransactionsExecutor)); _receiptsRootCalculator = receiptsRootCalculator ?? ReceiptsRootCalculator.Instance; + _blockhashStore = blockHashStore ?? throw new ArgumentNullException(nameof(blockHashStore)); _beaconBlockRootHandler = new BeaconBlockRootHandler(); - ReceiptsTracer = new BlockReceiptsTracer(); } @@ -236,6 +239,8 @@ private void ValidateProcessedBlock(Block suggestedBlock, ProcessingOptions opti ReceiptsTracer.StartNewBlockTrace(block); _beaconBlockRootHandler.ApplyContractStateChanges(block, spec, _stateProvider); + _blockhashStore.ApplyHistoryBlockHashes(block.Header); + _stateProvider.Commit(spec); TxReceipt[] receipts = _blockTransactionsExecutor.ProcessTransactions(block, options, ReceiptsTracer, spec); diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs index 6fff1bc71d9..f448f7ee1e9 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Validators; @@ -48,6 +49,7 @@ public class ReadOnlyChainProcessingEnv : IDisposable StateProvider, receiptStorage, NullWitnessCollector.Instance, + new BlockhashStore(txEnv.BlockTree, specProvider, StateProvider), logManager); _blockProcessingQueue = new BlockchainProcessor(_txEnv.BlockTree, BlockProcessor, recoveryStep, _txEnv.StateReader, logManager, BlockchainProcessor.Options.NoReceipts); diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs index 060b52ca5dc..47671734515 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs @@ -45,7 +45,7 @@ public class ReadOnlyTxProcessingEnv : IReadOnlyTxProcessorSource StateProvider = worldStateManager.CreateResettableWorldState(); BlockTree = readOnlyBlockTree ?? throw new ArgumentNullException(nameof(readOnlyBlockTree)); - BlockhashProvider = new BlockhashProvider(BlockTree, logManager); + BlockhashProvider = new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager); Machine = new VirtualMachine(BlockhashProvider, specProvider, logManager); TransactionProcessor = new TransactionProcessor(specProvider, StateProvider, Machine, logManager); diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs index 3a4f595ca23..8bc9472b3e1 100644 --- a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs +++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Config; using Nethermind.Consensus.Comparers; @@ -142,6 +143,7 @@ public virtual BlockProducerEnv Create(ITxSource? additionalTxSource = null) readOnlyTxProcessingEnv.StateProvider, receiptStorage, NullWitnessCollector.Instance, + new BlockhashStore(_blockTree, _specProvider, readOnlyTxProcessingEnv.StateProvider), logManager, new BlockProductionWithdrawalProcessor(new WithdrawalProcessor(readOnlyTxProcessingEnv.StateProvider, logManager))); diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs index 9131ce20ba1..f252f9bbfca 100644 --- a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs +++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; using Nethermind.Config; @@ -129,6 +130,12 @@ protected virtual async Task Build(ISpecProvider? specProvider = State.CreateAccount(SpecProvider.GenesisSpec.Eip4788ContractAddress, 1); } + // Eip2935 + if (specProvider?.GenesisSpec?.IsBlockHashInStateAvailable ?? false) + { + State.CreateAccount(SpecProvider.GenesisSpec.Eip2935ContractAddress, 1); + } + State.CreateAccount(TestItem.AddressA, (initialValues ?? InitialValue)); State.CreateAccount(TestItem.AddressB, (initialValues ?? InitialValue)); State.CreateAccount(TestItem.AddressC, (initialValues ?? InitialValue)); @@ -165,7 +172,7 @@ protected virtual async Task Build(ISpecProvider? specProvider = _trieStoreWatcher = new TrieStoreBoundaryWatcher(WorldStateManager, BlockTree, LogManager); ReceiptStorage = new InMemoryReceiptStorage(blockTree: BlockTree); - VirtualMachine virtualMachine = new(new BlockhashProvider(BlockTree, LogManager), SpecProvider, LogManager); + VirtualMachine virtualMachine = new(new BlockhashProvider(BlockTree, SpecProvider, State, LogManager), SpecProvider, LogManager); TxProcessor = new TransactionProcessor(SpecProvider, State, virtualMachine, LogManager); BlockPreprocessorStep = new RecoverSignatures(EthereumEcdsa, TxPool, SpecProvider, LogManager); HeaderValidator = new HeaderValidator(BlockTree, Always.Valid, SpecProvider, LogManager); @@ -350,6 +357,7 @@ protected virtual async Task AddBlocksOnStart() State, ReceiptStorage, NullWitnessCollector.Instance, + new BlockhashStore(BlockTree, SpecProvider, State), LogManager); public async Task WaitForNewHead() diff --git a/src/Nethermind/Nethermind.Core/Eip2935Constants.cs b/src/Nethermind/Nethermind.Core/Eip2935Constants.cs new file mode 100644 index 00000000000..9ca60fc3cbf --- /dev/null +++ b/src/Nethermind/Nethermind.Core/Eip2935Constants.cs @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Int256; + +namespace Nethermind.Core; + +/// +/// Represents the EIP-2935 parameters. +/// +public static class Eip2935Constants +{ + /// + /// The HISTORY_STORAGE_ADDRESS parameter. + /// + public static readonly Address BlockHashHistoryAddress = new("0x25a219378dad9b3503c8268c9ca836a52427a4fb"); + + /// + /// The HISTORY_SERVE_WINDOW parameter. + /// + public static readonly long RingBufferSize = 8192; +} diff --git a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs index f7e8519de72..d7d5d32a8c6 100644 --- a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs @@ -273,6 +273,13 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec bool IsEip4788Enabled { get; } Address Eip4788ContractAddress { get; } + /// + /// Save historical block hashes in state + /// + bool IsEip2935Enabled { get; } + Address Eip2935ContractAddress { get; } + public ulong Eip2935TransitionTimestamp { get; } + /// /// SELFDESTRUCT only in same transaction /// @@ -288,7 +295,7 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec public ulong Eip4844TransitionTimestamp { get; } - // STATE related + // STATE related public bool ClearEmptyAccountWhenTouched => IsEip158Enabled; // VM @@ -359,6 +366,7 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec public bool SelfdestructOnlyOnSameTransaction => IsEip6780Enabled; public bool IsBeaconBlockRootAvailable => IsEip4788Enabled; + public bool IsBlockHashInStateAvailable => IsEip2935Enabled; public bool MCopyIncluded => IsEip5656Enabled; public bool BlobBaseFeeEnabled => IsEip4844Enabled; } diff --git a/src/Nethermind/Nethermind.Evm.Benchmark/EvmBenchmarks.cs b/src/Nethermind/Nethermind.Evm.Benchmark/EvmBenchmarks.cs index 5e490186992..8d01214bfaa 100644 --- a/src/Nethermind/Nethermind.Evm.Benchmark/EvmBenchmarks.cs +++ b/src/Nethermind/Nethermind.Evm.Benchmark/EvmBenchmarks.cs @@ -28,7 +28,7 @@ public class EvmBenchmarks private ExecutionEnvironment _environment; private IVirtualMachine _virtualMachine; private BlockHeader _header = new BlockHeader(Keccak.Zero, Keccak.Zero, Address.Zero, UInt256.One, MainnetSpecProvider.IstanbulBlockNumber, Int64.MaxValue, 1UL, Bytes.Empty); - private IBlockhashProvider _blockhashProvider = new TestBlockhashProvider(); + private IBlockhashProvider _blockhashProvider = new TestBlockhashProvider(MainnetSpecProvider.Instance); private EvmState _evmState; private WorldState _stateProvider; diff --git a/src/Nethermind/Nethermind.Evm.Benchmark/MultipleUnsignedOperations.cs b/src/Nethermind/Nethermind.Evm.Benchmark/MultipleUnsignedOperations.cs index d3d8889bcc7..749ae715bd8 100644 --- a/src/Nethermind/Nethermind.Evm.Benchmark/MultipleUnsignedOperations.cs +++ b/src/Nethermind/Nethermind.Evm.Benchmark/MultipleUnsignedOperations.cs @@ -27,7 +27,7 @@ public class MultipleUnsignedOperations private ExecutionEnvironment _environment; private IVirtualMachine _virtualMachine; private readonly BlockHeader _header = new(Keccak.Zero, Keccak.Zero, Address.Zero, UInt256.One, MainnetSpecProvider.MuirGlacierBlockNumber, Int64.MaxValue, 1UL, Bytes.Empty); - private readonly IBlockhashProvider _blockhashProvider = new TestBlockhashProvider(); + private readonly IBlockhashProvider _blockhashProvider = new TestBlockhashProvider(MainnetSpecProvider.Instance); private EvmState _evmState; private WorldState _stateProvider; diff --git a/src/Nethermind/Nethermind.Evm.Benchmark/StaticCallBenchmarks.cs b/src/Nethermind/Nethermind.Evm.Benchmark/StaticCallBenchmarks.cs index 93e158881a7..ebedead21a1 100644 --- a/src/Nethermind/Nethermind.Evm.Benchmark/StaticCallBenchmarks.cs +++ b/src/Nethermind/Nethermind.Evm.Benchmark/StaticCallBenchmarks.cs @@ -28,7 +28,7 @@ public class StaticCallBenchmarks private ExecutionEnvironment _environment; private IVirtualMachine _virtualMachine; private BlockHeader _header = new BlockHeader(Keccak.Zero, Keccak.Zero, Address.Zero, UInt256.One, MainnetSpecProvider.MuirGlacierBlockNumber, Int64.MaxValue, 1UL, Bytes.Empty); - private IBlockhashProvider _blockhashProvider = new TestBlockhashProvider(); + private IBlockhashProvider _blockhashProvider = new TestBlockhashProvider(MainnetSpecProvider.Instance); private EvmState _evmState; private WorldState _stateProvider; diff --git a/src/Nethermind/Nethermind.Evm.Benchmark/TestBlockhashProvider.cs b/src/Nethermind/Nethermind.Evm.Benchmark/TestBlockhashProvider.cs index c95162989f5..a42d0d0be9a 100644 --- a/src/Nethermind/Nethermind.Evm.Benchmark/TestBlockhashProvider.cs +++ b/src/Nethermind/Nethermind.Evm.Benchmark/TestBlockhashProvider.cs @@ -3,14 +3,25 @@ using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Specs; +using Nethermind.State; namespace Nethermind.Evm.Benchmark { public class TestBlockhashProvider : IBlockhashProvider { + private readonly ISpecProvider _specProvider; + public TestBlockhashProvider(ISpecProvider specProvider) + { + _specProvider = specProvider; + } + public Hash256 GetBlockhash(BlockHeader currentBlock, in long number) { - return Keccak.Compute(number.ToString()); + IReleaseSpec spec = _specProvider.GetSpec(currentBlock); + return Keccak.Compute(spec.IsBlockHashInStateAvailable + ? (Eip2935Constants.RingBufferSize + number).ToString() + : (number).ToString()); } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip2935Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip2935Tests.cs new file mode 100644 index 00000000000..bc623cfb4cb --- /dev/null +++ b/src/Nethermind/Nethermind.Evm.Test/Eip2935Tests.cs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using FluentAssertions; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Specs; +using Nethermind.Evm.Tracing; +using Nethermind.Specs; +using NUnit.Framework; + +namespace Nethermind.Evm.Test; + +[TestFixture] +public class Eip2935Tests : VirtualMachineTestsBase +{ + protected override long BlockNumber => MainnetSpecProvider.ParisBlockNumber; + protected override ulong Timestamp => MainnetSpecProvider.PragueBlockTimestamp; + + + public override void Setup() + { + base.Setup(); + TestState.CreateAccount(Eip2935Constants.BlockHashHistoryAddress, 1); + TestState.Commit(SpecProvider.GenesisSpec); + TestState.CommitTree(0); + } + + + [TestCase(MainnetSpecProvider.CancunBlockTimestamp, false)] + [TestCase(MainnetSpecProvider.PragueBlockTimestamp, true)] + public void CorrectBlockhashBeingUsed(ulong timestamp, bool eipEnabled) + { + const long blockNumber = 256; + byte[] bytecode = + Prepare.EvmCode + .PushData(blockNumber) + .Op(Instruction.BLOCKHASH) + .PushData(0) + .Op(Instruction.MSTORE) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + .Done; + + + (Block block, Transaction transaction) = PrepareTx(new ForkActivation(BlockNumber, timestamp), 100000, bytecode); + CallOutputTracer callOutputTracer = new(); + _processor.Execute(transaction, block.Header, callOutputTracer); + + long expected = eipEnabled ? blockNumber + Eip2935Constants.RingBufferSize : blockNumber; + callOutputTracer.ReturnValue!.Should().BeEquivalentTo(Keccak.Compute(expected.ToString()).BytesToArray()); + } +} diff --git a/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs b/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs index 48129be9325..18529a85794 100644 --- a/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs @@ -159,7 +159,7 @@ private static string run(byte[] input) LimboLogs.Instance); ISpecProvider specProvider = new TestSpecProvider(London.Instance); VirtualMachine virtualMachine = new( - Nethermind.Evm.Test.TestBlockhashProvider.Instance, + new TestBlockhashProvider(specProvider), specProvider, LimboLogs.Instance); TransactionProcessor transactionProcessor = new TransactionProcessor( diff --git a/src/Nethermind/Nethermind.Evm.Test/TestBlockhashProvider.cs b/src/Nethermind/Nethermind.Evm.Test/TestBlockhashProvider.cs index b95fb719cc8..8f90fee3cdc 100644 --- a/src/Nethermind/Nethermind.Evm.Test/TestBlockhashProvider.cs +++ b/src/Nethermind/Nethermind.Evm.Test/TestBlockhashProvider.cs @@ -3,20 +3,25 @@ using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Specs; +using Nethermind.State; namespace Nethermind.Evm.Test { public class TestBlockhashProvider : IBlockhashProvider { - public static TestBlockhashProvider Instance = new(); - - private TestBlockhashProvider() + private readonly ISpecProvider _specProvider; + public TestBlockhashProvider(ISpecProvider specProvider) { + _specProvider = specProvider; } public Hash256 GetBlockhash(BlockHeader currentBlock, in long number) { - return Keccak.Compute(number.ToString()); + IReleaseSpec? spec = _specProvider.GetSpec(currentBlock); + return Keccak.Compute(spec.IsBlockHashInStateAvailable + ? (Eip2935Constants.RingBufferSize + number).ToString() + : (number).ToString()); } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/GasEstimationTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/GasEstimationTests.cs index 134cd6bd0a7..2e41c2443ed 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/GasEstimationTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/GasEstimationTests.cs @@ -362,7 +362,7 @@ public TestEnvironment() _stateProvider.Commit(_specProvider.GenesisSpec); _stateProvider.CommitTree(0); - VirtualMachine virtualMachine = new(TestBlockhashProvider.Instance, _specProvider, LimboLogs.Instance); + VirtualMachine virtualMachine = new(new TestBlockhashProvider(_specProvider), _specProvider, LimboLogs.Instance); _transactionProcessor = new TransactionProcessor(_specProvider, _stateProvider, virtualMachine, LimboLogs.Instance); _ethereumEcdsa = new EthereumEcdsa(_specProvider.ChainId, LimboLogs.Instance); diff --git a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorEip4844Tests.cs b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorEip4844Tests.cs index 7a72a46e358..7312cf923f7 100644 --- a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorEip4844Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorEip4844Tests.cs @@ -35,7 +35,7 @@ public void Setup() _specProvider = new TestSpecProvider(Cancun.Instance); TrieStore trieStore = new(stateDb, LimboLogs.Instance); _stateProvider = new WorldState(trieStore, new MemDb(), LimboLogs.Instance); - VirtualMachine virtualMachine = new(TestBlockhashProvider.Instance, _specProvider, LimboLogs.Instance); + VirtualMachine virtualMachine = new(new TestBlockhashProvider(_specProvider), _specProvider, LimboLogs.Instance); _transactionProcessor = new TransactionProcessor(_specProvider, _stateProvider, virtualMachine, LimboLogs.Instance); _ethereumEcdsa = new EthereumEcdsa(_specProvider.ChainId, LimboLogs.Instance); } diff --git a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorFeeTests.cs b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorFeeTests.cs index d7f530768f3..09d61e31b55 100644 --- a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorFeeTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorFeeTests.cs @@ -42,7 +42,7 @@ public void Setup() _stateProvider.Commit(_specProvider.GenesisSpec); _stateProvider.CommitTree(0); - VirtualMachine virtualMachine = new(TestBlockhashProvider.Instance, _specProvider, LimboLogs.Instance); + VirtualMachine virtualMachine = new(new TestBlockhashProvider(_specProvider), _specProvider, LimboLogs.Instance); _transactionProcessor = new TransactionProcessor(_specProvider, _stateProvider, virtualMachine, LimboLogs.Instance); _ethereumEcdsa = new EthereumEcdsa(_specProvider.ChainId, LimboLogs.Instance); } diff --git a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs index afe85bcc78d..5d30cc00eee 100644 --- a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs @@ -58,7 +58,7 @@ public void Setup() _stateProvider.Commit(_specProvider.GenesisSpec); _stateProvider.CommitTree(0); - VirtualMachine virtualMachine = new(TestBlockhashProvider.Instance, _specProvider, LimboLogs.Instance); + VirtualMachine virtualMachine = new(new TestBlockhashProvider(_specProvider), _specProvider, LimboLogs.Instance); _transactionProcessor = new TransactionProcessor(_specProvider, _stateProvider, virtualMachine, LimboLogs.Instance); _ethereumEcdsa = new EthereumEcdsa(_specProvider.ChainId, LimboLogs.Instance); } diff --git a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs index da4554f0314..5985f35d3d5 100644 --- a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs +++ b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs @@ -66,7 +66,7 @@ public virtual void Setup() ITrieStore trieStore = new TrieStore(_stateDb, logManager); TestState = new WorldState(trieStore, codeDb, logManager); _ethereumEcdsa = new EthereumEcdsa(SpecProvider.ChainId, logManager); - IBlockhashProvider blockhashProvider = TestBlockhashProvider.Instance; + IBlockhashProvider blockhashProvider = new TestBlockhashProvider(SpecProvider); Machine = new VirtualMachine(blockhashProvider, SpecProvider, logManager); _processor = new TransactionProcessor(SpecProvider, TestState, Machine, logManager); } diff --git a/src/Nethermind/Nethermind.Evm/IBlockhashProvider.cs b/src/Nethermind/Nethermind.Evm/IBlockhashProvider.cs index 3cbc1b9335d..bdbd27d52fc 100644 --- a/src/Nethermind/Nethermind.Evm/IBlockhashProvider.cs +++ b/src/Nethermind/Nethermind.Evm/IBlockhashProvider.cs @@ -3,11 +3,13 @@ using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Specs; +using Nethermind.State; namespace Nethermind.Evm { public interface IBlockhashProvider { - Hash256 GetBlockhash(BlockHeader currentBlock, in long number); + Hash256? GetBlockhash(BlockHeader currentBlock, in long number); } } diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index ee5e1eef67e..14e6a432ff4 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -19,7 +19,6 @@ using Nethermind.State; using System.Diagnostics.CodeAnalysis; using System.Diagnostics; -using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using static Nethermind.Evm.VirtualMachine; using static System.Runtime.CompilerServices.Unsafe; @@ -1486,7 +1485,9 @@ private CallResult ExecuteCall(EvmState vmState, ReadOnlyM if (!stack.PopUInt256(out a)) goto StackUnderflow; long number = a > long.MaxValue ? long.MaxValue : (long)a; - Hash256 blockHash = _blockhashProvider.GetBlockhash(blkCtx.Header, number); + + Hash256? blockHash = _blockhashProvider.GetBlockhash(blkCtx.Header, number); + stack.PushBytes(blockHash is not null ? blockHash.Bytes : BytesZero32); if (typeof(TLogger) == typeof(IsTracing)) diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs index 5b8a5202835..3816b0a5840 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Nethermind.Api; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Filters; using Nethermind.Blockchain.FullPruning; using Nethermind.Blockchain.Receipts; @@ -175,10 +176,11 @@ protected virtual VirtualMachine CreateVirtualMachine() { if (_api.BlockTree is null) throw new StepDependencyException(nameof(_api.BlockTree)); if (_api.SpecProvider is null) throw new StepDependencyException(nameof(_api.SpecProvider)); + if (_api.WorldState is null) throw new StepDependencyException(nameof(_api.WorldState)); // blockchain processing BlockhashProvider blockhashProvider = new( - _api.BlockTree, _api.LogManager); + _api.BlockTree, _api.SpecProvider, _api.WorldState, _api.LogManager); return new VirtualMachine( blockhashProvider, @@ -217,6 +219,7 @@ protected virtual BlockProcessor CreateBlockProcessor() if (_api.DbProvider is null) throw new StepDependencyException(nameof(_api.DbProvider)); if (_api.RewardCalculatorSource is null) throw new StepDependencyException(nameof(_api.RewardCalculatorSource)); if (_api.TransactionProcessor is null) throw new StepDependencyException(nameof(_api.TransactionProcessor)); + if (_api.BlockTree is null) throw new StepDependencyException(nameof(_api.BlockTree)); IWorldState worldState = _api.WorldState!; @@ -228,6 +231,7 @@ protected virtual BlockProcessor CreateBlockProcessor() worldState, _api.ReceiptStorage, _api.WitnessCollector, + new BlockhashStore(_api.BlockTree, _api.SpecProvider!, worldState), _api.LogManager); } diff --git a/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs b/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs index 78641dbe1ed..07b96b59c2a 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs @@ -79,7 +79,7 @@ public void GlobalSetup() NullBloomStorage.Instance, new SyncConfig(), LimboLogs.Instance); - _blockhashProvider = new BlockhashProvider(blockTree, LimboLogs.Instance); + _blockhashProvider = new BlockhashProvider(blockTree, specProvider, stateProvider, LimboLogs.Instance); _virtualMachine = new VirtualMachine(_blockhashProvider, specProvider, LimboLogs.Instance); Block genesisBlock = Build.A.Block.Genesis.TestObject; @@ -93,7 +93,7 @@ TransactionProcessor transactionProcessor IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor = new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider); BlockProcessor blockProcessor = new(specProvider, Always.Valid, new RewardCalculator(specProvider), transactionsExecutor, - stateProvider, NullReceiptStorage.Instance, NullWitnessCollector.Instance, LimboLogs.Instance); + stateProvider, NullReceiptStorage.Instance, NullWitnessCollector.Instance, new BlockhashStore(blockTree, specProvider, stateProvider), LimboLogs.Instance); EthereumEcdsa ecdsa = new(specProvider.ChainId, LimboLogs.Instance); BlockchainProcessor blockchainProcessor = new( diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs index e5dec786b18..2c6722f3e19 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs @@ -4,6 +4,7 @@ using System.Linq; using FluentAssertions; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Synchronization; @@ -61,7 +62,7 @@ public void Setup() WorldState stateProvider = new(trieStore, codeDb, LimboLogs.Instance); _stateReader = new StateReader(trieStore, codeDb, LimboLogs.Instance); - BlockhashProvider blockhashProvider = new(_blockTree, LimboLogs.Instance); + BlockhashProvider blockhashProvider = new(_blockTree, specProvider, stateProvider, LimboLogs.Instance); VirtualMachine virtualMachine = new(blockhashProvider, specProvider, LimboLogs.Instance); TransactionProcessor transactionProcessor = new(specProvider, stateProvider, virtualMachine, LimboLogs.Instance); @@ -74,6 +75,7 @@ public void Setup() stateProvider, NullReceiptStorage.Instance, NullWitnessCollector.Instance, + new BlockhashStore(_blockTree, specProvider, stateProvider), LimboLogs.Instance); RecoverSignatures txRecovery = new(new EthereumEcdsa(TestBlockchainIds.ChainId, LimboLogs.Instance), NullTxPool.Instance, specProvider, LimboLogs.Instance); diff --git a/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs b/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs index 8a8d3d562fe..ae7a2c03109 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs @@ -3,6 +3,7 @@ using System; using System.Threading.Tasks; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Consensus; @@ -131,6 +132,7 @@ protected override IBlockProcessor CreateBlockProcessor() State, ReceiptStorage, NullWitnessCollector.Instance, + new BlockhashStore(BlockTree, SpecProvider, State), LogManager, WithdrawalProcessor); diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs index 42df50543de..3d57378ffc5 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs @@ -2,11 +2,11 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -20,10 +20,7 @@ using Nethermind.Specs; using Nethermind.Specs.Forks; using Nethermind.State; -using Nethermind.Core.Specs; using Nethermind.Consensus.BeaconBlockRoot; -using Nethermind.Consensus.Withdrawals; -using Nethermind.Core.Test.Blockchain; namespace Nethermind.Merge.Plugin.Test { @@ -115,6 +112,8 @@ private ExecutionPayload CreateParentBlockRequestOnHead(IBlockTree blockTree) Snapshot before = chain.State.TakeSnapshot(); _beaconBlockRootHandler.ApplyContractStateChanges(block!, chain.SpecProvider.GenesisSpec, chain.State); + var blockHashStore = new BlockhashStore(chain.BlockTree, chain.SpecProvider, chain.State); + blockHashStore.ApplyHistoryBlockHashes(block!.Header); chain.WithdrawalProcessor?.ProcessWithdrawals(block!, chain.SpecProvider.GenesisSpec); chain.State.Commit(chain.SpecProvider.GenesisSpec); diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs index cd10b95848b..a758393594e 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Nethermind.Api; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Consensus; @@ -235,6 +236,7 @@ protected override IBlockProcessor CreateBlockProcessor() State, ReceiptStorage, NullWitnessCollector.Instance, + new BlockhashStore(BlockTree, SpecProvider, State), LogManager, WithdrawalProcessor); diff --git a/src/Nethermind/Nethermind.Mev.Test/MevRpcModuleTests.TestMevRpcBlockchain.cs b/src/Nethermind/Nethermind.Mev.Test/MevRpcModuleTests.TestMevRpcBlockchain.cs index c0a3b4b1168..e370ca4ba36 100644 --- a/src/Nethermind/Nethermind.Mev.Test/MevRpcModuleTests.TestMevRpcBlockchain.cs +++ b/src/Nethermind/Nethermind.Mev.Test/MevRpcModuleTests.TestMevRpcBlockchain.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using FluentAssertions; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Config; using Nethermind.Consensus; using Nethermind.Consensus.Comparers; @@ -201,6 +202,7 @@ protected override BlockProcessor CreateBlockProcessor() State, ReceiptStorage, NullWitnessCollector.Instance, + new BlockhashStore(BlockTree, SpecProvider, State), LogManager); _tracerFactory = new TracerFactory( diff --git a/src/Nethermind/Nethermind.Network/P2P/P2PMessageKey.cs b/src/Nethermind/Nethermind.Network/P2P/P2PMessageKey.cs index 8f4e62c8c57..17bcacfb843 100644 --- a/src/Nethermind/Nethermind.Network/P2P/P2PMessageKey.cs +++ b/src/Nethermind/Nethermind.Network/P2P/P2PMessageKey.cs @@ -59,7 +59,7 @@ private string GetMessageType() if (!MessageNames.TryGetValue((Protocol.Protocol, PacketType), out string messageName)) { #if DEBUG - throw new NotImplementedException($"Message name for protocol {Protocol.Protocol} message id {PacketType} not set."); + throw new NotImplementedException($"Message name for protocol {Protocol.Protocol} message id {PacketType} not set."); #else return PacketType.ToString(); // Just use the integer directly then #endif diff --git a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs index fb7b53726ff..fa99bec8bf7 100644 --- a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs +++ b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Nethermind.Api; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Services; using Nethermind.Config; using Nethermind.Consensus.Processing; @@ -102,6 +103,7 @@ protected override BlockProcessor CreateBlockProcessor() _api.WorldState, _api.ReceiptStorage, _api.WitnessCollector, + new BlockhashStore(_api.BlockTree, _api.SpecProvider, _api.WorldState), _api.LogManager, _api.SpecHelper, contractRewriter); diff --git a/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs b/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs index f289c36f041..289ab3d3ab6 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs @@ -2,6 +2,9 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; +using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus.Processing; using Nethermind.Consensus.Rewards; @@ -10,6 +13,7 @@ using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; +using Nethermind.Evm; using Nethermind.Evm.Tracing; using Nethermind.Logging; using Nethermind.State; @@ -28,12 +32,13 @@ public class OptimismBlockProcessor : BlockProcessor IWorldState? stateProvider, IReceiptStorage? receiptStorage, IWitnessCollector? witnessCollector, + IBlockhashStore? blockhashStore, ILogManager? logManager, IOPConfigHelper opConfigHelper, Create2DeployerContractRewriter contractRewriter, IWithdrawalProcessor? withdrawalProcessor = null) : base(specProvider, blockValidator, rewardCalculator, blockTransactionsExecutor, - stateProvider, receiptStorage, witnessCollector, logManager, withdrawalProcessor, OptimismReceiptsRootCalculator.Instance) + stateProvider, receiptStorage, witnessCollector, blockhashStore, logManager, withdrawalProcessor, OptimismReceiptsRootCalculator.Instance) { ArgumentNullException.ThrowIfNull(stateProvider); _contractRewriter = contractRewriter; diff --git a/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs index 42df6a18aa3..b0d8d0620a1 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Config; using Nethermind.Consensus.Comparers; @@ -88,6 +89,7 @@ public class OptimismBlockProducerEnvFactory : BlockProducerEnvFactory readOnlyTxProcessingEnv.StateProvider, receiptStorage, NullWitnessCollector.Instance, + new BlockhashStore(_blockTree, specProvider, readOnlyTxProcessingEnv.StateProvider), logManager, _specHelper, new Create2DeployerContractRewriter(_specHelper, _specProvider, _blockTree), diff --git a/src/Nethermind/Nethermind.Specs.Test/MainnetSpecProviderTests.cs b/src/Nethermind/Nethermind.Specs.Test/MainnetSpecProviderTests.cs index 095ece65f81..9809cdb69fa 100644 --- a/src/Nethermind/Nethermind.Specs.Test/MainnetSpecProviderTests.cs +++ b/src/Nethermind/Nethermind.Specs.Test/MainnetSpecProviderTests.cs @@ -57,6 +57,21 @@ public void Cancun_eips(long blockNumber, ulong timestamp, bool isEnabled) } } + [TestCase(MainnetSpecProvider.ParisBlockNumber, MainnetSpecProvider.CancunBlockTimestamp, false)] + [TestCase(MainnetSpecProvider.ParisBlockNumber, MainnetSpecProvider.PragueBlockTimestamp, true)] + public void Prague_eips(long blockNumber, ulong timestamp, bool isEnabled) + { + _specProvider.GetSpec(new ForkActivation(blockNumber, timestamp)).IsEip2935Enabled.Should().Be(isEnabled); + if (isEnabled) + { + _specProvider.GetSpec(new ForkActivation(blockNumber, timestamp)).Eip2935ContractAddress.Should().NotBeNull(); + } + else + { + _specProvider.GetSpec(new ForkActivation(blockNumber, timestamp)).Eip2935ContractAddress.Should().BeNull(); + } + } + [Test] public void Dao_block_number_is_correct() { diff --git a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs index b36a57071d0..c03262e5510 100644 --- a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs @@ -147,6 +147,19 @@ public ulong Eip4844TransitionTimestamp } } + private ulong? _overridenEip2935TransitionTimeStamp; + public ulong Eip2935TransitionTimestamp + { + get + { + return _overridenEip2935TransitionTimeStamp ?? _spec.Eip2935TransitionTimestamp; + } + set + { + _overridenEip2935TransitionTimeStamp = value; + } + } + public bool IsEip1153Enabled => _spec.IsEip1153Enabled; public bool IsEip3651Enabled => _spec.IsEip3651Enabled; public bool IsEip3855Enabled => _spec.IsEip3855Enabled; @@ -157,6 +170,8 @@ public ulong Eip4844TransitionTimestamp public bool IsEip6780Enabled => _spec.IsEip6780Enabled; public bool IsEip4788Enabled => _spec.IsEip4788Enabled; public Address Eip4788ContractAddress => _spec.Eip4788ContractAddress; + public bool IsEip2935Enabled => _spec.IsEip2935Enabled; + public Address Eip2935ContractAddress => _spec.Eip2935ContractAddress; public UInt256 ForkBaseFee => _spec.ForkBaseFee; public UInt256 BaseFeeMaxChangeDenominator => _spec.BaseFeeMaxChangeDenominator; public long ElasticityMultiplier => _spec.ElasticityMultiplier; diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs index 817250bc01e..41fa983d646 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs @@ -117,6 +117,8 @@ public class ChainParameters public ulong? Eip6780TransitionTimestamp { get; set; } public ulong? Eip4788TransitionTimestamp { get; set; } public Address Eip4788ContractAddress { get; set; } + public ulong? Eip2935TransitionTimestamp { get; set; } + public Address Eip2935ContractAddress { get; set; } #region EIP-4844 parameters /// diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs index 7aad4bac04f..f2b2a6fbce8 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs @@ -251,6 +251,8 @@ private static ReleaseSpec CreateReleaseSpec(ChainSpec chainSpec, long releaseSt releaseSpec.IsEip6780Enabled = (chainSpec.Parameters.Eip6780TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.IsEip4788Enabled = (chainSpec.Parameters.Eip4788TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.Eip4788ContractAddress = chainSpec.Parameters.Eip4788ContractAddress; + releaseSpec.IsEip2935Enabled = (chainSpec.Parameters.Eip2935TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; + releaseSpec.Eip2935ContractAddress = chainSpec.Parameters.Eip2935ContractAddress; return releaseSpec; } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs index db4155117c8..512a4537cdf 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs @@ -143,6 +143,8 @@ private void LoadParameters(ChainSpecJson chainSpecJson, ChainSpec chainSpec) Eip6780TransitionTimestamp = chainSpecJson.Params.Eip6780TransitionTimestamp, Eip4788TransitionTimestamp = chainSpecJson.Params.Eip4788TransitionTimestamp, Eip4788ContractAddress = chainSpecJson.Params.Eip4788ContractAddress ?? Eip4788Constants.BeaconRootsAddress, + Eip2935TransitionTimestamp = chainSpecJson.Params.Eip2935TransitionTimestamp, + Eip2935ContractAddress = chainSpecJson.Params.Eip2935ContractAddress ?? Eip2935Constants.BlockHashHistoryAddress, TransactionPermissionContract = chainSpecJson.Params.TransactionPermissionContract, TransactionPermissionContractTransition = chainSpecJson.Params.TransactionPermissionContractTransition, ValidateChainIdTransition = chainSpecJson.Params.ValidateChainIdTransition, diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs index 5f22e8e6a85..283f755d9f0 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs @@ -141,6 +141,8 @@ internal class ChainSpecParamsJson public ulong? Eip6780TransitionTimestamp { get; set; } public ulong? Eip4788TransitionTimestamp { get; set; } public Address Eip4788ContractAddress { get; set; } + public ulong? Eip2935TransitionTimestamp { get; set; } + public Address Eip2935ContractAddress { get; set; } public UInt256? Eip4844BlobGasPriceUpdateFraction { get; set; } public ulong? Eip4844MaxBlobGasPerBlock { get; set; } public UInt256? Eip4844MinBlobGasPrice { get; set; } diff --git a/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs b/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs index ee5cfba6752..11036fa0946 100644 --- a/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs +++ b/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Threading; +using Nethermind.Core; using Nethermind.Core.Specs; namespace Nethermind.Specs.Forks; @@ -14,6 +15,8 @@ protected Prague() { Name = "Prague"; IsEip2537Enabled = true; + IsEip2935Enabled = true; + Eip2935ContractAddress = Eip2935Constants.BlockHashHistoryAddress; } public new static IReleaseSpec Instance => LazyInitializer.EnsureInitialized(ref _instance, () => new Prague()); diff --git a/src/Nethermind/Nethermind.Specs/MainnetSpecProvider.cs b/src/Nethermind/Nethermind.Specs/MainnetSpecProvider.cs index 4108dffe7b8..ce8148f311a 100644 --- a/src/Nethermind/Nethermind.Specs/MainnetSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/MainnetSpecProvider.cs @@ -47,7 +47,8 @@ public class MainnetSpecProvider : ISpecProvider { BlockNumber: < ParisBlockNumber } => GrayGlacier.Instance, { Timestamp: null } or { Timestamp: < ShanghaiBlockTimestamp } => Paris.Instance, { Timestamp: < CancunBlockTimestamp } => Shanghai.Instance, - _ => Cancun.Instance + { Timestamp: < PragueBlockTimestamp } => Cancun.Instance, + _ => Prague.Instance }; public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalDifficulty = null) @@ -86,7 +87,7 @@ public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalD (ForkActivation)GrayGlacierBlockNumber, ShanghaiActivation, CancunActivation, - //PragueActivation, + PragueActivation, //OsakaActivation }; diff --git a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs index 5de83c8356b..7d0f08e4ae7 100644 --- a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs @@ -91,5 +91,16 @@ public Address Eip4788ContractAddress get => IsEip4788Enabled ? _eip4788ContractAddress : null; set => _eip4788ContractAddress = value; } + + public bool IsEip2935Enabled { get; set; } + + private Address _eip2935ContractAddress; + public Address Eip2935ContractAddress + { + get => IsEip2935Enabled ? _eip2935ContractAddress : null; + set => _eip2935ContractAddress = value; + } + + public ulong Eip2935TransitionTimestamp { get; set; } } } diff --git a/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs index 8774d7a03ae..66f9bb2c756 100644 --- a/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs @@ -130,6 +130,9 @@ public bool IsEip158IgnoredAccount(Address address) public bool IsEip6780Enabled => _spec.IsEip6780Enabled; public bool IsEip4788Enabled => _spec.IsEip4788Enabled; public Address Eip4788ContractAddress => _spec.Eip4788ContractAddress; + public bool IsEip2935Enabled => _spec.IsEip2935Enabled; + public Address Eip2935ContractAddress => _spec.Eip2935ContractAddress; + public ulong Eip2935TransitionTimestamp => _spec.Eip2935TransitionTimestamp; public UInt256 ForkBaseFee => _spec.ForkBaseFee; public UInt256 BaseFeeMaxChangeDenominator => _spec.BaseFeeMaxChangeDenominator; public long ElasticityMultiplier => _spec.ElasticityMultiplier; diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs index 0111224a4f1..b2ae132370c 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Synchronization; using Nethermind.Consensus; @@ -273,7 +274,7 @@ private SyncTestContext CreateSyncManager(int index) new TxValidator(specProvider.ChainId), logManager, transactionComparerProvider.GetDefaultComparer()); - BlockhashProvider blockhashProvider = new(tree, LimboLogs.Instance); + BlockhashProvider blockhashProvider = new(tree, specProvider, stateProvider, LimboLogs.Instance); VirtualMachine virtualMachine = new(blockhashProvider, specProvider, logManager); Always sealValidator = Always.Valid; @@ -299,6 +300,7 @@ private SyncTestContext CreateSyncManager(int index) stateProvider, receiptStorage, NullWitnessCollector.Instance, + new BlockhashStore(tree, specProvider, stateProvider), logManager); RecoverSignatures step = new(ecdsa, txPool, specProvider, logManager); @@ -321,6 +323,7 @@ private SyncTestContext CreateSyncManager(int index) devState, receiptStorage, NullWitnessCollector.Instance, + new BlockhashStore(tree, specProvider, devState), logManager); BlockchainProcessor devChainProcessor = new(tree, devBlockProcessor, step, stateReader, logManager,