diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.TestAccountAbstractionRpcBlockchain.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.TestAccountAbstractionRpcBlockchain.cs index 778036b98164..e7726ddbbe05 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.TestAccountAbstractionRpcBlockchain.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.TestAccountAbstractionRpcBlockchain.cs @@ -252,7 +252,7 @@ protected override BlockProcessor CreateBlockProcessor() } protected override async Task Build(ISpecProvider? specProvider = null, - UInt256? initialValues = null) + UInt256? initialValues = null, bool addBlockOnStart = true) { TestBlockchain chain = await base.Build(specProvider, initialValues); IList
entryPointContractAddresses = new List
(); diff --git a/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs index 95dd21eecb13..bf648ea31b9b 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs @@ -363,7 +363,7 @@ protected override ILocalDataSource> GetWhitelistLocalDataS protected override ILocalDataSource> GetMinGasPricesLocalDataStore() => LocalDataSource.GetMinGasPricesLocalDataSource(); - protected override Task Build(ISpecProvider specProvider = null, UInt256? initialValues = null) + protected override Task Build(ISpecProvider specProvider = null, UInt256? initialValues = null, bool addBlockOnStart = true) { TempFile = TempPath.GetTempFile(); LocalDataSource = new TxPriorityContract.LocalDataSource(TempFile.Path, new EthereumJsonSerializer(), new FileSystem(), LimboLogs.Instance, Interval); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs index 58c6fb51a53a..6c1956ae6580 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs @@ -29,6 +29,7 @@ using Nethermind.Consensus.Withdrawals; using Nethermind.Core.Test.Blockchain; using Nethermind.Evm.TransactionProcessing; +using Nethermind.Consensus.BeaconBlockRoot; namespace Nethermind.Blockchain.Test { @@ -95,6 +96,42 @@ public void Can_store_a_witness() witnessCollector.Received(1).Persist(block.Hash); } + [Test, Timeout(Timeout.MaxTestTime)] + public void Creates_BeaconRootPrecompile_on_cancun_genesis() + { + IDb stateDb = new MemDb(); + IDb codeDb = new MemDb(); + var trieStore = new TrieStore(stateDb, LimboLogs.Instance); + + IWorldState stateProvider = new WorldState(trieStore, codeDb, LimboLogs.Instance); + ITransactionProcessor transactionProcessor = Substitute.For(); + IWitnessCollector witnessCollector = Substitute.For(); + BlockProcessor processor = new( + new TestSpecProvider(Cancun.Instance), + TestBlockValidator.AlwaysValid, + NoBlockRewards.Instance, + new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), + stateProvider, + NullReceiptStorage.Instance, + witnessCollector, + LimboLogs.Instance); + + BlockHeader header = Build.A.BlockHeader.WithAuthor(TestItem.AddressD).TestObject; + Block block = Build.A.Block.WithHeader(header) + .WithParentBeaconBlockRoot(Keccak.Zero) + .TestObject; + + Assert.IsFalse(stateProvider.AccountExists(BeaconBlockRootHandler.Address)); + + _ = processor.Process( + Keccak.EmptyTreeHash, + new List { block }, + ProcessingOptions.None, + NullBlockTracer.Instance); + + Assert.IsTrue(stateProvider.AccountExists(BeaconBlockRootHandler.Address)); + } + [Test, Timeout(Timeout.MaxTestTime)] public void Recovers_state_on_cancel() { diff --git a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPruningDiskTest.cs b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPruningDiskTest.cs index c5af5c5c360b..f603f6352016 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPruningDiskTest.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPruningDiskTest.cs @@ -48,7 +48,7 @@ public PruningTestBlockchain() TempDirectory = TempPath.GetTempDirectory(); } - protected override async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null) + protected override async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null, bool addBlockOnStart = true) { TestBlockchain chain = await base.Build(specProvider, initialValues); PruningDb = (IFullPruningDb)DbProvider.StateDb; diff --git a/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/BeaconBlockRootHandler.cs b/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/BeaconBlockRootHandler.cs new file mode 100644 index 000000000000..e1f1999ad4b4 --- /dev/null +++ b/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/BeaconBlockRootHandler.cs @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Nethermind.Core.Specs; +using Nethermind.Core; +using Nethermind.Int256; +using Nethermind.State; +using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; +namespace Nethermind.Consensus.BeaconBlockRoot; +public class BeaconBlockRootHandler : IBeaconBlockRootHandler +{ + public static Address Address { get; } = Address.FromNumber(0x0B); + public static UInt256 HISTORICAL_ROOTS_LENGTH = 98304; + public void UpdateState(Block block, IReleaseSpec spec, IWorldState stateProvider) + { + if (!spec.IsBeaconBlockRootAvailable || + block.IsGenesis || + block.Header.ParentBeaconBlockRoot is null) return; + + UInt256 timestamp = (UInt256)block.Timestamp; + Keccak parentBeaconBlockRoot = block.ParentBeaconBlockRoot; + + UInt256.Mod(timestamp, HISTORICAL_ROOTS_LENGTH, out UInt256 timestampReduced); + UInt256 rootIndex = timestampReduced + HISTORICAL_ROOTS_LENGTH; + + StorageCell tsStorageCell = new(Address, timestampReduced); + StorageCell brStorageCell = new(Address, rootIndex); + + + + stateProvider.Set(tsStorageCell, Bytes.WithoutLeadingZeros(timestamp.ToBigEndian()).ToArray()); + stateProvider.Set(brStorageCell, Bytes.WithoutLeadingZeros(parentBeaconBlockRoot.Bytes).ToArray()); + } +} diff --git a/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/IBeaconBlockRootHandler.cs b/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/IBeaconBlockRootHandler.cs new file mode 100644 index 000000000000..923239582b58 --- /dev/null +++ b/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/IBeaconBlockRootHandler.cs @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Nethermind.Core.Specs; +using Nethermind.Core; +using Nethermind.State; + +namespace Nethermind.Consensus.BeaconBlockRoot; +public interface IBeaconBlockRootHandler +{ + void UpdateState(Block block, IReleaseSpec spec, IWorldState state); +} diff --git a/src/Nethermind/Nethermind.Blockchain/GenesisLoader.cs b/src/Nethermind/Nethermind.Blockchain/GenesisLoader.cs index 8cac17f0ed3e..92a86abb6e32 100644 --- a/src/Nethermind/Nethermind.Blockchain/GenesisLoader.cs +++ b/src/Nethermind/Nethermind.Blockchain/GenesisLoader.cs @@ -15,6 +15,7 @@ using Nethermind.Evm.TransactionProcessing; using Nethermind.Specs.ChainSpecStyle; using Nethermind.State; +using Nethermind.Consensus.BeaconBlockRoot; namespace Nethermind.Blockchain { @@ -24,6 +25,7 @@ public class GenesisLoader private readonly ISpecProvider _specProvider; private readonly IWorldState _stateProvider; private readonly ITransactionProcessor _transactionProcessor; + private readonly BeaconBlockRootHandler _beaconBlockRootHandler; public GenesisLoader( ChainSpec chainSpec, @@ -35,6 +37,7 @@ public GenesisLoader( _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); _stateProvider = stateProvider ?? throw new ArgumentNullException(nameof(stateProvider)); _transactionProcessor = transactionProcessor ?? throw new ArgumentNullException(nameof(transactionProcessor)); + _beaconBlockRootHandler = new BeaconBlockRootHandler(); } public Block Load() @@ -45,6 +48,8 @@ public Block Load() // we no longer need the allocations - 0.5MB RAM, 9000 objects for mainnet _chainSpec.Allocations = null; + _beaconBlockRootHandler?.UpdateState(genesis, _specProvider.GenesisSpec, _stateProvider); + _stateProvider.Commit(_specProvider.GenesisSpec, true); _stateProvider.CommitTree(0); diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/BeaconBlockRoot/NullBeaconBlockRootHandler.cs b/src/Nethermind/Nethermind.Consensus.AuRa/BeaconBlockRoot/NullBeaconBlockRootHandler.cs new file mode 100644 index 000000000000..b6b55259702e --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus.AuRa/BeaconBlockRoot/NullBeaconBlockRootHandler.cs @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Nethermind.Consensus.BeaconBlockRoot; +using Nethermind.Core; +using Nethermind.Core.Specs; +using Nethermind.State; + +namespace Nethermind.Consensus.AuRa.BeaconBlockRoot; +internal class NullBeaconBlockRootHandler : IBeaconBlockRootHandler +{ + public void UpdateState(Block block, IReleaseSpec spec, IWorldState state) + { + } + + public static IBeaconBlockRootHandler Instance { get; } = new NullBeaconBlockRootHandler(); +} diff --git a/src/Nethermind/Nethermind.Consensus/EgineApiVersions.cs b/src/Nethermind/Nethermind.Consensus/EgineApiVersions.cs new file mode 100644 index 000000000000..598c87849079 --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus/EgineApiVersions.cs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +namespace Nethermind.Consensus; + +public static class EngineApiVersions +{ + public const int Paris = 1; + public const int Shanghai = 2; + public const int Cancun = 3; +} diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs index b9a42b1aaa97..3b04e947ce85 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs @@ -7,6 +7,7 @@ using System.Numerics; using Nethermind.Blockchain; using Nethermind.Blockchain.Receipts; +using Nethermind.Consensus.BeaconBlockRoot; using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Validators; using Nethermind.Consensus.Withdrawals; @@ -32,6 +33,7 @@ public partial class BlockProcessor : IBlockProcessor private readonly IReceiptStorage _receiptStorage; private readonly IWitnessCollector _witnessCollector; private readonly IWithdrawalProcessor _withdrawalProcessor; + private readonly IBeaconBlockRootHandler _beaconBlockRootHandler; private readonly IBlockValidator _blockValidator; private readonly IRewardCalculator _rewardCalculator; private readonly IBlockProcessor.IBlockTransactionsExecutor _blockTransactionsExecutor; @@ -64,7 +66,7 @@ public BlockProcessor( _withdrawalProcessor = withdrawalProcessor ?? new WithdrawalProcessor(stateProvider, logManager); _rewardCalculator = rewardCalculator ?? throw new ArgumentNullException(nameof(rewardCalculator)); _blockTransactionsExecutor = blockTransactionsExecutor ?? throw new ArgumentNullException(nameof(blockTransactionsExecutor)); - + _beaconBlockRootHandler = new BeaconBlockRootHandler(); _receiptsTracer = new BlockReceiptsTracer(); } @@ -225,6 +227,9 @@ protected virtual TxReceipt[] ProcessBlock( _receiptsTracer.SetOtherTracer(blockTracer); _receiptsTracer.StartNewBlockTrace(block); + _beaconBlockRootHandler.UpdateState(block, spec, _stateProvider); + _stateProvider.Commit(spec); + TxReceipt[] receipts = _blockTransactionsExecutor.ProcessTransactions(block, options, _receiptsTracer, spec); if (spec.IsEip4844Enabled) @@ -283,6 +288,7 @@ private Block PrepareBlockForProcessing(Block suggestedBlock) BaseFeePerGas = bh.BaseFeePerGas, WithdrawalsRoot = bh.WithdrawalsRoot, IsPostMerge = bh.IsPostMerge, + ParentBeaconBlockRoot = bh.ParentBeaconBlockRoot, }; return suggestedBlock.CreateCopy(headerForProcessing); diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs index d4e5accf15e2..4e593141924d 100644 --- a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs +++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs @@ -292,6 +292,7 @@ protected virtual BlockHeader PrepareBlockHeader(BlockHeader parent, { Author = blockAuthor, MixHash = payloadAttributes?.PrevRandao, + ParentBeaconBlockRoot = payloadAttributes?.ParentBeaconBlockRoot }; UInt256 difficulty = _difficultyCalculator.Calculate(header, parent); diff --git a/src/Nethermind/Nethermind.Consensus/Producers/PayloadAttributes.cs b/src/Nethermind/Nethermind.Consensus/Producers/PayloadAttributes.cs index a2e78b2a2fd6..9f02f3a69442 100644 --- a/src/Nethermind/Nethermind.Consensus/Producers/PayloadAttributes.cs +++ b/src/Nethermind/Nethermind.Consensus/Producers/PayloadAttributes.cs @@ -25,6 +25,7 @@ public class PayloadAttributes public IList? Withdrawals { get; set; } + public Keccak? ParentBeaconBlockRoot { get; set; } /// Gets or sets the gas limit. /// Used for MEV-Boost only. public long? GasLimit { get; set; } @@ -43,6 +44,11 @@ public string ToString(string indentation) sb.Append($", {nameof(Withdrawals)} count: {Withdrawals.Count}"); } + if (ParentBeaconBlockRoot is not null) + { + sb.Append($", {nameof(ParentBeaconBlockRoot)} : {ParentBeaconBlockRoot}"); + } + sb.Append('}'); return sb.ToString(); @@ -54,12 +60,15 @@ public static class PayloadAttributesExtensions public static string ComputePayloadId(this PayloadAttributes payloadAttributes, BlockHeader parentHeader) { bool hasWithdrawals = payloadAttributes.Withdrawals is not null; - Span inputSpan = stackalloc byte[32 + 32 + 32 + 20 + (hasWithdrawals ? 32 : 0)]; + bool hasBeaconParentBlockRoot = payloadAttributes.ParentBeaconBlockRoot is not null; - parentHeader.Hash!.Bytes.CopyTo(inputSpan[..32]); - BinaryPrimitives.WriteUInt64BigEndian(inputSpan.Slice(56, 8), payloadAttributes.Timestamp); - payloadAttributes.PrevRandao.Bytes.CopyTo(inputSpan.Slice(64, 32)); - payloadAttributes.SuggestedFeeRecipient.Bytes.CopyTo(inputSpan.Slice(96, 20)); + const int preambleLength = Keccak.Size + Keccak.Size + Keccak.Size + Address.ByteLength; + Span inputSpan = stackalloc byte[preambleLength + (hasWithdrawals ? Keccak.Size : 0) + (hasBeaconParentBlockRoot ? Keccak.Size : 0)]; + + parentHeader.Hash!.Bytes.CopyTo(inputSpan[..Keccak.Size]); + BinaryPrimitives.WriteUInt64BigEndian(inputSpan.Slice(56, sizeof(UInt64)), payloadAttributes.Timestamp); + payloadAttributes.PrevRandao.Bytes.CopyTo(inputSpan.Slice(64, Keccak.Size)); + payloadAttributes.SuggestedFeeRecipient.Bytes.CopyTo(inputSpan.Slice(96, Address.ByteLength)); if (hasWithdrawals) { @@ -67,7 +76,12 @@ public static string ComputePayloadId(this PayloadAttributes payloadAttributes, ? PatriciaTree.EmptyTreeHash : new WithdrawalTrie(payloadAttributes.Withdrawals).RootHash; - withdrawalsRootHash.Bytes.CopyTo(inputSpan[116..]); + withdrawalsRootHash.Bytes.CopyTo(inputSpan[preambleLength..]); + } + + if (hasBeaconParentBlockRoot) + { + payloadAttributes.ParentBeaconBlockRoot.Bytes.CopyTo(inputSpan[(preambleLength + (hasWithdrawals ? Keccak.Size : 0))..]); } ValueKeccak inputHash = ValueKeccak.Compute(inputSpan); @@ -76,7 +90,20 @@ public static string ComputePayloadId(this PayloadAttributes payloadAttributes, } public static int GetVersion(this PayloadAttributes executionPayload) => - executionPayload.Withdrawals is null ? 1 : 2; + executionPayload switch + { + { ParentBeaconBlockRoot: not null, Withdrawals: not null } => EngineApiVersions.Cancun, + { Withdrawals: not null } => EngineApiVersions.Shanghai, + _ => EngineApiVersions.Paris + }; + + public static int ExpectedEngineSpecVersion(this IReleaseSpec spec) => + spec switch + { + { WithdrawalsEnabled: true, IsEip4844Enabled: true } => EngineApiVersions.Cancun, + { WithdrawalsEnabled: true } => EngineApiVersions.Shanghai, + _ => EngineApiVersions.Paris + }; public static bool Validate( this PayloadAttributes payloadAttributes, @@ -85,14 +112,17 @@ public static bool Validate( [NotNullWhen(false)] out string? error) { int actualVersion = payloadAttributes.GetVersion(); + int expectedVersion = spec.ExpectedEngineSpecVersion(); - error = actualVersion switch + error = null; + if (actualVersion != expectedVersion) { - 1 when spec.WithdrawalsEnabled => "PayloadAttributesV2 expected", - > 1 when !spec.WithdrawalsEnabled => "PayloadAttributesV1 expected", - _ => actualVersion > version ? $"PayloadAttributesV{version} expected" : null - }; - + error = $"PayloadAttributesV{expectedVersion} expected"; + } + else if (actualVersion > version) + { + error = $"PayloadAttributesV{version} expected"; + } return error is null; } diff --git a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs index c07717c9e9fa..9d3dba58e2a8 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs @@ -146,6 +146,11 @@ public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, B if (_logger.IsError) _logger.Error($"- excess blob gas: expected {suggestedBlock.Header.ExcessBlobGas}, got {processedBlock.Header.ExcessBlobGas}"); } + if (processedBlock.Header.ParentBeaconBlockRoot != suggestedBlock.Header.ParentBeaconBlockRoot) + { + if (_logger.IsError) _logger.Error($"- parent beacon block root : expected {suggestedBlock.Header.ParentBeaconBlockRoot}, got {processedBlock.Header.ParentBeaconBlockRoot}"); + } + for (int i = 0; i < processedBlock.Transactions.Length; i++) { if (receipts[i].Error is not null && receipts[i].GasUsed == 0 && receipts[i].Error == "invalid") diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs index e12cadcbc01e..7a06b7b6b084 100644 --- a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs +++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs @@ -10,6 +10,7 @@ using Nethermind.Blockchain.Receipts; using Nethermind.Config; using Nethermind.Consensus; +using Nethermind.Consensus.BeaconBlockRoot; using Nethermind.Consensus.Comparers; using Nethermind.Consensus.Processing; using Nethermind.Consensus.Producers; @@ -49,6 +50,7 @@ public class TestBlockchain : IDisposable public ITxPool TxPool { get; set; } = null!; public IDb CodeDb => DbProvider.CodeDb; public IBlockProcessor BlockProcessor { get; set; } = null!; + public IBeaconBlockRootHandler ParentBeaconBlockRootHandler { get; set; } = null!; public IBlockchainProcessor BlockchainProcessor { get; set; } = null!; public IBlockPreprocessorStep BlockPreprocessorStep { get; set; } = null!; @@ -107,7 +109,7 @@ protected TestBlockchain() public static TransactionBuilder BuildSimpleTransaction => Builders.Build.A.Transaction.SignedAndResolved(TestItem.PrivateKeyA).To(AccountB); - protected virtual async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null) + protected virtual async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null, bool addBlockOnStart = true) { Timestamper = new ManualTimestamper(new DateTime(2020, 2, 15, 12, 50, 30, DateTimeKind.Utc)); JsonSerializer = new EthereumJsonSerializer(); @@ -116,6 +118,13 @@ protected virtual async Task Build(ISpecProvider? specProvider = DbProvider = await CreateDbProvider(); TrieStore = new TrieStore(StateDb, LogManager); State = new WorldState(TrieStore, DbProvider.CodeDb, LogManager); + + // Eip4788 precompile state account + if (specProvider?.GenesisSpec?.IsBeaconBlockRootAvailable ?? false) + { + State.CreateAccount(BeaconBlockRootHandler.Address, 1); + } + State.CreateAccount(TestItem.AddressA, (initialValues ?? InitialValue)); State.CreateAccount(TestItem.AddressB, (initialValues ?? InitialValue)); State.CreateAccount(TestItem.AddressC, (initialValues ?? InitialValue)); @@ -169,6 +178,7 @@ protected virtual async Task Build(ISpecProvider? specProvider = BloomStorage bloomStorage = new(new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); ReceiptsRecovery receiptsRecovery = new(new EthereumEcdsa(SpecProvider.ChainId, LimboLogs.Instance), SpecProvider); LogFinder = new LogFinder(BlockTree, ReceiptStorage, ReceiptStorage, bloomStorage, LimboLogs.Instance, receiptsRecovery); + ParentBeaconBlockRootHandler = new BeaconBlockRootHandler(); BlockProcessor = CreateBlockProcessor(); BlockchainProcessor chainProcessor = new(BlockTree, BlockProcessor, BlockPreprocessorStep, StateReader, LogManager, Consensus.Processing.BlockchainProcessor.Options.Default); @@ -194,7 +204,10 @@ protected virtual async Task Build(ISpecProvider? specProvider = BlockTree.SuggestBlock(genesis); await WaitAsync(_resetEvent, "Failed to process genesis in time."); - await AddBlocksOnStart(); + + if (addBlockOnStart) + await AddBlocksOnStart(); + return this; } @@ -292,18 +305,33 @@ protected virtual Block GetGenesisBlock() genesisBlockBuilder = GenesisBlockBuilder; } - genesisBlockBuilder.WithStateRoot(State.StateRoot); if (SealEngineType == Core.SealEngineType.AuRa) { genesisBlockBuilder.WithAura(0, new byte[65]); } + if (SpecProvider.GenesisSpec.IsBeaconBlockRootAvailable) + { + genesisBlockBuilder.WithParentBeaconBlockRoot(TestItem.KeccakG); + } + if (SpecProvider.GenesisSpec.IsEip4844Enabled) { genesisBlockBuilder.WithBlobGasUsed(0); genesisBlockBuilder.WithExcessBlobGas(0); } + + if (SpecProvider.GenesisSpec.IsBeaconBlockRootAvailable) + { + + ParentBeaconBlockRootHandler.UpdateState(genesisBlockBuilder.TestObject, SpecProvider.GenesisSpec, State); + State.Commit(SpecProvider.GenesisSpec); + State.CommitTree(0); + + State.RecalculateStateRoot(); + } + genesisBlockBuilder.WithStateRoot(State.StateRoot); return genesisBlockBuilder.TestObject; } diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs index dc02a45ca4dc..66d6f4e19c27 100644 --- a/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs +++ b/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs @@ -277,5 +277,11 @@ public BlockBuilder WithWithdrawals(params Withdrawal[]? withdrawals) return this; } + + public BlockBuilder WithParentBeaconBlockRoot(Keccak parentBeaconBlockRoot) + { + TestObjectInternal.Header.ParentBeaconBlockRoot = parentBeaconBlockRoot; + return this; + } } } diff --git a/src/Nethermind/Nethermind.Core/Block.cs b/src/Nethermind/Nethermind.Core/Block.cs index 8a86c1253e47..b1b3e1b03daa 100644 --- a/src/Nethermind/Nethermind.Core/Block.cs +++ b/src/Nethermind/Nethermind.Core/Block.cs @@ -107,6 +107,7 @@ public Transaction[] Transactions public bool IsBodyMissing => Header.HasBody && Body.IsEmpty; public Keccak? WithdrawalsRoot => Header.WithdrawalsRoot; // do not add setter here + public Keccak? ParentBeaconBlockRoot => Header.ParentBeaconBlockRoot; // do not add setter here public override string ToString() => ToString(Format.Short); diff --git a/src/Nethermind/Nethermind.Core/BlockHeader.cs b/src/Nethermind/Nethermind.Core/BlockHeader.cs index 49f22f5c83e8..c47e73c02d39 100644 --- a/src/Nethermind/Nethermind.Core/BlockHeader.cs +++ b/src/Nethermind/Nethermind.Core/BlockHeader.cs @@ -26,7 +26,8 @@ public BlockHeader( ulong timestamp, byte[] extraData, ulong? blobGasUsed = null, - ulong? excessBlobGas = null) + ulong? excessBlobGas = null, + Keccak? parentBeaconBlockRoot = null) { ParentHash = parentHash; UnclesHash = unclesHash; @@ -36,6 +37,7 @@ public BlockHeader( GasLimit = gasLimit; Timestamp = timestamp; ExtraData = extraData; + ParentBeaconBlockRoot = parentBeaconBlockRoot; BlobGasUsed = blobGasUsed; ExcessBlobGas = excessBlobGas; } @@ -67,6 +69,7 @@ public BlockHeader( public long? AuRaStep { get; set; } public UInt256 BaseFeePerGas { get; set; } public Keccak? WithdrawalsRoot { get; set; } + public Keccak? ParentBeaconBlockRoot { get; set; } public ulong? BlobGasUsed { get; set; } public ulong? ExcessBlobGas { get; set; } public bool HasBody => (TxRoot is not null && TxRoot != Keccak.EmptyTreeHash) @@ -101,6 +104,10 @@ public string ToString(string indent) { builder.AppendLine($"{indent}WithdrawalsRoot: {WithdrawalsRoot}"); } + if (ParentBeaconBlockRoot is not null) + { + builder.AppendLine($"{indent}ParentBeaconBlockRoot: {ParentBeaconBlockRoot}"); + } if (BlobGasUsed is not null || ExcessBlobGas is not null) { builder.AppendLine($"{indent}BlobGasUsed: {BlobGasUsed}"); diff --git a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs index 4dfc2b7b533f..0108fee22e70 100644 --- a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs @@ -267,6 +267,11 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec /// bool IsEip4844Enabled { get; } + /// + /// Parent Beacon Block precompile + /// + bool IsEip4788Enabled { get; } + /// /// SELFDESTRUCT only in same transaction /// @@ -352,6 +357,7 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec public bool WithdrawalsEnabled => IsEip4895Enabled; public bool SelfdestructOnlyOnSameTransaction => IsEip6780Enabled; - bool MCopyIncluded => IsEip5656Enabled; + public bool IsBeaconBlockRootAvailable => IsEip4788Enabled; + public bool MCopyIncluded => IsEip5656Enabled; } } diff --git a/src/Nethermind/Nethermind.Evm.Test/BeaconParentBlockRootPrecompileTests.cs b/src/Nethermind/Nethermind.Evm.Test/BeaconParentBlockRootPrecompileTests.cs new file mode 100644 index 000000000000..131ab43ffccc --- /dev/null +++ b/src/Nethermind/Nethermind.Evm.Test/BeaconParentBlockRootPrecompileTests.cs @@ -0,0 +1,102 @@ +// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Collections.Generic; +using System.Linq; +using Nethermind.Blockchain.Receipts; +using Nethermind.Blockchain; +using Nethermind.Consensus.Processing; +using Nethermind.Consensus.Rewards; +using Nethermind.Consensus.Validators; +using Nethermind.Core; +using Nethermind.Core.Extensions; +using Nethermind.Core.Specs; +using Nethermind.Core.Test.Builders; +using Nethermind.Db.Blooms; +using Nethermind.Db; +using Nethermind.Evm.TransactionProcessing; +using Nethermind.Int256; +using Nethermind.Logging; +using Nethermind.Specs; +using Nethermind.Specs.Forks; +using Nethermind.State.Repositories; +using Nethermind.State; +using Nethermind.Trie.Pruning; +using NUnit.Framework; +using Nethermind.Core.Crypto; +using Nethermind.Evm.Tracing.GethStyle; +using Nethermind.Core.Test.Blockchain; +using System.Threading.Tasks; + +namespace Nethermind.Evm.Test; + +public class Eip4788Tests : TestBlockchain +{ + private ISpecProvider specProvider; + private SenderRecipientAndMiner senderRecipientAndMiner = SenderRecipientAndMiner.Default; + protected static IEnumerable<(IReleaseSpec Spec, bool ShouldFail)> BeaconBlockRootGetPayloadV3ForDifferentSpecTestSource() + { + yield return (Shanghai.Instance, true); + yield return (Cancun.Instance, false); + } + + [TestCaseSource(nameof(BeaconBlockRootGetPayloadV3ForDifferentSpecTestSource))] + public async Task BeaconBlockRoot_Is_Stored_Correctly_and_Only_Valid_PostCancun((IReleaseSpec Spec, bool ShouldFail) testCase) + { + specProvider = new TestSpecProvider(testCase.Spec); + TestBlockchain testBlockchain = await base.Build(specProvider, addBlockOnStart: false); + GethLikeBlockMemoryTracer? tracer = new(GethTraceOptions.Default); + Block block = CreateBlock(testBlockchain.State, testCase.Spec); + _ = testBlockchain.BlockProcessor.Process( + testBlockchain.State.StateRoot, + new List { block }, + ProcessingOptions.NoValidation, + tracer); + List? traces = tracer.BuildResult().ToList(); + Assert.That(testCase.ShouldFail, Is.EqualTo(traces[0].Failed)); + } + + Block CreateBlock(IWorldState testState, IReleaseSpec spec) + { + Keccak parentBeaconBlockRoot = TestItem.KeccakG; + + byte[] bytecode = Prepare + .EvmCode + .TIMESTAMP() + .MSTORE(0) + .CALL(100.Ether(), Address.FromNumber(0x0B), 0, 0, 32, 32, 32) + .MLOAD(32) + .EQ(new UInt256(parentBeaconBlockRoot.Bytes, true)) + .JUMPI(0x57) + .INVALID() + .JUMPDEST() + .STOP() + .Done; + + testState.InsertCode(TestBlockchain.AccountA, bytecode, specProvider.GenesisSpec); + Transaction tx = Core.Test.Builders.Build.A.Transaction + .WithGasLimit(1_000_000) + .WithGasPrice(1) + .WithValue(1) + .WithSenderAddress(TestBlockchain.AccountB) + .WithNonce(testState.GetNonce(TestBlockchain.AccountB)) + .To(TestBlockchain.AccountA) + .TestObject; + + testState.Commit(spec); + testState.CommitTree(0); + testState.RecalculateStateRoot(); + BlockBuilder blockBuilder = Core.Test.Builders.Build.A.Block.Genesis + .WithDifficulty(1) + .WithTotalDifficulty(1L) + .WithTransactions(tx) + .WithPostMergeFlag(true); + + if (spec.IsBeaconBlockRootAvailable) + { + blockBuilder.WithParentBeaconBlockRoot(parentBeaconBlockRoot); + } + + return blockBuilder.TestObject; + } +} diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip2565Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip2565Tests.cs index afc87008b9aa..2f261a9ca3a5 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip2565Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip2565Tests.cs @@ -47,7 +47,7 @@ public void Overflow_gas_cost() public void ModExp_run_should_not_throw_exception(string inputStr) { Prepare input = Prepare.EvmCode.FromCode(inputStr); - Assert.DoesNotThrow(() => ModExpPrecompile.Instance.Run(input.Done.ToArray(), London.Instance)); + Assert.DoesNotThrow(() => ModExpPrecompile.Instance.Run(input.Done.ToArray(), London.Instance, null)); long gas = ModExpPrecompile.Instance.DataGasCost(input.Done, London.Instance); gas.Should().Be(200); } diff --git a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs index 2832236dfe06..15676b8f4195 100644 --- a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs +++ b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs @@ -237,20 +237,21 @@ protected Block BuildBlock(long blockNumber, SenderRecipientAndMiner senderRecip return BuildBlock(blockNumber, senderRecipientAndMiner, null); } - protected virtual Block BuildBlock(long blockNumber, SenderRecipientAndMiner senderRecipientAndMiner, - Transaction tx, long blockGasLimit = DefaultBlockGasLimit, - ulong timestamp = 0) - { - senderRecipientAndMiner ??= SenderRecipientAndMiner.Default; - return Build.A.Block.WithNumber(blockNumber) - .WithTransactions(tx is null ? new Transaction[0] : new[] { tx }) - .WithGasLimit(blockGasLimit) - .WithBeneficiary(senderRecipientAndMiner.Miner) - .WithBlobGasUsed(0) - .WithExcessBlobGas(0) - .WithTimestamp(timestamp) - .TestObject; - } + protected virtual Block BuildBlock(long blockNumber, SenderRecipientAndMiner senderRecipientAndMiner, + Transaction tx, long blockGasLimit = DefaultBlockGasLimit, + ulong timestamp = 0) + { + senderRecipientAndMiner ??= SenderRecipientAndMiner.Default; + return Build.A.Block.WithNumber(blockNumber) + .WithTransactions(tx is null ? new Transaction[0] : new[] { tx }) + .WithGasLimit(blockGasLimit) + .WithBeneficiary(senderRecipientAndMiner.Miner) + .WithBlobGasUsed(0) + .WithExcessBlobGas(0) + .WithTimestamp(timestamp) + .WithParentBeaconBlockRoot(TestItem.KeccakG) + .TestObject; + } protected void AssertGas(TestAllTracerWithOutput receipt, long gas) { diff --git a/src/Nethermind/Nethermind.Evm/GasCostOf.cs b/src/Nethermind/Nethermind.Evm/GasCostOf.cs index 5e8b2291dc1c..6cd434c45a12 100644 --- a/src/Nethermind/Nethermind.Evm/GasCostOf.cs +++ b/src/Nethermind/Nethermind.Evm/GasCostOf.cs @@ -54,6 +54,8 @@ public static class GasCostOf public const long InitCodeWord = 2; //eip-3860 gas per word cost for init code size public const long ColdSLoad = 2100; // eip-2929 + public const long BeaconBlockRootPrecompile = ColdSLoad * 2; // Eip hardcded 4200 // eip-2929 + public const long ColdAccountAccess = 2600; // eip-2929 public const long WarmStateRead = 100; // eip-2929 diff --git a/src/Nethermind/Nethermind.Evm/Metrics.cs b/src/Nethermind/Nethermind.Evm/Metrics.cs index cf38e9a29226..28983fe03a13 100644 --- a/src/Nethermind/Nethermind.Evm/Metrics.cs +++ b/src/Nethermind/Nethermind.Evm/Metrics.cs @@ -84,12 +84,16 @@ public class Metrics [Description("Number of Point Evaluation precompile calls.")] public static long PointEvaluationPrecompile { get; set; } + [CounterMetric] + [Description("Number of Parent Beacon Block Root precompile calls.")] + public static int BeaconBlockRootPrecompile { get; set; } + + [Description("Number of calls made to addresses without code.")] public static long EmptyCalls { get; set; } [Description("Number of contract create calls.")] public static long Creates { get; set; } - internal static long Transactions { get; set; } internal static decimal AveGasPrice { get; set; } internal static decimal MinGasPrice { get; set; } = decimal.MaxValue; diff --git a/src/Nethermind/Nethermind.Evm/Nethermind.Evm.csproj b/src/Nethermind/Nethermind.Evm/Nethermind.Evm.csproj index bf4f06ca1676..949467e8b6c9 100644 --- a/src/Nethermind/Nethermind.Evm/Nethermind.Evm.csproj +++ b/src/Nethermind/Nethermind.Evm/Nethermind.Evm.csproj @@ -17,4 +17,7 @@ + + + diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs b/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs index 560ef8ca8e7b..d41e5cc6446e 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs @@ -27,6 +27,7 @@ public static bool IsPrecompile(this Address address, IReleaseSpec releaseSpec) 0x08 => releaseSpec.Bn128Enabled, 0x09 => releaseSpec.BlakeEnabled, 0x0a => releaseSpec.IsEip4844Enabled, + // 0x0b => releaseSpec.IsBeaconBlockRootAvailable, 0x0c => releaseSpec.Bls381Enabled, 0x0d => releaseSpec.Bls381Enabled, 0x0e => releaseSpec.Bls381Enabled, diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Blake2FPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Blake2FPrecompile.cs index f0d374134756..9b4a5cda9e89 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Blake2FPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Blake2FPrecompile.cs @@ -6,16 +6,17 @@ using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Crypto.Blake2; +using Nethermind.State; namespace Nethermind.Evm.Precompiles { - public class Blake2FPrecompile : IPrecompile + public class Blake2FPrecompile : IPrecompile { private const int RequiredInputLength = 213; private Blake2Compression _blake = new(); - public static readonly IPrecompile Instance = new Blake2FPrecompile(); + public static readonly Blake2FPrecompile Instance = new Blake2FPrecompile(); public static Address Address { get; } = Address.FromNumber(9); @@ -39,7 +40,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return rounds; } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { if (inputData.Length != RequiredInputLength) { diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1AddPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1AddPrecompile.cs index e3bc46d020d7..7fe2c117716d 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1AddPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1AddPrecompile.cs @@ -5,15 +5,16 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles.Bls; /// /// https://eips.ethereum.org/EIPS/eip-2537 /// -public class G1AddPrecompile : IPrecompile +public class G1AddPrecompile : IPrecompile { - public static IPrecompile Instance = new G1AddPrecompile(); + public static G1AddPrecompile Instance = new G1AddPrecompile(); private G1AddPrecompile() { @@ -31,7 +32,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return 0L; } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { const int expectedInputLength = 4 * BlsParams.LenFp; if (inputData.Length != expectedInputLength) diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MulPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MulPrecompile.cs index bcf58d628eda..8619e54ada64 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MulPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MulPrecompile.cs @@ -5,15 +5,16 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles.Bls; /// /// https://eips.ethereum.org/EIPS/eip-2537 /// -public class G1MulPrecompile : IPrecompile +public class G1MulPrecompile : IPrecompile { - public static IPrecompile Instance = new G1MulPrecompile(); + public static G1MulPrecompile Instance = new G1MulPrecompile(); private G1MulPrecompile() { @@ -31,7 +32,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return 0L; } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { const int expectedInputLength = 2 * BlsParams.LenFp + BlsParams.LenFr; if (inputData.Length != expectedInputLength) diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MultiExpPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MultiExpPrecompile.cs index 337a27876fcb..f7514bb80603 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MultiExpPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MultiExpPrecompile.cs @@ -5,15 +5,16 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles.Bls; /// /// https://eips.ethereum.org/EIPS/eip-2537 /// -public class G1MultiExpPrecompile : IPrecompile +public class G1MultiExpPrecompile : IPrecompile { - public static IPrecompile Instance = new G1MultiExpPrecompile(); + public static G1MultiExpPrecompile Instance = new G1MultiExpPrecompile(); private G1MultiExpPrecompile() { @@ -34,7 +35,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS private const int ItemSize = 160; - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { if (inputData.Length % ItemSize > 0 || inputData.Length == 0) { diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2AddPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2AddPrecompile.cs index 387b15b7cb2d..b247daaf7ec6 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2AddPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2AddPrecompile.cs @@ -5,15 +5,16 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles.Bls; /// /// https://eips.ethereum.org/EIPS/eip-2537 /// -public class G2AddPrecompile : IPrecompile +public class G2AddPrecompile : IPrecompile { - public static IPrecompile Instance = new G2AddPrecompile(); + public static G2AddPrecompile Instance = new G2AddPrecompile(); private G2AddPrecompile() { @@ -31,7 +32,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return 0L; } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { const int expectedInputLength = 8 * BlsParams.LenFp; if (inputData.Length != expectedInputLength) diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MulPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MulPrecompile.cs index e8bcb212b907..49c4ef13388c 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MulPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MulPrecompile.cs @@ -5,15 +5,16 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles.Bls; /// /// https://eips.ethereum.org/EIPS/eip-2537 /// -public class G2MulPrecompile : IPrecompile +public class G2MulPrecompile : IPrecompile { - public static IPrecompile Instance = new G2MulPrecompile(); + public static G2MulPrecompile Instance = new G2MulPrecompile(); private G2MulPrecompile() { @@ -31,7 +32,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return 0L; } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { const int expectedInputLength = 4 * BlsParams.LenFp + BlsParams.LenFr; if (inputData.Length != expectedInputLength) diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MultiExpPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MultiExpPrecompile.cs index 8092a7923fe1..a6e71c1afde0 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MultiExpPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MultiExpPrecompile.cs @@ -5,15 +5,16 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles.Bls; /// /// https://eips.ethereum.org/EIPS/eip-2537 /// -public class G2MultiExpPrecompile : IPrecompile +public class G2MultiExpPrecompile : IPrecompile { - public static IPrecompile Instance = new G2MultiExpPrecompile(); + public static G2MultiExpPrecompile Instance = new G2MultiExpPrecompile(); private G2MultiExpPrecompile() { @@ -34,7 +35,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS private const int ItemSize = 288; - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { if (inputData.Length % ItemSize > 0 || inputData.Length == 0) { diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapToG1Precompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapToG1Precompile.cs index e15d5fb320a4..55b58a25cad9 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapToG1Precompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapToG1Precompile.cs @@ -5,15 +5,16 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles.Bls; /// /// https://eips.ethereum.org/EIPS/eip-2537 /// -public class MapToG1Precompile : IPrecompile +public class MapToG1Precompile : IPrecompile { - public static IPrecompile Instance = new MapToG1Precompile(); + public static MapToG1Precompile Instance = new MapToG1Precompile(); private MapToG1Precompile() { @@ -31,7 +32,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return 0L; } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { const int expectedInputLength = 64; if (inputData.Length != expectedInputLength) diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapToG2Precompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapToG2Precompile.cs index b0fa9e16ad94..0e12870fbeea 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapToG2Precompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapToG2Precompile.cs @@ -5,15 +5,16 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles.Bls; /// /// https://eips.ethereum.org/EIPS/eip-2537 /// -public class MapToG2Precompile : IPrecompile +public class MapToG2Precompile : IPrecompile { - public static IPrecompile Instance = new MapToG2Precompile(); + public static MapToG2Precompile Instance = new MapToG2Precompile(); private MapToG2Precompile() { @@ -31,7 +32,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return 0L; } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { const int expectedInputLength = 2 * BlsParams.LenFp; if (inputData.Length != expectedInputLength) diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/PairingPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/PairingPrecompile.cs index 0d7e5144efa5..c202180db1bf 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/PairingPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/PairingPrecompile.cs @@ -5,13 +5,14 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles.Bls; /// /// https://eips.ethereum.org/EIPS/eip-2537 /// -public class PairingPrecompile : IPrecompile +public class PairingPrecompile : IPrecompile { private const int PairSize = 384; @@ -19,7 +20,7 @@ private PairingPrecompile() { } public static Address Address { get; } = Address.FromNumber(0x12); - public static IPrecompile Instance = new PairingPrecompile(); + public static PairingPrecompile Instance = new PairingPrecompile(); public long BaseGasCost(IReleaseSpec releaseSpec) => 115000L; @@ -28,7 +29,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return 23000L * (inputData.Length / PairSize); } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { if (inputData.Length % PairSize > 0 || inputData.Length == 0) { diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/EcRecoverPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/EcRecoverPrecompile.cs index 831bdef83b3d..ee9bffdf226c 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/EcRecoverPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/EcRecoverPrecompile.cs @@ -8,12 +8,13 @@ using Nethermind.Core.Specs; using Nethermind.Crypto; using Nethermind.Logging; +using Nethermind.State; namespace Nethermind.Evm.Precompiles { - public class EcRecoverPrecompile : IPrecompile + public class EcRecoverPrecompile : IPrecompile { - public static readonly IPrecompile Instance = new EcRecoverPrecompile(); + public static readonly EcRecoverPrecompile Instance = new EcRecoverPrecompile(); private EcRecoverPrecompile() { @@ -35,7 +36,7 @@ public long BaseGasCost(IReleaseSpec releaseSpec) private readonly byte[] _zero31 = new byte[31]; - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { Metrics.EcRecoverPrecompile++; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/IPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/IPrecompile.cs index 1d80239ebdfc..9b8cacb772c5 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/IPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/IPrecompile.cs @@ -4,6 +4,7 @@ using System; using Nethermind.Core; using Nethermind.Core.Specs; +using Nethermind.State; namespace Nethermind.Evm.Precompiles { @@ -15,6 +16,12 @@ public interface IPrecompile long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec); - (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec); + (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? state = null); + } + + + public interface IPrecompile : IPrecompile + { + static TPrecompileTypeInstance Instance { get; } } } diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/IdentityPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/IdentityPrecompile.cs index a760f842d712..564061da1b63 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/IdentityPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/IdentityPrecompile.cs @@ -4,12 +4,13 @@ using System; using Nethermind.Core; using Nethermind.Core.Specs; +using Nethermind.State; namespace Nethermind.Evm.Precompiles { - public class IdentityPrecompile : IPrecompile + public class IdentityPrecompile : IPrecompile { - public static readonly IPrecompile Instance = new IdentityPrecompile(); + public static readonly IdentityPrecompile Instance = new IdentityPrecompile(); private IdentityPrecompile() { @@ -27,7 +28,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return 3L * EvmPooledMemory.Div32Ceiling((ulong)inputData.Length); } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { return (inputData, true); } diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/ModExpPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/ModExpPrecompile.cs index f45048107d2f..871df924e7a9 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/ModExpPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/ModExpPrecompile.cs @@ -9,15 +9,16 @@ using Nethermind.Core.Specs; using Nethermind.Int256; using MathGmp.Native; +using Nethermind.State; namespace Nethermind.Evm.Precompiles { /// /// https://github.com/ethereum/EIPs/blob/vbuterin-patch-2/EIPS/bigint_modexp.md /// - public class ModExpPrecompile : IPrecompile + public class ModExpPrecompile : IPrecompile { - public static readonly IPrecompile Instance = new ModExpPrecompile(); + public static readonly ModExpPrecompile Instance = new ModExpPrecompile(); private ModExpPrecompile() { @@ -102,7 +103,7 @@ private static (int, int, int) GetInputLengths(in ReadOnlyMemory inputData return (baseLength, expLength, modulusLength); } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { Metrics.ModExpPrecompile++; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/ModExpPrecompilePreEip2565.cs b/src/Nethermind/Nethermind.Evm/Precompiles/ModExpPrecompilePreEip2565.cs index a2bee1881478..5635a9ae95d1 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/ModExpPrecompilePreEip2565.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/ModExpPrecompilePreEip2565.cs @@ -7,6 +7,7 @@ using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Int256; +using Nethermind.State; namespace Nethermind.Evm.Precompiles { @@ -14,9 +15,9 @@ namespace Nethermind.Evm.Precompiles /// https://github.com/ethereum/EIPs/blob/vbuterin-patch-2/EIPS/bigint_modexp.md /// [Obsolete("Pre-eip2565 implementation")] - public class ModExpPrecompilePreEip2565 : IPrecompile + public class ModExpPrecompilePreEip2565 : IPrecompile { - public static IPrecompile Instance = new ModExpPrecompilePreEip2565(); + public static ModExpPrecompilePreEip2565 Instance = new ModExpPrecompilePreEip2565(); private ModExpPrecompilePreEip2565() { @@ -56,7 +57,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS } } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { Metrics.ModExpPrecompile++; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/PointEvaluationPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/PointEvaluationPrecompile.cs index 60734490d18b..4d63f51f2ea6 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/PointEvaluationPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/PointEvaluationPrecompile.cs @@ -8,12 +8,13 @@ using Nethermind.Core.Specs; using Nethermind.Crypto; using Nethermind.Int256; +using Nethermind.State; namespace Nethermind.Evm.Precompiles; -public class PointEvaluationPrecompile : IPrecompile +public class PointEvaluationPrecompile : IPrecompile { - public static readonly IPrecompile Instance = new PointEvaluationPrecompile(); + public static readonly PointEvaluationPrecompile Instance = new PointEvaluationPrecompile(); private static readonly ReadOnlyMemory PointEvaluationSuccessfulResponse = ((UInt256)Ckzg.Ckzg.FieldElementsPerBlob).ToBigEndian() @@ -26,7 +27,7 @@ public class PointEvaluationPrecompile : IPrecompile public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 0; - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { [SkipLocalsInit] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Ripemd160Precompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Ripemd160Precompile.cs index 8c357d917d18..ba899a59ce89 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Ripemd160Precompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Ripemd160Precompile.cs @@ -6,12 +6,13 @@ using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles { - public class Ripemd160Precompile : IPrecompile + public class Ripemd160Precompile : IPrecompile { - public static readonly IPrecompile Instance = new Ripemd160Precompile(); + public static readonly Ripemd160Precompile Instance = new Ripemd160Precompile(); // missing in .NET Core // private static RIPEMD160 _ripemd; @@ -35,7 +36,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return 120L * EvmPooledMemory.Div32Ceiling((ulong)inputData.Length); } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { Metrics.Ripemd160Precompile++; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Sha256Precompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Sha256Precompile.cs index fdb5dacf80bd..be0ed4d18090 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Sha256Precompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Sha256Precompile.cs @@ -6,14 +6,15 @@ using System.Threading; using Nethermind.Core; using Nethermind.Core.Specs; +using Nethermind.State; namespace Nethermind.Evm.Precompiles { - public class Sha256Precompile : IPrecompile + public class Sha256Precompile : IPrecompile { private static ThreadLocal _sha256 = new(); - public static readonly IPrecompile Instance = new Sha256Precompile(); + public static readonly Sha256Precompile Instance = new Sha256Precompile(); private Sha256Precompile() { @@ -42,7 +43,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return 12L * EvmPooledMemory.Div32Ceiling((ulong)inputData.Length); } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { Metrics.Sha256Precompile++; InitIfNeeded(); diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Snarks/Bn254AddPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Snarks/Bn254AddPrecompile.cs index 4ce9259c3d85..07c61793d3f5 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Snarks/Bn254AddPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Snarks/Bn254AddPrecompile.cs @@ -5,15 +5,16 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles.Snarks; /// /// https://github.com/matter-labs/eip1962/blob/master/eip196_header.h /// -public class Bn254AddPrecompile : IPrecompile +public class Bn254AddPrecompile : IPrecompile { - public static IPrecompile Instance = new Bn254AddPrecompile(); + public static Bn254AddPrecompile Instance = new Bn254AddPrecompile(); public static Address Address { get; } = Address.FromNumber(6); @@ -27,7 +28,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return 0L; } - public unsafe (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public unsafe (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { Metrics.Bn254AddPrecompile++; Span inputDataSpan = stackalloc byte[128]; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Snarks/Bn254MulPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Snarks/Bn254MulPrecompile.cs index 64659eb0bbb7..2450b8a6ec34 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Snarks/Bn254MulPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Snarks/Bn254MulPrecompile.cs @@ -5,15 +5,16 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles.Snarks; /// /// https://github.com/herumi/mcl/blob/master/api.md /// -public class Bn254MulPrecompile : IPrecompile +public class Bn254MulPrecompile : IPrecompile { - public static IPrecompile Instance = new Bn254MulPrecompile(); + public static Bn254MulPrecompile Instance = new Bn254MulPrecompile(); public static Address Address { get; } = Address.FromNumber(7); @@ -27,7 +28,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return 0L; } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { Metrics.Bn254MulPrecompile++; Span inputDataSpan = stackalloc byte[96]; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Snarks/Bn254PairingPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Snarks/Bn254PairingPrecompile.cs index 8cff25969d43..b0e107fb401c 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Snarks/Bn254PairingPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Snarks/Bn254PairingPrecompile.cs @@ -5,17 +5,18 @@ using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.State; namespace Nethermind.Evm.Precompiles.Snarks; /// /// https://github.com/herumi/mcl/blob/master/api.md /// -public class Bn254PairingPrecompile : IPrecompile +public class Bn254PairingPrecompile : IPrecompile { private const int PairSize = 192; - public static IPrecompile Instance = new Bn254PairingPrecompile(); + public static Bn254PairingPrecompile Instance = new Bn254PairingPrecompile(); public static Address Address { get; } = Address.FromNumber(8); @@ -29,7 +30,7 @@ public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseS return (releaseSpec.IsEip1108Enabled ? 34000L : 80000L) * (inputData.Length / PairSize); } - public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec, IWorldState? _ = null) { Metrics.Bn254PairingPrecompile++; diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index b0236578ddcd..86118e7dcdbe 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -671,7 +671,7 @@ private CallResult ExecutePrecompile(EvmState state, IReleaseSpec spec) try { - (ReadOnlyMemory output, bool success) = precompile.Run(callData, spec); + (ReadOnlyMemory output, bool success) = precompile.Run(callData, spec, _state); CallResult callResult = new(output.ToArray(), success, !success); return callResult; } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcBlockchain.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcBlockchain.cs index f1377527086b..5c3e29fe46c4 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcBlockchain.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcBlockchain.cs @@ -115,7 +115,7 @@ public async Task Build(ISpecProvider? specProvider = null, UInt256? initialV } } - protected override async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null) + protected override async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null, bool addBlockOnStart = true) { specProvider ??= new TestSpecProvider(Berlin.Instance); await base.Build(specProvider, initialValues); diff --git a/src/Nethermind/Nethermind.JsonRpc/JsonRpcService.cs b/src/Nethermind/Nethermind.JsonRpc/JsonRpcService.cs index 8a22f31c4037..0cba05fee8ea 100644 --- a/src/Nethermind/Nethermind.JsonRpc/JsonRpcService.cs +++ b/src/Nethermind/Nethermind.JsonRpc/JsonRpcService.cs @@ -328,7 +328,11 @@ private void LogRequest(string methodName, string?[] providedParameters, Paramet } else { - executionParam = _serializer.Deserialize(new JsonTextReader(new StringReader($"\"{providedParameter}\"")), paramType); + var stringReader = providedParameter.StartsWith('\"') && providedParameter.EndsWith('\"') + ? new StringReader(providedParameter) + : new StringReader($"\"{providedParameter}\""); + var jsonTextReader = new JsonTextReader(stringReader); + executionParam = _serializer.Deserialize(jsonTextReader, paramType); } } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/BlockForRpc.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/BlockForRpc.cs index b54b4c8336d1..e991e3fd6ac1 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/BlockForRpc.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/BlockForRpc.cs @@ -61,6 +61,11 @@ public BlockForRpc(Block block, bool includeFullTransactionData, ISpecProvider s BlobGasUsed = block.Header.BlobGasUsed; ExcessBlobGas = block.Header.ExcessBlobGas; } + + if (spec.IsEip4788Enabled) + { + ParentBeaconBlockRoot = block.ParentBeaconBlockRoot; + } } Number = block.Number; @@ -76,6 +81,7 @@ public BlockForRpc(Block block, bool includeFullTransactionData, ISpecProvider s Uncles = block.Uncles.Select(o => o.Hash); Withdrawals = block.Withdrawals; WithdrawalsRoot = block.Header.WithdrawalsRoot; + ParentBeaconBlockRoot = block.ParentBeaconBlockRoot; } public Address Author { get; set; } @@ -130,4 +136,7 @@ public BlockForRpc(Block block, bool includeFullTransactionData, ISpecProvider s [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public ulong? ExcessBlobGas { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public Keccak? ParentBeaconBlockRoot { get; set; } } diff --git a/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProducerEnvFactory.cs index a16c283a4ecd..fb91848e4ef9 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProducerEnvFactory.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProducerEnvFactory.cs @@ -87,8 +87,7 @@ protected override BlockProcessor CreateBlockProcessor( withdrawalContractFactory.Create(readOnlyTxProcessingEnv.TransactionProcessor), logManager ) - ) - ); + )); } protected override TxPoolTxSource CreateTxPoolTxSource( diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs index 3334788b008c..09b20cdd9604 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs @@ -20,6 +20,9 @@ using Nethermind.Specs; using Nethermind.Specs.Forks; using Nethermind.State; +using Nethermind.Core.Specs; +using Nethermind.Synchronization.Blocks; +using Nethermind.Consensus.BeaconBlockRoot; namespace Nethermind.Merge.Plugin.Test { @@ -27,8 +30,8 @@ namespace Nethermind.Merge.Plugin.Test public partial class EngineModuleTests { private static readonly DateTime Timestamp = DateTimeOffset.FromUnixTimeSeconds(1000).UtcDateTime; + private static readonly IBeaconBlockRootHandler _beaconBlockRootHandler = new BeaconBlockRootHandler(); private ITimestamper Timestamper { get; } = new ManualTimestamper(Timestamp); - private void AssertExecutionStatusChanged(IBlockFinder blockFinder, Keccak headBlockHash, Keccak finalizedBlockHash, Keccak safeBlockHash) { @@ -84,16 +87,26 @@ private ExecutionPayload CreateParentBlockRequestOnHead(IBlockTree blockTree) }; } - private static ExecutionPayload CreateBlockRequest(ExecutionPayload parent, Address miner, IList? withdrawals = null, - ulong? blobGasUsed = null, ulong? excessBlobGas = null, Transaction[]? transactions = null, Keccak? parentBeaconBlockRoot = null) - => CreateBlockRequestInternal(parent, miner, withdrawals, blobGasUsed, excessBlobGas, transactions: transactions, parentBeaconBlockRoot: parentBeaconBlockRoot); + private static ExecutionPayload CreateBlockRequest(IReleaseSpec spec, IWorldState state, ExecutionPayload parent, Address miner, IList? withdrawals = null, Transaction[]? transactions = null, Keccak? beaconParentBlockRoot = null) + => CreateBlockRequestInternal(spec, state, parent, miner, withdrawals, transactions: transactions, beaconParentBlockRoot: beaconParentBlockRoot); - private static ExecutionPayloadV3 CreateBlockRequestV3(ExecutionPayload parent, Address miner, IList? withdrawals = null, - ulong? blobGasUsed = null, ulong? excessBlobGas = null, Transaction[]? transactions = null, Keccak? parentBeaconBlockRoot = null) - => CreateBlockRequestInternal(parent, miner, withdrawals, blobGasUsed, excessBlobGas, transactions: transactions, parentBeaconBlockRoot: parentBeaconBlockRoot); + private static ExecutionPayloadV3 CreateBlockRequestV3(IReleaseSpec spec, IWorldState state, ExecutionPayload parent, Address miner, IList? withdrawals = null, ulong? blobGasUsed = null, ulong? excessBlobGas = null, Transaction[]? transactions = null, Keccak? beaconParentBlockRoot = null) + { + var blockRequestV3 = CreateBlockRequestInternal(spec, state, parent, miner, withdrawals, blobGasUsed, excessBlobGas, transactions: transactions, beaconParentBlockRoot: beaconParentBlockRoot); + blockRequestV3.TryGetBlock(out Block? block); + _beaconBlockRootHandler.UpdateState(block!, spec, state); + + state.Commit(spec); + state.CommitTree(blockRequestV3.BlockNumber); + + state.RecalculateStateRoot(); + blockRequestV3.StateRoot = state.StateRoot; + TryCalculateHash(blockRequestV3, out Keccak? hash); + blockRequestV3.BlockHash = hash; + return blockRequestV3; + } - private static T CreateBlockRequestInternal(ExecutionPayload parent, Address miner, IList? withdrawals = null, - ulong? blobGasUsed = null, ulong? excessBlobGas = null, Transaction[]? transactions = null, Keccak? parentBeaconBlockRoot = null) where T : ExecutionPayload, new() + private static T CreateBlockRequestInternal(IReleaseSpec spec, IWorldState state, ExecutionPayload parent, Address miner, IList? withdrawals = null, ulong? blobGasUsed = null, ulong? excessBlobGas = null, Transaction[]? transactions = null, Keccak? beaconParentBlockRoot = null) where T : ExecutionPayload, new() { T blockRequest = new() { @@ -107,24 +120,28 @@ private static T CreateBlockRequestInternal(ExecutionPayload parent, Address LogsBloom = Bloom.Empty, Timestamp = parent.Timestamp + 1, Withdrawals = withdrawals, - BlobGasUsed = blobGasUsed, - ExcessBlobGas = excessBlobGas, - ParentBeaconBlockRoot = parentBeaconBlockRoot, }; + if (blockRequest is ExecutionPayloadV3 blockRequestV3) + { + blockRequestV3.ParentBeaconBlockRoot = beaconParentBlockRoot; + blockRequestV3.BlobGasUsed = blobGasUsed; + blockRequestV3.ExcessBlobGas = excessBlobGas; + } + blockRequest.SetTransactions(transactions ?? Array.Empty()); TryCalculateHash(blockRequest, out Keccak? hash); blockRequest.BlockHash = hash; return blockRequest; } - private static ExecutionPayload[] CreateBlockRequestBranch(ExecutionPayload parent, Address miner, int count) + private static ExecutionPayload[] CreateBlockRequestBranch(IReleaseSpec spec, IWorldState state, ExecutionPayload parent, Address miner, int count) { ExecutionPayload currentBlock = parent; ExecutionPayload[] blockRequests = new ExecutionPayload[count]; for (int i = 0; i < count; i++) { - currentBlock = CreateBlockRequest(currentBlock, miner); + currentBlock = CreateBlockRequest(spec, state, currentBlock, miner); blockRequests[i] = currentBlock; } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs index f7dc238563b6..abe7a3f24e62 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs @@ -246,7 +246,7 @@ private IBlockValidator CreateBlockValidator() public IManualBlockFinalizationManager BlockFinalizationManager { get; } = new ManualBlockFinalizationManager(); - protected override async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null) + protected override async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null, bool addBlockOnStart = true) { TestBlockchain chain = await base.Build(specProvider, initialValues); return chain; diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs index 256557f1d8b0..a97fbc04bbf2 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs @@ -204,14 +204,14 @@ public async Task should_return_invalid_lvh_null_on_invalid_blocks_during_the_sy forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should() .Be(nameof(PayloadStatusV1.Syncing).ToUpper()); - ExecutionPayload[] requests = CreateBlockRequestBranch(startingNewPayload, TestItem.AddressD, 1); + ExecutionPayload[] requests = CreateBlockRequestBranch(chain.SpecProvider.GenesisSpec, chain.State, startingNewPayload, TestItem.AddressD, 1); foreach (ExecutionPayload r in requests) { ResultWrapper payloadStatus = await rpc.engine_newPayloadV1(r); payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Syncing).ToUpper()); } - ExecutionPayload[] invalidRequests = CreateBlockRequestBranch(requests[0], TestItem.AddressD, 1); + ExecutionPayload[] invalidRequests = CreateBlockRequestBranch(chain.SpecProvider.GenesisSpec, chain.State, requests[0], TestItem.AddressD, 1); foreach (ExecutionPayload r in invalidRequests) { r.TryGetBlock(out Block? newBlock); @@ -231,7 +231,7 @@ public async Task newPayloadV1_can_insert_blocks_from_cache_when_syncing() Keccak startingHead = chain.BlockTree.HeadHash; ExecutionPayload parentBlockRequest = new(Build.A.Block.WithNumber(2).TestObject); - ExecutionPayload[] requests = CreateBlockRequestBranch(parentBlockRequest, Address.Zero, 7); + ExecutionPayload[] requests = CreateBlockRequestBranch(chain.SpecProvider.GenesisSpec, chain.State, parentBlockRequest, Address.Zero, 7); ResultWrapper payloadStatus; foreach (ExecutionPayload r in requests) { @@ -295,7 +295,7 @@ public async Task first_new_payload_set_beacon_main_chain() await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1); forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should() .Be(nameof(PayloadStatusV1.Syncing).ToUpper()); - ExecutionPayload[] requests = CreateBlockRequestBranch(startingNewPayload, Address.Zero, 4); + ExecutionPayload[] requests = CreateBlockRequestBranch(chain.SpecProvider.GenesisSpec, chain.State, startingNewPayload, Address.Zero, 4); foreach (ExecutionPayload r in requests) { ResultWrapper payloadStatus = await rpc.engine_newPayloadV1(r); @@ -336,7 +336,7 @@ public async Task repeated_new_payloads_do_not_change_metadata() await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1); forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should() .Be(nameof(PayloadStatusV1.Syncing).ToUpper()); - ExecutionPayload[] requests = CreateBlockRequestBranch(startingNewPayload, Address.Zero, 4); + ExecutionPayload[] requests = CreateBlockRequestBranch(chain.SpecProvider.GenesisSpec, chain.State, startingNewPayload, Address.Zero, 4); foreach (ExecutionPayload r in requests) { ResultWrapper payloadStatus = await rpc.engine_newPayloadV1(r); @@ -494,7 +494,7 @@ public async Task second_new_payload_should_not_set_beacon_main_chain() await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1); forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should() .Be(nameof(PayloadStatusV1.Syncing).ToUpper()); - ExecutionPayload[] requests = CreateBlockRequestBranch(startingNewPayload, Address.Zero, 4); + ExecutionPayload[] requests = CreateBlockRequestBranch(chain.SpecProvider.GenesisSpec, chain.State, startingNewPayload, Address.Zero, 4); foreach (ExecutionPayload r in requests) { ResultWrapper payloadStatus = await rpc.engine_newPayloadV1(r); @@ -505,7 +505,7 @@ public async Task second_new_payload_should_not_set_beacon_main_chain() lvl!.BlockInfos[0].Metadata.Should().Be(BlockMetadata.BeaconBody | BlockMetadata.BeaconHeader | BlockMetadata.BeaconMainChain); } - ExecutionPayload[] secondNewPayloads = CreateBlockRequestBranch(startingNewPayload, TestItem.AddressD, 4); + ExecutionPayload[] secondNewPayloads = CreateBlockRequestBranch(chain.SpecProvider.GenesisSpec, chain.State, startingNewPayload, TestItem.AddressD, 4); foreach (ExecutionPayload r in secondNewPayloads) { ResultWrapper payloadStatus = await rpc.engine_newPayloadV1(r); @@ -551,13 +551,13 @@ public async Task should_reorg_during_the_sync(int initialChainPayloadsCount, in await rpc.engine_newPayloadV1(startingNewPayload); ForkchoiceStateV1 forkchoiceStateV1 = new(block.Hash!, startingHead, startingHead); await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1); - ExecutionPayload[] initialBranchPayloads = CreateBlockRequestBranch(startingNewPayload, Address.Zero, initialChainPayloadsCount); + ExecutionPayload[] initialBranchPayloads = CreateBlockRequestBranch(chain.SpecProvider.GenesisSpec, chain.State, startingNewPayload, Address.Zero, initialChainPayloadsCount); foreach (ExecutionPayload r in initialBranchPayloads) { await rpc.engine_newPayloadV1(r); } - ExecutionPayload[] newBranchPayloads = CreateBlockRequestBranch(startingNewPayload, TestItem.AddressD, reorgedChainPayloadCount); + ExecutionPayload[] newBranchPayloads = CreateBlockRequestBranch(chain.SpecProvider.GenesisSpec, chain.State, startingNewPayload, TestItem.AddressD, reorgedChainPayloadCount); foreach (ExecutionPayload r in newBranchPayloads) { await rpc.engine_newPayloadV1(r); @@ -588,7 +588,7 @@ public async Task Blocks_from_cache_inserted_when_fast_headers_sync_finish_befor using MergeTestBlockchain chain = await CreateBlockchain(); Keccak startingHead = chain.BlockTree.HeadHash; IEngineRpcModule rpc = CreateEngineModule(chain); - ExecutionPayload[] requests = CreateBlockRequestBranch(new ExecutionPayload(chain.BlockTree.Head!), Address.Zero, 7); + ExecutionPayload[] requests = CreateBlockRequestBranch(chain.SpecProvider.GenesisSpec, chain.State, new ExecutionPayload(chain.BlockTree.Head!), Address.Zero, 7); ResultWrapper payloadStatus; for (int i = 4; i < requests.Length - 1; i++) @@ -640,13 +640,13 @@ public async Task Maintain_correct_pointers_for_beacon_sync_in_archive_sync() Block[] missingBlocks = new Block[gap]; for (int i = 0; i < gap; i++) { - headBlockRequest = CreateBlockRequest(headBlockRequest, Address.Zero); + headBlockRequest = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, headBlockRequest, Address.Zero); headBlockRequest.TryGetBlock(out Block? block); missingBlocks[i] = block!; } // setting up beacon pivot - ExecutionPayload pivotRequest = CreateBlockRequest(headBlockRequest, Address.Zero); + ExecutionPayload pivotRequest = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, headBlockRequest, Address.Zero); ResultWrapper payloadStatus = await rpc.engine_newPayloadV1(pivotRequest); payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Syncing).ToUpper()); pivotRequest.TryGetBlock(out Block? pivotBlock); @@ -668,7 +668,7 @@ public async Task Maintain_correct_pointers_for_beacon_sync_in_archive_sync() forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should() .Be(nameof(PayloadStatusV1.Syncing).ToUpper()); // trigger insertion of blocks in cache into block tree by adding new block - ExecutionPayload bestBeaconBlockRequest = CreateBlockRequest(pivotRequest, Address.Zero); + ExecutionPayload bestBeaconBlockRequest = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, pivotRequest, Address.Zero); payloadStatus = await rpc.engine_newPayloadV1(bestBeaconBlockRequest); payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Syncing).ToUpper()); // simulate headers sync by inserting 3 headers from pivot backwards @@ -722,7 +722,7 @@ public async Task Maintain_correct_pointers_for_beacon_sync_in_archive_sync() await bestBlockProcessed.WaitAsync(); // beacon sync should be finished, eventually - bestBeaconBlockRequest = CreateBlockRequest(bestBeaconBlockRequest, Address.Zero); + bestBeaconBlockRequest = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, bestBeaconBlockRequest, Address.Zero); Assert.That( () => rpc.engine_newPayloadV1(bestBeaconBlockRequest).Result.Data.Status, Is.EqualTo(PayloadStatus.Valid).After(1000, 100) @@ -798,9 +798,9 @@ public async Task Maintain_correct_pointers_for_beacon_sync_in_fast_sync() // create block gap from fast sync pivot int gap = 7; ExecutionPayload[] requests = - CreateBlockRequestBranch(new ExecutionPayload(syncedBlockTree.Head!), Address.Zero, gap); + CreateBlockRequestBranch(chain.SpecProvider.GenesisSpec, chain.State, new ExecutionPayload(syncedBlockTree.Head!), Address.Zero, gap); // setting up beacon pivot - ExecutionPayload pivotRequest = CreateBlockRequest(requests[^1], Address.Zero); + ExecutionPayload pivotRequest = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, requests[^1], Address.Zero); ResultWrapper payloadStatus = await rpc.engine_newPayloadV1(pivotRequest); payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Syncing).ToUpper()); pivotRequest.TryGetBlock(out Block? pivotBlock); @@ -823,7 +823,7 @@ public async Task Maintain_correct_pointers_for_beacon_sync_in_fast_sync() forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should() .Be(nameof(PayloadStatusV1.Syncing).ToUpper()); // trigger insertion of blocks in cache into block tree by adding new block - ExecutionPayload bestBeaconBlockRequest = CreateBlockRequest(pivotRequest, Address.Zero); + ExecutionPayload bestBeaconBlockRequest = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, pivotRequest, Address.Zero); payloadStatus = await rpc.engine_newPayloadV1(bestBeaconBlockRequest); payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Syncing).ToUpper()); // fill in beacon headers until fast headers pivot @@ -857,12 +857,12 @@ public async Task Invalid_block_can_create_invalid_best_state_issue_but_recalcul chain.BlockTree.HeadHash.Should().Be(lastHash); // send newPayload - ExecutionPayload validBlockOnTopOfHead = CreateBlockRequest(CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); + ExecutionPayload validBlockOnTopOfHead = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); PayloadStatusV1 payloadStatusResponse = (await rpc.engine_newPayloadV1(validBlockOnTopOfHead)).Data; payloadStatusResponse.Status.Should().Be(PayloadStatus.Valid); // send block with invalid state root - ExecutionPayload blockWithInvalidStateRoot = CreateBlockRequest(validBlockOnTopOfHead, TestItem.AddressA); + ExecutionPayload blockWithInvalidStateRoot = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, validBlockOnTopOfHead, TestItem.AddressA); blockWithInvalidStateRoot.StateRoot = TestItem.KeccakB; TryCalculateHash(blockWithInvalidStateRoot, out Keccak? hash); blockWithInvalidStateRoot.BlockHash = hash; @@ -894,12 +894,12 @@ public async Task MultiSyncModeSelector_should_fix_block_tree_levels_if_needed() chain.BlockTree.HeadHash.Should().Be(lastHash); // send newPayload - ExecutionPayload validBlockOnTopOfHead = CreateBlockRequest(CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); + ExecutionPayload validBlockOnTopOfHead = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); PayloadStatusV1 payloadStatusResponse = (await rpc.engine_newPayloadV1(validBlockOnTopOfHead)).Data; payloadStatusResponse.Status.Should().Be(PayloadStatus.Valid); // send block with invalid state root - ExecutionPayload blockWithInvalidStateRoot = CreateBlockRequest(validBlockOnTopOfHead, TestItem.AddressA); + ExecutionPayload blockWithInvalidStateRoot = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, validBlockOnTopOfHead, TestItem.AddressA); blockWithInvalidStateRoot.StateRoot = TestItem.KeccakB; TryCalculateHash(blockWithInvalidStateRoot, out Keccak? hash); blockWithInvalidStateRoot.BlockHash = hash; diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs index 6be6c4e6bf23..878cd9a4665c 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs @@ -450,7 +450,7 @@ public async Task executePayloadV1_result_is_fail_when_blockchainprocessor_repor ((TestBlockProcessorInterceptor)chain.BlockProcessor).ExceptionToThrow = new Exception("unxpected exception"); - ExecutionPayload executionPayload = CreateBlockRequest(CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); + ExecutionPayload executionPayload = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(executionPayload); resultWrapper.Result.ResultType.Should().Be(ResultType.Failure); } @@ -786,7 +786,7 @@ public async Task executePayloadV1_should_not_accept_blocks_with_incorrect_ttd(l TerminalTotalDifficulty = $"{terminalTotalDifficulty}" }); IEngineRpcModule rpc = CreateEngineModule(chain); - ExecutionPayload executionPayload = CreateBlockRequest(CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); + ExecutionPayload executionPayload = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(executionPayload); resultWrapper.Data.Status.Should().Be(PayloadStatus.Invalid); resultWrapper.Data.LatestValidHash.Should().Be(Keccak.Zero); @@ -903,7 +903,7 @@ public async Task executePayloadV1_accepts_first_block() { using MergeTestBlockchain chain = await CreateBlockchain(); IEngineRpcModule rpc = CreateEngineModule(chain); - ExecutionPayload executionPayload = CreateBlockRequest(CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); + ExecutionPayload executionPayload = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(executionPayload); resultWrapper.Data.Status.Should().Be(PayloadStatus.Valid); new ExecutionPayload(chain.BlockTree.BestSuggestedBody!).Should().BeEquivalentTo(executionPayload); @@ -915,6 +915,7 @@ public async Task executePayloadV1_calculate_hash_for_cached_blocks() using MergeTestBlockchain chain = await CreateBlockchain(); IEngineRpcModule rpc = CreateEngineModule(chain); ExecutionPayload executionPayload = CreateBlockRequest( + chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(executionPayload); @@ -1000,7 +1001,7 @@ public async Task newPayloadV1_should_return_accepted_for_side_branch() { using MergeTestBlockchain chain = await CreateBlockchain(); IEngineRpcModule rpc = CreateEngineModule(chain); - ExecutionPayload executionPayload = CreateBlockRequest(CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); + ExecutionPayload executionPayload = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(executionPayload); resultWrapper.Data.Status.Should().Be(PayloadStatus.Valid); ForkchoiceStateV1 forkChoiceUpdatedRequest = new(executionPayload.BlockHash, executionPayload.BlockHash, executionPayload.BlockHash); @@ -1025,7 +1026,7 @@ public async Task executePayloadV1_processes_passed_transactions(bool moveHead) foreach (ExecutionPayload block in branch) { uint count = 10; - ExecutionPayload executePayloadRequest = CreateBlockRequest(block, TestItem.AddressA); + ExecutionPayload executePayloadRequest = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, block, TestItem.AddressA); PrivateKey from = TestItem.PrivateKeyB; Address to = TestItem.AddressD; (_, UInt256 toBalanceAfter) = AddTransactions(chain, executePayloadRequest, from, to, count, 1, out BlockHeader? parentHeader); @@ -1062,7 +1063,7 @@ public async Task executePayloadV1_transactions_produce_receipts() foreach (ExecutionPayload block in branch) { uint count = 10; - ExecutionPayload executionPayload = CreateBlockRequest(block, TestItem.AddressA); + ExecutionPayload executionPayload = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, block, TestItem.AddressA); PrivateKey from = TestItem.PrivateKeyB; Address to = TestItem.AddressD; (_, UInt256 toBalanceAfter) = AddTransactions(chain, executionPayload, from, to, count, 1, out BlockHeader parentHeader); @@ -1215,6 +1216,7 @@ public async Task exchangeTransitionConfiguration_return_with_empty_Nethermind_c private async Task SendNewBlockV1(IEngineRpcModule rpc, MergeTestBlockchain chain) { ExecutionPayload executionPayload = CreateBlockRequest( + chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); ResultWrapper executePayloadResult = @@ -1262,6 +1264,7 @@ public async Task repeat_the_same_payload_after_fcu_should_return_valid_and_be_i // Correct new payload ExecutionPayload executionPayloadV11 = CreateBlockRequest( + chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressA); ResultWrapper newPayloadResult1 = await rpc.engine_newPayloadV1(executionPayloadV11); @@ -1289,6 +1292,7 @@ public async Task payloadV1_invalid_parent_hash() // Correct new payload ExecutionPayload executionPayloadV11 = CreateBlockRequest( + chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressA); ResultWrapper newPayloadResult1 = await rpc.engine_newPayloadV1(executionPayloadV11); @@ -1301,7 +1305,7 @@ public async Task payloadV1_invalid_parent_hash() forkchoiceUpdatedResult1.Data.PayloadStatus.Status.Should().Be(PayloadStatus.Valid); // New payload unknown parent hash - ExecutionPayload executionPayloadV12A = CreateBlockRequest(executionPayloadV11, TestItem.AddressA); + ExecutionPayload executionPayloadV12A = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, executionPayloadV11, TestItem.AddressA); executionPayloadV12A.ParentHash = TestItem.KeccakB; TryCalculateHash(executionPayloadV12A, out Keccak? hash); executionPayloadV12A.BlockHash = hash; @@ -1316,7 +1320,7 @@ public async Task payloadV1_invalid_parent_hash() forkchoiceUpdatedResult2A.Data.PayloadStatus.Status.Should().Be(PayloadStatus.Syncing); // New payload with correct parent hash - ExecutionPayload executionPayloadV12B = CreateBlockRequest(executionPayloadV11, TestItem.AddressA); + ExecutionPayload executionPayloadV12B = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, executionPayloadV11, TestItem.AddressA); ResultWrapper newPayloadResult2B = await rpc.engine_newPayloadV1(executionPayloadV12B); newPayloadResult2B.Data.Status.Should().Be(PayloadStatus.Valid); @@ -1327,7 +1331,7 @@ public async Task payloadV1_invalid_parent_hash() forkchoiceUpdatedResult2B.Data.PayloadStatus.Status.Should().Be(PayloadStatus.Valid); // New payload unknown parent hash - ExecutionPayload executionPayloadV13A = CreateBlockRequest(executionPayloadV12A, TestItem.AddressA); + ExecutionPayload executionPayloadV13A = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, executionPayloadV12A, TestItem.AddressA); ResultWrapper newPayloadResult3A = await rpc.engine_newPayloadV1(executionPayloadV13A); newPayloadResult3A.Data.Status.Should().Be(PayloadStatus.Syncing); @@ -1338,7 +1342,7 @@ public async Task payloadV1_invalid_parent_hash() ResultWrapper forkchoiceUpdatedResult3A = await rpc.engine_forkchoiceUpdatedV1(forkChoiceState3A); forkchoiceUpdatedResult3A.Data.PayloadStatus.Status.Should().Be(PayloadStatus.Syncing); - ExecutionPayload executionPayloadV13B = CreateBlockRequest(executionPayloadV12B, TestItem.AddressA); + ExecutionPayload executionPayloadV13B = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, executionPayloadV12B, TestItem.AddressA); ResultWrapper newPayloadResult3B = await rpc.engine_newPayloadV1(executionPayloadV13B); newPayloadResult3B.Data.Status.Should().Be(PayloadStatus.Valid); @@ -1357,6 +1361,7 @@ public async Task inconsistent_finalized_hash() IEngineRpcModule rpc = CreateEngineModule(chain); ExecutionPayload blockRequestResult1 = CreateBlockRequest( + chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressA); ResultWrapper newPayloadResult1 = await rpc.engine_newPayloadV1(blockRequestResult1); @@ -1367,15 +1372,15 @@ public async Task inconsistent_finalized_hash() ResultWrapper forkchoiceUpdatedResult1 = await rpc.engine_forkchoiceUpdatedV1(forkChoiceState1); forkchoiceUpdatedResult1.Data.PayloadStatus.Status.Should().Be(PayloadStatus.Valid); - ExecutionPayload blockRequestResult2A = CreateBlockRequest(blockRequestResult1, TestItem.AddressB); + ExecutionPayload blockRequestResult2A = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, blockRequestResult1, TestItem.AddressB); ResultWrapper newPayloadResult2A = await rpc.engine_newPayloadV1(blockRequestResult2A); newPayloadResult2A.Data.Status.Should().Be(PayloadStatus.Valid); - ExecutionPayload blockRequestResult2B = CreateBlockRequest(blockRequestResult1, TestItem.AddressA); + ExecutionPayload blockRequestResult2B = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, blockRequestResult1, TestItem.AddressA); ResultWrapper newPayloadResult2B = await rpc.engine_newPayloadV1(blockRequestResult2B); newPayloadResult2B.Data.Status.Should().Be(PayloadStatus.Valid); - ExecutionPayload blockRequestResult3B = CreateBlockRequest(blockRequestResult2B, TestItem.AddressA); + ExecutionPayload blockRequestResult3B = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, blockRequestResult2B, TestItem.AddressA); ResultWrapper newPayloadResult3B = await rpc.engine_newPayloadV1(blockRequestResult3B); newPayloadResult3B.Data.Status.Should().Be(PayloadStatus.Valid); @@ -1393,6 +1398,7 @@ public async Task inconsistent_safe_hash() IEngineRpcModule rpc = CreateEngineModule(chain); ExecutionPayload blockRequestResult1 = CreateBlockRequest( + chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressA); ResultWrapper newPayloadResult1 = await rpc.engine_newPayloadV1(blockRequestResult1); @@ -1403,15 +1409,15 @@ public async Task inconsistent_safe_hash() ResultWrapper forkchoiceUpdatedResult1 = await rpc.engine_forkchoiceUpdatedV1(forkChoiceState1); forkchoiceUpdatedResult1.Data.PayloadStatus.Status.Should().Be(PayloadStatus.Valid); - ExecutionPayload blockRequestResult2A = CreateBlockRequest(blockRequestResult1, TestItem.AddressB); + ExecutionPayload blockRequestResult2A = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, blockRequestResult1, TestItem.AddressB); ResultWrapper newPayloadResult2A = await rpc.engine_newPayloadV1(blockRequestResult2A); newPayloadResult2A.Data.Status.Should().Be(PayloadStatus.Valid); - ExecutionPayload blockRequestResult2B = CreateBlockRequest(blockRequestResult1, TestItem.AddressA); + ExecutionPayload blockRequestResult2B = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, blockRequestResult1, TestItem.AddressA); ResultWrapper newPayloadResult2B = await rpc.engine_newPayloadV1(blockRequestResult2B); newPayloadResult2B.Data.Status.Should().Be(PayloadStatus.Valid); - ExecutionPayload blockRequestResult3B = CreateBlockRequest(blockRequestResult2B, TestItem.AddressA); + ExecutionPayload blockRequestResult3B = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, blockRequestResult2B, TestItem.AddressA); ResultWrapper newPayloadResult3B = await rpc.engine_newPayloadV1(blockRequestResult3B); newPayloadResult3B.Data.Status.Should().Be(PayloadStatus.Valid); @@ -1449,6 +1455,7 @@ await rpc.engine_forkchoiceUpdatedV1(forkChoiceStateGen, // Add one block ExecutionPayload executionPayloadV11 = CreateBlockRequest( + chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressA); executionPayloadV11.PrevRandao = prevRandao1; @@ -1474,6 +1481,7 @@ await rpc.engine_forkchoiceUpdatedV1(forkChoiceState1, { ExecutionPayload executionPayloadV12 = CreateBlockRequest( + chain.SpecProvider.GenesisSpec, chain.State, executionPayloadV11, TestItem.AddressA); @@ -1498,6 +1506,7 @@ await rpc.engine_forkchoiceUpdatedV1(forkChoiceState1, // re-org { ExecutionPayload executionPayloadV13 = CreateBlockRequest( + chain.SpecProvider.GenesisSpec, chain.State, executionPayloadV11, TestItem.AddressA); diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V2.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V2.cs index 2c81e1457d41..73804c4690b4 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V2.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V2.cs @@ -638,7 +638,7 @@ public async Task executePayloadV2_works_correctly_when_0_withdrawals_applied(( { using MergeTestBlockchain chain = await CreateBlockchain(input.ReleaseSpec); IEngineRpcModule rpc = CreateEngineModule(chain); - ExecutionPayload executionPayload = CreateBlockRequest(CreateParentBlockRequestOnHead(chain.BlockTree), + ExecutionPayload executionPayload = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD, input.Withdrawals); ResultWrapper resultWrapper = await rpc.engine_newPayloadV2(executionPayload); @@ -707,7 +707,7 @@ public virtual async Task Should_handle_withdrawals_transition_when_Shanghai_for // Block without withdrawals, Timestamp = 2 ExecutionPayload executionPayload = - CreateBlockRequest(CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); + CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); ResultWrapper resultWrapper = await rpc.engine_newPayloadV2(executionPayload); resultWrapper.Data.Status.Should().Be(PayloadStatus.Valid); @@ -873,7 +873,7 @@ private async Task BuildAndSendNewBlockV2( private async Task SendNewBlockV2(IEngineRpcModule rpc, MergeTestBlockchain chain, IList? withdrawals) { - ExecutionPayload executionPayload = CreateBlockRequest( + ExecutionPayload executionPayload = CreateBlockRequest(chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD, withdrawals); ResultWrapper executePayloadResult = await rpc.engine_newPayloadV2(executionPayload); diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V3.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V3.cs index cd3f764c2457..0f74759b8698 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V3.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V3.cs @@ -8,6 +8,8 @@ using System.Threading; using System.Threading.Tasks; using FluentAssertions; +using k8s; +using Nethermind.Consensus; using Nethermind.Consensus.Producers; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -40,6 +42,7 @@ public async Task NewPayloadV1_should_decline_post_cancun() MergeTestBlockchain chain = await CreateBlockchain(releaseSpec: Cancun.Instance); IEngineRpcModule rpcModule = CreateEngineModule(chain); ExecutionPayload executionPayload = CreateBlockRequest( + chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD, withdrawals: Array.Empty()); ResultWrapper result = await rpcModule.engine_newPayloadV1(executionPayload); @@ -53,6 +56,7 @@ public async Task NewPayloadV2_should_decline_post_cancun() MergeTestBlockchain chain = await CreateBlockchain(releaseSpec: Cancun.Instance); IEngineRpcModule rpcModule = CreateEngineModule(chain); ExecutionPayload executionPayload = CreateBlockRequest( + chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD, withdrawals: Array.Empty()); ResultWrapper result = await rpcModule.engine_newPayloadV2(executionPayload); @@ -66,8 +70,8 @@ public async Task NewPayloadV2_should_decline_pre_cancun_with_cancun_fields MergeTestBlockchain chain = await CreateBlockchain(releaseSpec: Shanghai.Instance); IEngineRpcModule rpcModule = CreateEngineModule(chain); ExecutionPayload executionPayload = CreateBlockRequest( - CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD, withdrawals: Array.Empty(), - blobGasUsed: blobGasUsed, excessBlobGas: excessBlobGas, parentBeaconBlockRoot: parentBlockBeaconRoot); + chain.SpecProvider.GenesisSpec, chain.State, + CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD, withdrawals: Array.Empty(), beaconParentBlockRoot: parentBlockBeaconRoot); ResultWrapper result = await rpcModule.engine_newPayloadV2(executionPayload); @@ -80,9 +84,10 @@ public async Task NewPayloadV3_should_decline_pre_cancun_payloads() MergeTestBlockchain chain = await CreateBlockchain(releaseSpec: Shanghai.Instance); IEngineRpcModule rpcModule = CreateEngineModule(chain); ExecutionPayloadV3 executionPayload = CreateBlockRequestV3( + chain.SpecProvider.GenesisSpec, chain.State, CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD, withdrawals: Array.Empty()); - ResultWrapper result = await rpcModule.engine_newPayloadV3(executionPayload, new byte[0][]); + ResultWrapper result = await rpcModule.engine_newPayloadV3(executionPayload, new byte[0][], executionPayload.ParentBeaconBlockRoot?.BytesToArray()); Assert.That(result.ErrorCode, Is.EqualTo(ErrorCodes.UnsupportedFork)); } @@ -121,6 +126,31 @@ public async Task GetPayloadV3_should_fail_on_unknown_payload() responseFirst.ErrorCode.Should().Be(MergeErrorCodes.UnknownPayload); } + [TestCase(1, true)] + [TestCase(2, true)] + [TestCase(3, false)] + public async Task ForkchoiceUpdatedV3_should_fail_on_wrong_payloadVersion(int version, bool shoudlFail) + { + using SemaphoreSlim blockImprovementLock = new(0); + using MergeTestBlockchain chain = await CreateBlockchain(Cancun.Instance); + IEngineRpcModule rpc = CreateEngineModule(chain); + + Keccak currentHeadHash = chain.BlockTree.HeadHash; + ForkchoiceStateV1 forkchoiceState = new(currentHeadHash, currentHeadHash, currentHeadHash); + PayloadAttributes payloadAttributes = new() + { + Timestamp = chain.BlockTree.Head!.Timestamp + 1, + PrevRandao = TestItem.KeccakH, + SuggestedFeeRecipient = TestItem.AddressF, + Withdrawals = version >= EngineApiVersions.Shanghai ? new List { TestItem.WithdrawalA_1Eth } : null, + ParentBeaconBlockRoot = version >= EngineApiVersions.Cancun ? TestItem.KeccakE : null + }; + + ResultWrapper responseFirst = await rpc.engine_forkchoiceUpdatedV3(forkchoiceState, payloadAttributes); + responseFirst.Should().NotBeNull(); + responseFirst.Result.ResultType.Should().Be(shoudlFail ? ResultType.Failure : ResultType.Success); + } + [TestCase(0)] [TestCase(1)] [TestCase(2)] @@ -137,6 +167,21 @@ public async Task GetPayloadV3_should_return_all_the_blobs(int blobTxCount) Assert.That(getPayloadResultBlobsBundle.Proofs!.Length, Is.EqualTo(blobTxCount)); } + [TestCase(true, PayloadStatus.Valid)] + [TestCase(false, PayloadStatus.Invalid)] + public virtual async Task NewPayloadV3_should_fail_on_null_parentBeaconBlockHash(bool includeParentBeaconBlockRoot, string expectedPayloadStatus) + { + (IEngineRpcModule rpcModule, string payloadId, Transaction[] transactions) = await BuildAndGetPayloadV3Result(Cancun.Instance, 1); + + ExecutionPayloadV3 payload = (await rpcModule.engine_getPayloadV3(Bytes.FromHexString(payloadId))).Data!.ExecutionPayload; + + byte[]?[] blobVersionedHashes = transactions.SelectMany(tx => tx.BlobVersionedHashes ?? Array.Empty()).ToArray(); + ResultWrapper result = await rpcModule.engine_newPayloadV3(payload, blobVersionedHashes, includeParentBeaconBlockRoot ? payload.ParentBeaconBlockRoot.BytesToArray() : null); + + Assert.That(result.ErrorCode, Is.EqualTo(ErrorCodes.None)); + result.Data.Status.Should().Be(expectedPayloadStatus); + } + [TestCase(false, PayloadStatus.Valid)] [TestCase(true, PayloadStatus.Invalid)] public virtual async Task NewPayloadV3_should_decline_mempool_encoding(bool inMempoolForm, string expectedPayloadStatus) @@ -150,7 +195,7 @@ public virtual async Task NewPayloadV3_should_decline_mempool_encoding(bool inMe payload.Transactions = transactions.Select(tx => rlpEncoder.Encode(tx, rlpBehaviors).Bytes).ToArray(); byte[]?[] blobVersionedHashes = transactions.SelectMany(tx => tx.BlobVersionedHashes ?? Array.Empty()).ToArray(); - ResultWrapper result = await rpcModule.engine_newPayloadV3(payload, blobVersionedHashes); + ResultWrapper result = await rpcModule.engine_newPayloadV3(payload, blobVersionedHashes, payload.ParentBeaconBlockRoot.BytesToArray()); Assert.That(result.ErrorCode, Is.EqualTo(ErrorCodes.None)); result.Data.Status.Should().Be(expectedPayloadStatus); @@ -183,7 +228,8 @@ public async Task NewPayloadV3_should_decline_null_blobversionedhashes() moduleProvider.Register(new SingletonModulePool(new SingletonFactory(rpcModule), true)); ExecutionPayloadV3 executionPayload = CreateBlockRequestV3( - CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD, withdrawals: Array.Empty(), blobGasUsed: 0, excessBlobGas: 0); + chain.SpecProvider.GenesisSpec, chain.State, + CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD, withdrawals: Array.Empty(), blobGasUsed: 0, excessBlobGas: 0, beaconParentBlockRoot: TestItem.KeccakA); return (new(moduleProvider, LimboLogs.Instance, jsonRpcConfig), new(RpcEndpoint.Http), new(), executionPayload); } @@ -196,11 +242,12 @@ public async Task NewPayloadV3_should_decline_empty_fields() string executionPayloadString = serializer.Serialize(executionPayload); string blobsString = serializer.Serialize(Array.Empty()); + string parentBeaconBlockRootString = serializer.Serialize(TestItem.KeccakA.BytesToArray()); { JObject executionPayloadAsJObject = serializer.Deserialize(executionPayloadString); JsonRpcRequest request = RpcTest.GetJsonRequest(nameof(IEngineRpcModule.engine_newPayloadV3), - serializer.Serialize(executionPayloadAsJObject), blobsString); + serializer.Serialize(executionPayloadAsJObject), blobsString, parentBeaconBlockRootString); JsonRpcResponse response = await jsonRpcService.SendRequestAsync(request, context); Assert.That(response is JsonRpcSuccessResponse); } @@ -314,8 +361,9 @@ public async Task NewPayloadV3_should_verify_blob_versioned_hashes_again (byte[][] blobVersionedHashes, Transaction[] transactions) = BuildTransactionsAndBlobVersionedHashesList(hashesFirstBytes, transactionsAndFirstBytesOfTheirHashes, blockchain.SpecProvider.ChainId); ExecutionPayloadV3 executionPayload = CreateBlockRequestV3( - CreateParentBlockRequestOnHead(blockchain.BlockTree), TestItem.AddressD, withdrawals: Array.Empty(), 0, 0, transactions: transactions); - ResultWrapper result = await engineRpcModule.engine_newPayloadV3(executionPayload, blobVersionedHashes); + blockchain.SpecProvider.GenesisSpec, blockchain.State, + CreateParentBlockRequestOnHead(blockchain.BlockTree), TestItem.AddressD, withdrawals: Array.Empty(), 0, 0, transactions: transactions, beaconParentBlockRoot: Keccak.Zero); + ResultWrapper result = await engineRpcModule.engine_newPayloadV3(executionPayload, blobVersionedHashes, Keccak.Zero.BytesToArray()); return result.Data.Status; } @@ -419,8 +467,9 @@ public static IEnumerable CancunFieldsTestSource private async Task SendNewBlockV3(IEngineRpcModule rpc, MergeTestBlockchain chain, IList? withdrawals) { ExecutionPayloadV3 executionPayload = CreateBlockRequestV3( - CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD, withdrawals, 0, 0); - ResultWrapper executePayloadResult = await rpc.engine_newPayloadV3(executionPayload, Array.Empty()); + chain.SpecProvider.GenesisSpec, chain.State, + CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD, withdrawals, 0, 0, beaconParentBlockRoot: TestItem.KeccakE); + ResultWrapper executePayloadResult = await rpc.engine_newPayloadV3(executionPayload, Array.Empty(), executionPayload.ParentBeaconBlockRoot.BytesToArray()); executePayloadResult.Data.Status.Should().Be(PayloadStatus.Valid); @@ -454,12 +503,14 @@ private async Task SendNewBlockV3(IEngineRpcModule rpc, MergeT Timestamp = chain.BlockTree.Head!.Timestamp + 1, PrevRandao = TestItem.KeccakH, SuggestedFeeRecipient = TestItem.AddressF, - Withdrawals = new List { TestItem.WithdrawalA_1Eth } + Withdrawals = new List { TestItem.WithdrawalA_1Eth }, + ParentBeaconBlockRoot = spec.IsBeaconBlockRootAvailable ? TestItem.KeccakE : null }; Keccak currentHeadHash = chain.BlockTree.HeadHash; ForkchoiceStateV1 forkchoiceState = new(currentHeadHash, currentHeadHash, currentHeadHash); - string payloadId = rpcModule.engine_forkchoiceUpdatedV2(forkchoiceState, payloadAttributes).Result.Data - .PayloadId!; + string payloadId = spec.IsBeaconBlockRootAvailable + ? rpcModule.engine_forkchoiceUpdatedV3(forkchoiceState, payloadAttributes).Result.Data.PayloadId! + : rpcModule.engine_forkchoiceUpdatedV2(forkchoiceState, payloadAttributes).Result.Data.PayloadId!; return (rpcModule, payloadId, txs); } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadV3.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadV3.cs index ed182eb1466f..713585c19e6e 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadV3.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadV3.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core; +using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Int256; using Newtonsoft.Json; @@ -18,6 +19,7 @@ public class ExecutionPayloadV3 : ExecutionPayload public ExecutionPayloadV3(Block block) : base(block) { + ParentBeaconBlockRoot = block.ParentBeaconBlockRoot; BlobGasUsed = block.BlobGasUsed; ExcessBlobGas = block.ExcessBlobGas; } @@ -29,8 +31,9 @@ public override bool TryGetBlock(out Block? block, UInt256? totalDifficulty = nu return false; } + block!.Header.ParentBeaconBlockRoot = ParentBeaconBlockRoot; block!.Header.BlobGasUsed = BlobGasUsed; - block.Header.ExcessBlobGas = ExcessBlobGas; + block!.Header.ExcessBlobGas = ExcessBlobGas; return true; } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/IExecutionPayloadParams.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/IExecutionPayloadParams.cs index 3c2e721f40aa..5aa2404d32aa 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/IExecutionPayloadParams.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/IExecutionPayloadParams.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using Nethermind.Core; +using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Serialization.Rlp; @@ -22,11 +23,13 @@ public class ExecutionPayloadV3Params : IExecutionPayloadParams { private readonly ExecutionPayloadV3 _executionPayload; private readonly byte[]?[] _blobVersionedHashes; + private readonly byte[]? _parentBeaconBlockRoot; - public ExecutionPayloadV3Params(ExecutionPayloadV3 executionPayload, byte[]?[] blobVersionedHashes) + public ExecutionPayloadV3Params(ExecutionPayloadV3 executionPayload, byte[]?[] blobVersionedHashes, byte[]? parentBeaconBlockRoot) { _executionPayload = executionPayload; _blobVersionedHashes = blobVersionedHashes; + _parentBeaconBlockRoot = parentBeaconBlockRoot; } public ExecutionPayload ExecutionPayload => _executionPayload; @@ -49,13 +52,21 @@ public ValidationResult ValidateParams(IReleaseSpec spec, int version, out strin .Where(t => t.BlobVersionedHashes is not null) .SelectMany(t => t.BlobVersionedHashes!); - if (FlattenHashesFromTransactions(transactions).SequenceEqual(_blobVersionedHashes, Bytes.NullableEqualityComparer)) + if (!FlattenHashesFromTransactions(transactions).SequenceEqual(_blobVersionedHashes, Bytes.NullableEqualityComparer)) { - error = null; - return ValidationResult.Success; + error = "Blob versioned hashes do not match"; + return ValidationResult.Invalid; } - error = "Blob versioned hashes do not match"; - return ValidationResult.Invalid; + if (_parentBeaconBlockRoot is null) + { + error = "Parent beacon block root must be set"; + return ValidationResult.Fail; + } + + _executionPayload.ParentBeaconBlockRoot = new Keccak(_parentBeaconBlockRoot); + + error = null; + return ValidationResult.Success; } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.Cancun.cs b/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.Cancun.cs index 41aa57d7b61b..688f4ff0db31 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.Cancun.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.Cancun.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Nethermind.Consensus; +using Nethermind.Consensus.Producers; using Nethermind.Core.Extensions; using Nethermind.JsonRpc; using Nethermind.Merge.Plugin.Data; @@ -16,8 +18,11 @@ public partial class EngineRpcModule : IEngineRpcModule { private readonly IAsyncHandler _getPayloadHandlerV3; - public Task> engine_newPayloadV3(ExecutionPayloadV3 executionPayload, byte[]?[] blobVersionedHashes) => - NewPayload(new ExecutionPayloadV3Params(executionPayload, blobVersionedHashes), 3); + public Task> engine_forkchoiceUpdatedV3(ForkchoiceStateV1 forkchoiceState, PayloadAttributes? payloadAttributes = null) + => ForkchoiceUpdated(forkchoiceState, payloadAttributes, EngineApiVersions.Cancun); + + public Task> engine_newPayloadV3(ExecutionPayloadV3 executionPayload, byte[]?[] blobVersionedHashes, byte[]? parentBeaconBlockRoot) => + NewPayload(new ExecutionPayloadV3Params(executionPayload, blobVersionedHashes, parentBeaconBlockRoot), EngineApiVersions.Cancun); public async Task> engine_getPayloadV3(byte[] payloadId) => await _getPayloadHandlerV3.HandleAsync(payloadId); diff --git a/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.Paris.cs b/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.Paris.cs index 585af416360c..23a4c9740c93 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.Paris.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.Paris.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using Nethermind.Consensus; using Nethermind.Consensus.Producers; using Nethermind.Core.Specs; using Nethermind.JsonRpc; @@ -28,20 +29,20 @@ public ResultWrapper engine_exchangeTransitionConfigu TransitionConfigurationV1 beaconTransitionConfiguration) => _transitionConfigurationHandler.Handle(beaconTransitionConfiguration); public async Task> engine_forkchoiceUpdatedV1(ForkchoiceStateV1 forkchoiceState, PayloadAttributes? payloadAttributes = null) - => await ForkchoiceUpdated(forkchoiceState, payloadAttributes, 1); + => await ForkchoiceUpdated(forkchoiceState, payloadAttributes, EngineApiVersions.Paris); public Task> engine_getPayloadV1(byte[] payloadId) => _getPayloadHandlerV1.HandleAsync(payloadId); public async Task> engine_newPayloadV1(ExecutionPayload executionPayload) - => await NewPayload(executionPayload, 1); + => await NewPayload(executionPayload, EngineApiVersions.Paris); private async Task> ForkchoiceUpdated(ForkchoiceStateV1 forkchoiceState, PayloadAttributes? payloadAttributes, int version) { if (payloadAttributes?.Validate(_specProvider, version, out string? error) == false) { if (_logger.IsWarn) _logger.Warn(error); - return ResultWrapper.Fail(error, ErrorCodes.InvalidParams); + return ResultWrapper.Fail(error, version >= EngineApiVersions.Cancun ? ErrorCodes.UnsupportedFork : ErrorCodes.InvalidParams); } if (await _locker.WaitAsync(_timeout)) diff --git a/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.Shanghai.cs b/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.Shanghai.cs index 99792015ae3b..8c29a9ba971c 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.Shanghai.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.Shanghai.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Nethermind.Consensus; using Nethermind.Consensus.Producers; using Nethermind.Core.Crypto; using Nethermind.JsonRpc; @@ -18,7 +19,7 @@ public partial class EngineRpcModule : IEngineRpcModule private readonly IAsyncHandler _getPayloadHandlerV2; public Task> engine_forkchoiceUpdatedV2(ForkchoiceStateV1 forkchoiceState, PayloadAttributes? payloadAttributes = null) - => ForkchoiceUpdated(forkchoiceState, payloadAttributes, 2); + => ForkchoiceUpdated(forkchoiceState, payloadAttributes, EngineApiVersions.Shanghai); public Task> engine_getPayloadV2(byte[] payloadId) => _getPayloadHandlerV2.HandleAsync(payloadId); @@ -30,5 +31,5 @@ public Task> engine_forkchoiceUpdatedV2 => _executionGetPayloadBodiesByRangeV1Handler.Handle(start, count); public Task> engine_newPayloadV2(ExecutionPayload executionPayload) - => NewPayload(executionPayload, 2); + => NewPayload(executionPayload, EngineApiVersions.Shanghai); } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/EngineRpcCapabilitiesProvider.cs b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/EngineRpcCapabilitiesProvider.cs index 2248b429359e..1d69034f935f 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/EngineRpcCapabilitiesProvider.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/EngineRpcCapabilitiesProvider.cs @@ -42,6 +42,7 @@ public EngineRpcCapabilitiesProvider(ISpecProvider specProvider) #region Cancun _capabilities[nameof(IEngineRpcModule.engine_getPayloadV3)] = (spec.IsEip4844Enabled, spec.IsEip4844Enabled); + _capabilities[nameof(IEngineRpcModule.engine_forkchoiceUpdatedV3)] = (spec.IsEip4844Enabled, spec.IsEip4844Enabled); _capabilities[nameof(IEngineRpcModule.engine_newPayloadV3)] = (spec.IsEip4844Enabled, spec.IsEip4844Enabled); #endregion } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/IEngineRpcModule.Cancun.cs b/src/Nethermind/Nethermind.Merge.Plugin/IEngineRpcModule.Cancun.cs index f22b0bcb5f7e..fa3c978842f7 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/IEngineRpcModule.Cancun.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/IEngineRpcModule.Cancun.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Threading.Tasks; +using Nethermind.Consensus.Producers; using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules; using Nethermind.Merge.Plugin.Data; @@ -10,11 +11,18 @@ namespace Nethermind.Merge.Plugin; public partial interface IEngineRpcModule : IRpcModule { + + [JsonRpcMethod( + Description = "Verifies the payload according to the execution environment rules and returns the verification status and hash of the last valid block.", + IsSharable = true, + IsImplemented = true)] + Task> engine_forkchoiceUpdatedV3(ForkchoiceStateV1 forkchoiceState, PayloadAttributes? payloadAttributes = null); + [JsonRpcMethod( Description = "Verifies the payload according to the execution environment rules and returns the verification status and hash of the last valid block.", IsSharable = true, IsImplemented = true)] - Task> engine_newPayloadV3(ExecutionPayloadV3 executionPayload, byte[]?[] blobVersionedHashes); + Task> engine_newPayloadV3(ExecutionPayloadV3 executionPayload, byte[]?[] blobVersionedHashes, byte[]? beaconParentBlockRoot); [JsonRpcMethod( Description = "Returns the most recent version of an execution payload and fees with respect to the transaction set contained by the mempool.", diff --git a/src/Nethermind/Nethermind.Mev.Test/MevRpcModuleTests.TestMevRpcBlockchain.cs b/src/Nethermind/Nethermind.Mev.Test/MevRpcModuleTests.TestMevRpcBlockchain.cs index 7ae029e5287d..2155ea50b7f7 100644 --- a/src/Nethermind/Nethermind.Mev.Test/MevRpcModuleTests.TestMevRpcBlockchain.cs +++ b/src/Nethermind/Nethermind.Mev.Test/MevRpcModuleTests.TestMevRpcBlockchain.cs @@ -226,7 +226,7 @@ protected override BlockProcessor CreateBlockProcessor() } protected override async Task Build(ISpecProvider? specProvider = null, - UInt256? initialValues = null) + UInt256? initialValues = null, bool addBlockOnStart = true) { TestBlockchain chain = await base.Build(specProvider, initialValues); MevRpcModule = new MevRpcModule(new JsonRpcConfig(), diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs index 5c897186f3ff..e5cba70e565e 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only using System; @@ -77,13 +77,19 @@ public class HeaderDecoder : IRlpValueDecoder, IRlpStreamDecoder= 3 && decoderContext.Position != headerCheck) { blockHeader.BlobGasUsed = decoderContext.DecodeULong(allowLeadingZeroBytes: false); blockHeader.ExcessBlobGas = decoderContext.DecodeULong(allowLeadingZeroBytes: false); } + + if (itemsRemaining == 4 && decoderContext.Position != headerCheck) + { + blockHeader.ParentBeaconBlockRoot = decoderContext.DecodeKeccak(); + } } + if ((rlpBehaviors & RlpBehaviors.AllowExtraBytes) != RlpBehaviors.AllowExtraBytes) { decoderContext.Check(headerCheck); @@ -158,11 +164,16 @@ public class HeaderDecoder : IRlpValueDecoder, IRlpStreamDecoder= 3 && rlpStream.Position != headerCheck) { blockHeader.BlobGasUsed = rlpStream.DecodeUlong(allowLeadingZeroBytes: false); blockHeader.ExcessBlobGas = rlpStream.DecodeUlong(allowLeadingZeroBytes: false); } + + if (itemsRemaining == 4 && rlpStream.Position != headerCheck) + { + blockHeader.ParentBeaconBlockRoot = rlpStream.DecodeKeccak(); + } } if ((rlpBehaviors & RlpBehaviors.AllowExtraBytes) != RlpBehaviors.AllowExtraBytes) @@ -227,6 +238,11 @@ public void Encode(RlpStream rlpStream, BlockHeader? header, RlpBehaviors rlpBeh rlpStream.Encode(header.BlobGasUsed.GetValueOrDefault()); rlpStream.Encode(header.ExcessBlobGas.GetValueOrDefault()); } + + if (header.ParentBeaconBlockRoot is not null) + { + rlpStream.Encode(header.ParentBeaconBlockRoot ?? Keccak.Zero); + } } public Rlp Encode(BlockHeader? item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) @@ -266,6 +282,7 @@ private static int GetContentLength(BlockHeader? item, RlpBehaviors rlpBehaviors + Rlp.LengthOf(item.ExtraData) + (item.BaseFeePerGas.IsZero ? 0 : Rlp.LengthOf(item.BaseFeePerGas)) + (item.WithdrawalsRoot is null && item.BlobGasUsed is null && item.ExcessBlobGas is null ? 0 : Rlp.LengthOfKeccakRlp) + + (item.ParentBeaconBlockRoot is null ? 0 : Rlp.LengthOfKeccakRlp) + (item.BlobGasUsed is null ? 0 : Rlp.LengthOf(item.BlobGasUsed.Value)) + (item.ExcessBlobGas is null ? 0 : Rlp.LengthOf(item.ExcessBlobGas.Value)); diff --git a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs index dbebe3749dbd..48d301178e69 100644 --- a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs @@ -155,5 +155,6 @@ public ulong Eip4844TransitionTimestamp public ulong WithdrawalTimestamp => _spec.WithdrawalTimestamp; public bool IsEip5656Enabled => _spec.IsEip5656Enabled; public bool IsEip6780Enabled => _spec.IsEip6780Enabled; + public bool IsEip4788Enabled => _spec.IsEip4788Enabled; } } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs index 7f12e7acf4f9..5c3a6f79fc73 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs @@ -115,5 +115,6 @@ public class ChainParameters public ulong? Eip1153TransitionTimestamp { get; set; } public ulong? Eip5656TransitionTimestamp { get; set; } public ulong? Eip6780TransitionTimestamp { get; set; } + public ulong? Eip4788TransitionTimestamp { get; set; } } } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs index 655fa41af9ff..ecef8dc1df23 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs @@ -238,6 +238,7 @@ private static ReleaseSpec CreateReleaseSpec(ChainSpec chainSpec, long releaseSt releaseSpec.Eip4844TransitionTimestamp = chainSpec.Parameters.Eip4844TransitionTimestamp ?? ulong.MaxValue; releaseSpec.IsEip5656Enabled = (chainSpec.Parameters.Eip5656TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.IsEip6780Enabled = (chainSpec.Parameters.Eip6780TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; + releaseSpec.IsEip4788Enabled = (chainSpec.Parameters.Eip4788TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; return releaseSpec; } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs index c5b65c6c6356..5362e45e86ba 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs @@ -142,6 +142,7 @@ private void LoadParameters(ChainSpecJson chainSpecJson, ChainSpec chainSpec) Eip2537TransitionTimestamp = chainSpecJson.Params.Eip2537TransitionTimestamp, Eip5656TransitionTimestamp = chainSpecJson.Params.Eip5656TransitionTimestamp, Eip6780TransitionTimestamp = chainSpecJson.Params.Eip6780TransitionTimestamp, + Eip4788TransitionTimestamp = chainSpecJson.Params.Eip4788TransitionTimestamp, TransactionPermissionContract = chainSpecJson.Params.TransactionPermissionContract, TransactionPermissionContractTransition = chainSpecJson.Params.TransactionPermissionContractTransition, ValidateChainIdTransition = chainSpecJson.Params.ValidateChainIdTransition, @@ -388,6 +389,12 @@ private static void LoadGenesis(ChainSpecJson chainSpecJson, ChainSpec chainSpec genesisHeader.ExcessBlobGas = chainSpecJson.Genesis.ExcessBlobGas; } + bool isEip4788Enabled = chainSpecJson.Params.Eip4788TransitionTimestamp != null && genesisHeader.Timestamp >= chainSpecJson.Params.Eip4788TransitionTimestamp; + if (isEip4788Enabled) + { + genesisHeader.ParentBeaconBlockRoot = chainSpecJson.Genesis.ParentBeaconBlockRoot; + } + genesisHeader.AuRaStep = step; genesisHeader.AuRaSignature = auRaSignature; diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecGenesisJson.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecGenesisJson.cs index c6ef813acb54..52190d8a6222 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecGenesisJson.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecGenesisJson.cs @@ -25,5 +25,6 @@ internal class ChainSpecGenesisJson public ulong? BlobGasUsed { get; set; } public ulong? ExcessBlobGas { get; set; } + public Keccak ParentBeaconBlockRoot { get; set; } } } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs index d1fabed369a1..677c0c45a133 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs @@ -143,5 +143,6 @@ internal class ChainSpecParamsJson public ulong? Eip2537TransitionTimestamp { get; set; } public ulong? Eip5656TransitionTimestamp { get; set; } public ulong? Eip6780TransitionTimestamp { get; set; } + public ulong? Eip4788TransitionTimestamp { get; set; } } } diff --git a/src/Nethermind/Nethermind.Specs/Forks/16_Cancun.cs b/src/Nethermind/Nethermind.Specs/Forks/16_Cancun.cs index f50e02308f1c..bc4c01ab58ea 100644 --- a/src/Nethermind/Nethermind.Specs/Forks/16_Cancun.cs +++ b/src/Nethermind/Nethermind.Specs/Forks/16_Cancun.cs @@ -17,6 +17,7 @@ protected Cancun() IsEip5656Enabled = true; IsEip4844Enabled = true; IsEip6780Enabled = true; + IsEip4788Enabled = true; } public new static IReleaseSpec Instance => LazyInitializer.EnsureInitialized(ref _instance, () => new Cancun()); diff --git a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs index 029dbf37b08e..7f40302ee2d2 100644 --- a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs @@ -81,5 +81,6 @@ public ReleaseSpec Clone() public bool IsEip4844Enabled { get; set; } public bool IsEip5656Enabled { get; set; } public bool IsEip6780Enabled { get; set; } + public bool IsEip4788Enabled { get; set; } } } diff --git a/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs index 3dc669059c32..3b63d5a731ae 100644 --- a/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs @@ -128,5 +128,6 @@ public bool IsEip158IgnoredAccount(Address address) public bool IsEip4895Enabled => _spec.IsEip4895Enabled; public bool IsEip5656Enabled => _spec.IsEip5656Enabled; public bool IsEip6780Enabled => _spec.IsEip6780Enabled; + public bool IsEip4788Enabled => _spec.IsEip4788Enabled; } } diff --git a/src/Nethermind/Nethermind.State/IWorldState.cs b/src/Nethermind/Nethermind.State/IWorldState.cs index 50822e73e106..51f56ed43bc7 100644 --- a/src/Nethermind/Nethermind.State/IWorldState.cs +++ b/src/Nethermind/Nethermind.State/IWorldState.cs @@ -80,9 +80,8 @@ public interface IWorldState : IJournal, IReadOnlyStateProvider void DeleteAccount(Address address); - void CreateAccount(Address address, in UInt256 balance); - - void CreateAccount(Address address, in UInt256 balance, in UInt256 nonce); + void CreateAccount(Address address, in UInt256 balance, in UInt256 nonce = default); + void CreateAccountIfNotExists(Address address, in UInt256 balance, in UInt256 nonce = default); void InsertCode(Address address, ReadOnlyMemory code, IReleaseSpec spec, bool isGenesis = false); diff --git a/src/Nethermind/Nethermind.State/StateProvider.cs b/src/Nethermind/Nethermind.State/StateProvider.cs index e5aaea60b060..9569fe427a60 100644 --- a/src/Nethermind/Nethermind.State/StateProvider.cs +++ b/src/Nethermind/Nethermind.State/StateProvider.cs @@ -407,21 +407,18 @@ public void Restore(int snapshot) _keptInCache.Clear(); } - public void CreateAccount(Address address, in UInt256 balance) + public void CreateAccount(Address address, in UInt256 balance, in UInt256 nonce = default) { _needsStateRootUpdate = true; - if (_logger.IsTrace) _logger.Trace($"Creating account: {address} with balance {balance}"); - Account account = balance.IsZero ? Account.TotallyEmpty : new Account(balance); + if (_logger.IsTrace) _logger.Trace($"Creating account: {address} with balance {balance} and nonce {nonce}"); + Account account = (balance.IsZero && nonce.IsZero) ? Account.TotallyEmpty : new Account(nonce, balance); PushNew(address, account); } - - public void CreateAccount(Address address, in UInt256 balance, in UInt256 nonce) + public void CreateAccountIfNotExists(Address address, in UInt256 balance, in UInt256 nonce = default) { - _needsStateRootUpdate = true; - if (_logger.IsTrace) _logger.Trace($"Creating account: {address} with balance {balance} and nonce {nonce}"); - Account account = (balance.IsZero && nonce.IsZero) ? Account.TotallyEmpty : new Account(nonce, balance); - PushNew(address, account); + if (AccountExists(address)) return; + CreateAccount(address, balance, nonce); } public void AddToBalanceAndCreateIfNotExists(Address address, in UInt256 balance, IReleaseSpec spec) diff --git a/src/Nethermind/Nethermind.State/WorldState.cs b/src/Nethermind/Nethermind.State/WorldState.cs index f1590558cc00..924ce51c21cf 100644 --- a/src/Nethermind/Nethermind.State/WorldState.cs +++ b/src/Nethermind/Nethermind.State/WorldState.cs @@ -102,11 +102,7 @@ public void DeleteAccount(Address address) { _stateProvider.DeleteAccount(address); } - public void CreateAccount(Address address, in UInt256 balance) - { - _stateProvider.CreateAccount(address, balance); - } - public void CreateAccount(Address address, in UInt256 balance, in UInt256 nonce) + public void CreateAccount(Address address, in UInt256 balance, in UInt256 nonce = default) { _stateProvider.CreateAccount(address, balance, nonce); } @@ -230,5 +226,10 @@ internal void SetNonce(Address address, in UInt256 nonce) { _stateProvider.SetNonce(address, nonce); } + + public void CreateAccountIfNotExists(Address address, in UInt256 balance, in UInt256 nonce = default) + { + _stateProvider.CreateAccountIfNotExists(address, balance, nonce); + } } }