diff --git a/src/Nethermind/Nethermind.Evm.Benchmark/EvmBenchmarks.cs b/src/Nethermind/Nethermind.Evm.Benchmark/EvmBenchmarks.cs index be98ea39aab..b29fcf00088 100644 --- a/src/Nethermind/Nethermind.Evm.Benchmark/EvmBenchmarks.cs +++ b/src/Nethermind/Nethermind.Evm.Benchmark/EvmBenchmarks.cs @@ -40,7 +40,6 @@ public void GlobalSetup() TrieStore trieStore = new(new MemDb(), new OneLoggerLogManager(NullLogger.Instance)); IKeyValueStore codeDb = new MemDb(); - _stateProvider = new WorldState(trieStore, codeDb, new OneLoggerLogManager(NullLogger.Instance)); _stateProvider.CreateAccount(Address.Zero, 1000.Ether()); _stateProvider.Commit(_spec); @@ -59,7 +58,7 @@ public void GlobalSetup() inputData: default ); - _evmState = new EvmState(long.MaxValue, _environment, ExecutionType.TRANSACTION, true, _stateProvider.TakeSnapshot(), false); + _evmState = new EvmState(long.MaxValue, _environment, ExecutionType.TRANSACTION, _stateProvider.TakeSnapshot()); } [Benchmark] diff --git a/src/Nethermind/Nethermind.Evm.Benchmark/MultipleUnsignedOperations.cs b/src/Nethermind/Nethermind.Evm.Benchmark/MultipleUnsignedOperations.cs index 3b3853d5fc5..97d0d9e6cf8 100644 --- a/src/Nethermind/Nethermind.Evm.Benchmark/MultipleUnsignedOperations.cs +++ b/src/Nethermind/Nethermind.Evm.Benchmark/MultipleUnsignedOperations.cs @@ -91,7 +91,7 @@ public void GlobalSetup() inputData: default ); - _evmState = new EvmState(100_000_000L, _environment, ExecutionType.TRANSACTION, true, _stateProvider.TakeSnapshot(), false); + _evmState = new EvmState(100_000_000L, _environment, ExecutionType.TRANSACTION, _stateProvider.TakeSnapshot()); } [Benchmark] diff --git a/src/Nethermind/Nethermind.Evm.Benchmark/StaticCallBenchmarks.cs b/src/Nethermind/Nethermind.Evm.Benchmark/StaticCallBenchmarks.cs index 12c12742ed7..b7b8d39945b 100644 --- a/src/Nethermind/Nethermind.Evm.Benchmark/StaticCallBenchmarks.cs +++ b/src/Nethermind/Nethermind.Evm.Benchmark/StaticCallBenchmarks.cs @@ -102,7 +102,7 @@ public void GlobalSetup() inputData: default ); - _evmState = new EvmState(100_000_000L, _environment, ExecutionType.TRANSACTION, true, _stateProvider.TakeSnapshot(), false); + _evmState = new EvmState(100_000_000L, _environment, ExecutionType.TRANSACTION, _stateProvider.TakeSnapshot()); } [Benchmark(Baseline = true)] diff --git a/src/Nethermind/Nethermind.Evm.Test/EvmStateTests.cs b/src/Nethermind/Nethermind.Evm.Test/EvmStateTests.cs index 7360218608a..557f6016ea4 100644 --- a/src/Nethermind/Nethermind.Evm.Test/EvmStateTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/EvmStateTests.cs @@ -14,20 +14,13 @@ namespace Nethermind.Evm.Test { public class EvmStateTests { - [Test] - public void Top_level_continuations_are_not_valid() - { - Assert.Throws( - () => _ = CreateEvmState(isContinuation: true)); - } - [Test] public void Things_are_cold_to_start_with() { EvmState evmState = CreateEvmState(); StorageCell storageCell = new(TestItem.AddressA, 1); - evmState.IsCold(TestItem.AddressA).Should().BeTrue(); - evmState.IsCold(storageCell).Should().BeTrue(); + evmState.AccessTracker.IsCold(TestItem.AddressA).Should().BeTrue(); + evmState.AccessTracker.IsCold(storageCell).Should().BeTrue(); } [Test] @@ -35,9 +28,9 @@ public void Can_warm_address_up_twice() { EvmState evmState = CreateEvmState(); Address address = TestItem.AddressA; - evmState.WarmUp(address); - evmState.WarmUp(address); - evmState.IsCold(address).Should().BeFalse(); + evmState.AccessTracker.WarmUp(address); + evmState.AccessTracker.WarmUp(address); + evmState.AccessTracker.IsCold(address).Should().BeFalse(); } [Test] @@ -46,14 +39,14 @@ public void Can_warm_up_many() EvmState evmState = CreateEvmState(); for (int i = 0; i < TestItem.Addresses.Length; i++) { - evmState.WarmUp(TestItem.Addresses[i]); - evmState.WarmUp(new StorageCell(TestItem.Addresses[i], 1)); + evmState.AccessTracker.WarmUp(TestItem.Addresses[i]); + evmState.AccessTracker.WarmUp(new StorageCell(TestItem.Addresses[i], 1)); } for (int i = 0; i < TestItem.Addresses.Length; i++) { - evmState.IsCold(TestItem.Addresses[i]).Should().BeFalse(); - evmState.IsCold(new StorageCell(TestItem.Addresses[i], 1)).Should().BeFalse(); + evmState.AccessTracker.IsCold(TestItem.Addresses[i]).Should().BeFalse(); + evmState.AccessTracker.IsCold(new StorageCell(TestItem.Addresses[i], 1)).Should().BeFalse(); } } @@ -63,9 +56,9 @@ public void Can_warm_storage_up_twice() EvmState evmState = CreateEvmState(); Address address = TestItem.AddressA; StorageCell storageCell = new(address, 1); - evmState.WarmUp(storageCell); - evmState.WarmUp(storageCell); - evmState.IsCold(storageCell).Should().BeFalse(); + evmState.AccessTracker.WarmUp(storageCell); + evmState.AccessTracker.WarmUp(storageCell); + evmState.AccessTracker.IsCold(storageCell).Should().BeFalse(); } [Test] @@ -91,11 +84,11 @@ public void Address_to_commit_keeps_it_warm() EvmState parentEvmState = CreateEvmState(); using (EvmState evmState = CreateEvmState(parentEvmState)) { - evmState.WarmUp(TestItem.AddressA); + evmState.AccessTracker.WarmUp(TestItem.AddressA); evmState.CommitToParent(parentEvmState); } - parentEvmState.IsCold(TestItem.AddressA).Should().BeFalse(); + parentEvmState.AccessTracker.IsCold(TestItem.AddressA).Should().BeFalse(); } [Test] @@ -104,10 +97,10 @@ public void Address_to_restore_keeps_it_cold() EvmState parentEvmState = CreateEvmState(); using (EvmState evmState = CreateEvmState(parentEvmState)) { - evmState.WarmUp(TestItem.AddressA); + evmState.AccessTracker.WarmUp(TestItem.AddressA); } - parentEvmState.IsCold(TestItem.AddressA).Should().BeTrue(); + parentEvmState.AccessTracker.IsCold(TestItem.AddressA).Should().BeTrue(); } [Test] @@ -117,11 +110,11 @@ public void Storage_to_commit_keeps_it_warm() StorageCell storageCell = new(TestItem.AddressA, 1); using (EvmState evmState = CreateEvmState(parentEvmState)) { - evmState.WarmUp(storageCell); + evmState.AccessTracker.WarmUp(storageCell); evmState.CommitToParent(parentEvmState); } - parentEvmState.IsCold(storageCell).Should().BeFalse(); + parentEvmState.AccessTracker.IsCold(storageCell).Should().BeFalse(); } [Test] @@ -131,10 +124,10 @@ public void Storage_to_restore_keeps_it_cold() StorageCell storageCell = new(TestItem.AddressA, 1); using (EvmState evmState = CreateEvmState(parentEvmState)) { - evmState.WarmUp(storageCell); + evmState.AccessTracker.WarmUp(storageCell); } - parentEvmState.IsCold(storageCell).Should().BeTrue(); + parentEvmState.AccessTracker.IsCold(storageCell).Should().BeTrue(); } [Test] @@ -144,11 +137,11 @@ public void Logs_are_committed() LogEntry logEntry = new(Address.Zero, Bytes.Empty, Array.Empty()); using (EvmState evmState = CreateEvmState(parentEvmState)) { - evmState.Logs.Add(logEntry); + evmState.AccessTracker.Logs.Add(logEntry); evmState.CommitToParent(parentEvmState); } - parentEvmState.Logs.Contains(logEntry).Should().BeTrue(); + parentEvmState.AccessTracker.Logs.Contains(logEntry).Should().BeTrue(); } [Test] @@ -158,10 +151,10 @@ public void Logs_are_restored() LogEntry logEntry = new(Address.Zero, Bytes.Empty, Array.Empty()); using (EvmState evmState = CreateEvmState(parentEvmState)) { - evmState.Logs.Add(logEntry); + evmState.AccessTracker.Logs.Add(logEntry); } - parentEvmState.Logs.Contains(logEntry).Should().BeFalse(); + parentEvmState.AccessTracker.Logs.Contains(logEntry).Should().BeFalse(); } [Test] @@ -170,11 +163,11 @@ public void Destroy_list_is_committed() EvmState parentEvmState = CreateEvmState(); using (EvmState evmState = CreateEvmState(parentEvmState)) { - evmState.DestroyList.Add(Address.Zero); + evmState.AccessTracker.ToBeDestroyed(Address.Zero); evmState.CommitToParent(parentEvmState); } - parentEvmState.DestroyList.Contains(Address.Zero).Should().BeTrue(); + parentEvmState.AccessTracker.DestroyList.Contains(Address.Zero).Should().BeTrue(); } [Test] @@ -183,10 +176,10 @@ public void Destroy_list_is_restored() EvmState parentEvmState = CreateEvmState(); using (EvmState evmState = CreateEvmState(parentEvmState)) { - evmState.DestroyList.Add(Address.Zero); + evmState.AccessTracker.ToBeDestroyed(Address.Zero); } - parentEvmState.DestroyList.Contains(Address.Zero).Should().BeFalse(); + parentEvmState.AccessTracker.DestroyList.Contains(Address.Zero).Should().BeFalse(); } [Test] @@ -234,19 +227,15 @@ parentEvmState is null ? new EvmState(10000, new ExecutionEnvironment(), ExecutionType.CALL, - true, - Snapshot.Empty, - isContinuation) + Snapshot.Empty) : new EvmState(10000, new ExecutionEnvironment(), ExecutionType.CALL, - false, Snapshot.Empty, 0, 0, false, - parentEvmState, - isContinuation, + parentEvmState.AccessTracker, false); public class Context { } diff --git a/src/Nethermind/Nethermind.Evm/EvmState.cs b/src/Nethermind/Nethermind.Evm/EvmState.cs index b2c7cb93022..5df715ab60e 100644 --- a/src/Nethermind/Nethermind.Evm/EvmState.cs +++ b/src/Nethermind/Nethermind.Evm/EvmState.cs @@ -6,9 +6,7 @@ using System.Diagnostics; using System.Threading; using Nethermind.Core; -using Nethermind.Core.Collections; -using Nethermind.Core.Eip2930; -using Nethermind.Int256; +using Nethermind.Core.Specs; using Nethermind.State; namespace Nethermind.Evm @@ -75,62 +73,81 @@ public void ReturnStacks(byte[] dataStack, int[] returnStack) public int[]? ReturnStack; - /// - /// EIP-2929 accessed addresses - /// - public IReadOnlySet
AccessedAddresses => _accessedAddresses; - - /// - /// EIP-2929 accessed storage keys - /// - public IReadOnlySet AccessedStorageCells => _accessedStorageCells; - - // As we can add here from VM, we need it as ICollection - public ICollection
DestroyList => _destroyList; - // As we can add here from VM, we need it as ICollection - public ICollection CreateList => _createList; - // As we can add here from VM, we need it as ICollection - public ICollection Logs => _logs; + public StackAccessTracker AccessTracker => _accessTracker; - private readonly JournalSet
_accessedAddresses; - private readonly JournalSet _accessedStorageCells; - private readonly JournalCollection _logs; - private readonly JournalSet
_destroyList; - private readonly HashSet _createList; - private readonly int _accessedAddressesSnapshot; - private readonly int _accessedStorageKeysSnapshot; - private readonly int _destroyListSnapshot; - private readonly int _logsSnapshot; + private readonly StackAccessTracker _accessTracker; public int DataStackHead = 0; public int ReturnStackHead = 0; private bool _canRestore = true; - + /// + /// Contructor for a top level . + /// public EvmState( long gasAvailable, ExecutionEnvironment env, ExecutionType executionType, - bool isTopLevel, Snapshot snapshot, - bool isContinuation) - : this(gasAvailable, + in StackAccessTracker accessedItems) : this(gasAvailable, + env, + executionType, + true, + snapshot, + 0L, + 0L, + false, + accessedItems, + false) + { + } + /// + /// Contructor for a top level . + /// + public EvmState( + long gasAvailable, + ExecutionEnvironment env, + ExecutionType executionType, + Snapshot snapshot) : this(gasAvailable, + env, + executionType, + true, + snapshot, + 0L, + 0L, + false, + new StackAccessTracker(), + false) + { + } + /// + /// Contructor for a frame beneath top level. + /// + internal EvmState( + long gasAvailable, + ExecutionEnvironment env, + ExecutionType executionType, + Snapshot snapshot, + long outputDestination, + long outputLength, + bool isStatic, + in StackAccessTracker stateForAccessLists, + bool isCreateOnPreExistingAccount) : + this( + gasAvailable, env, executionType, - isTopLevel, - snapshot, - 0L, - 0L, false, - null, - isContinuation, - false) + snapshot, + outputDestination, + outputLength, + isStatic, + stateForAccessLists, + isCreateOnPreExistingAccount) { - GasAvailable = gasAvailable; - Env = env; - } - internal EvmState( + } + private EvmState( long gasAvailable, ExecutionEnvironment env, ExecutionType executionType, @@ -139,15 +156,9 @@ internal EvmState( long outputDestination, long outputLength, bool isStatic, - EvmState? stateForAccessLists, - bool isContinuation, + in StackAccessTracker stateForAccessLists, bool isCreateOnPreExistingAccount) { - if (isTopLevel && isContinuation) - { - throw new InvalidOperationException("Top level continuations are not valid"); - } - GasAvailable = gasAvailable; ExecutionType = executionType; IsTopLevel = isTopLevel; @@ -157,36 +168,14 @@ internal EvmState( OutputDestination = outputDestination; OutputLength = outputLength; IsStatic = isStatic; - IsContinuation = isContinuation; + IsContinuation = false; IsCreateOnPreExistingAccount = isCreateOnPreExistingAccount; - if (stateForAccessLists is not null) - { - // if we are sub-call, then we use the main collection for this transaction - _accessedAddresses = stateForAccessLists._accessedAddresses; - _accessedStorageCells = stateForAccessLists._accessedStorageCells; - _destroyList = stateForAccessLists._destroyList; - _createList = stateForAccessLists._createList; - _logs = stateForAccessLists._logs; - } - else - { - // if we are top level, then we need to create the collections - _accessedAddresses = new JournalSet
(); - _accessedStorageCells = new JournalSet(); - _destroyList = new JournalSet
(); - _createList = new HashSet(); - _logs = new JournalCollection(); - } + _accessTracker = new(stateForAccessLists); if (executionType.IsAnyCreate()) { - _createList.Add(env.ExecutingAccount); + _accessTracker.WasCreated(env.ExecutingAccount); } - - _accessedAddressesSnapshot = _accessedAddresses.TakeSnapshot(); - _accessedStorageKeysSnapshot = _accessedStorageCells.TakeSnapshot(); - _destroyListSnapshot = _destroyList.TakeSnapshot(); - _logsSnapshot = _logs.TakeSnapshot(); - + _accessTracker.TakeSnapshot(); } public Address From @@ -252,29 +241,6 @@ public void InitStacks() } } - public bool IsCold(Address? address) => !_accessedAddresses.Contains(address); - - public bool IsCold(in StorageCell storageCell) => !_accessedStorageCells.Contains(storageCell); - - public void WarmUp(AccessList? accessList) - { - if (accessList?.IsEmpty == false) - { - foreach ((Address address, AccessList.StorageKeysEnumerable storages) in accessList) - { - WarmUp(address); - foreach (UInt256 storage in storages) - { - WarmUp(new StorageCell(address, storage)); - } - } - } - } - - public void WarmUp(Address address) => _accessedAddresses.Add(address); - - public void WarmUp(in StorageCell storageCell) => _accessedStorageCells.Add(storageCell); - public void CommitToParent(EvmState parentState) { parentState.Refund += Refund; @@ -285,10 +251,7 @@ private void Restore() { if (_canRestore) // if we didn't commit and we are not top level, then we need to restore and drop the changes done in this call { - _logs.Restore(_logsSnapshot); - _destroyList.Restore(_destroyListSnapshot); - _accessedAddresses.Restore(_accessedAddressesSnapshot); - _accessedStorageCells.Restore(_accessedStorageKeysSnapshot); + _accessTracker.Restore(); } } } diff --git a/src/Nethermind/Nethermind.Evm/StackAccessTracker.cs b/src/Nethermind/Nethermind.Evm/StackAccessTracker.cs new file mode 100644 index 00000000000..8e94313fb8b --- /dev/null +++ b/src/Nethermind/Nethermind.Evm/StackAccessTracker.cs @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; +using Nethermind.Core; +using Nethermind.Core.Collections; +using Nethermind.Core.Eip2930; +using Nethermind.Int256; + +namespace Nethermind.Evm +{ + public struct StackAccessTracker + { + public readonly IReadOnlySet
AccessedAddresses => _accessedAddresses; + public readonly IReadOnlySet AccessedStorageCells => _accessedStorageCells; + public readonly ICollection Logs => _logs; + public readonly IReadOnlySet
DestroyList => _destroyList; + public readonly IReadOnlySet CreateList => _createList; + private readonly JournalSet
_accessedAddresses; + private readonly JournalSet _accessedStorageCells; + private readonly JournalCollection _logs; + private readonly JournalSet
_destroyList; + private readonly HashSet _createList; + + private int _addressesSnapshots; + private int _storageKeysSnapshots; + private int _destroyListSnapshots; + private int _logsSnapshots; + + public StackAccessTracker(in StackAccessTracker accessTracker) + { + _accessedAddresses = accessTracker._accessedAddresses; + _accessedStorageCells = accessTracker._accessedStorageCells; + _logs = accessTracker._logs; + _destroyList = accessTracker._destroyList; + _createList = accessTracker._createList; + } + + public StackAccessTracker() + { + _accessedAddresses = new(); + _accessedStorageCells = new(); + _logs = new(); + _destroyList = new(); + _createList = new(); + } + public readonly bool IsCold(Address? address) => !AccessedAddresses.Contains(address); + + public readonly bool IsCold(in StorageCell storageCell) => !_accessedStorageCells.Contains(storageCell); + + public readonly void WarmUp(Address address) + { + _accessedAddresses.Add(address); + } + + public readonly void WarmUp(in StorageCell storageCell) + { + _accessedStorageCells.Add(storageCell); + } + + public readonly void WarmUp(AccessList? accessList) + { + if (accessList?.IsEmpty == false) + { + foreach ((Address address, AccessList.StorageKeysEnumerable storages) in accessList) + { + _accessedAddresses.Add(address); + foreach (UInt256 storage in storages) + { + _accessedStorageCells.Add(new StorageCell(address, storage)); + } + } + } + } + + public void ToBeDestroyed(Address address) + { + _destroyList.Add(address); + } + + public void WasCreated(Address address) + { + _createList.Add(address); + } + + public void TakeSnapshot() + { + _addressesSnapshots = _accessedAddresses.TakeSnapshot(); + _storageKeysSnapshots = _accessedStorageCells.TakeSnapshot(); + _destroyListSnapshots = _destroyList.TakeSnapshot(); + _logsSnapshots = _logs.TakeSnapshot(); + } + + public void Restore() + { + _logs.Restore(_logsSnapshots); + _destroyList.Restore(_destroyListSnapshots); + _accessedAddresses.Restore(_addressesSnapshots); + _accessedStorageCells.Restore(_storageKeysSnapshots); + } + } +} diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index 3f70990d8a4..f914553a832 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Runtime.CompilerServices; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Crypto; @@ -158,13 +159,13 @@ protected virtual TransactionResult Execute(Transaction tx, in BlockExecutionCon if (commit) WorldState.Commit(spec, tracer.IsTracingState ? tracer : NullTxTracer.Instance, commitStorageRoots: false); - _accessedAddresses.Clear(); - int delegationRefunds = ProcessDelegations(tx, spec, _accessedAddresses); + StackAccessTracker accessTracker = new(); + int delegationRefunds = ProcessDelegations(tx, spec, accessTracker); - ExecutionEnvironment env = BuildExecutionEnvironment(tx, in blCtx, spec, effectiveGasPrice, _codeInfoRepository, _accessedAddresses); + ExecutionEnvironment env = BuildExecutionEnvironment(tx, in blCtx, spec, effectiveGasPrice, _codeInfoRepository, accessTracker); long gasAvailable = tx.GasLimit - intrinsicGas; - ExecuteEvmCall(tx, header, spec, tracer, opts, delegationRefunds, _accessedAddresses, gasAvailable, env, out TransactionSubstate? substate, out long spentGas, out byte statusCode); + ExecuteEvmCall(tx, header, spec, tracer, opts, delegationRefunds, accessTracker, gasAvailable, env, out TransactionSubstate? substate, out long spentGas, out byte statusCode); PayFees(tx, header, spec, tracer, substate, spentGas, premiumPerGas, blobBaseFee, statusCode); // Finalize @@ -217,7 +218,7 @@ protected virtual TransactionResult Execute(Transaction tx, in BlockExecutionCon return TransactionResult.Ok; } - private int ProcessDelegations(Transaction tx, IReleaseSpec spec, HashSet
accessedAddresses) + private int ProcessDelegations(Transaction tx, IReleaseSpec spec, in StackAccessTracker accessTracker) { int refunds = 0; if (spec.IsEip7702Enabled && tx.HasAuthorizationList) @@ -226,7 +227,7 @@ private int ProcessDelegations(Transaction tx, IReleaseSpec spec, HashSet accessedAddresses, + StackAccessTracker accessTracker, [NotNullWhen(false)] out string? error) { UInt256 s = new(authorizationTuple.AuthoritySignature.SAsSpan, isBigEndian: true); @@ -279,7 +280,18 @@ bool IsValidForExecution( return false; } - accessedAddresses.Add(authorizationTuple.Authority); + if (authorizationTuple.AuthoritySignature.ChainId is not null && authorizationTuple.AuthoritySignature.ChainId != authorizationTuple.ChainId) + { + error = "Bad signature."; + return false; + } + + if (authorizationTuple.Nonce == ulong.MaxValue) + { + error = $"Nonce ({authorizationTuple.Nonce}) must be less than 2**64 - 1."; + return false; + } + accessTracker.WarmUp(authorizationTuple.Authority); if (WorldState.HasCode(authorizationTuple.Authority) && !_codeInfoRepository.TryGetDelegation(WorldState, authorizationTuple.Authority, out _)) { @@ -532,24 +544,33 @@ private ExecutionEnvironment BuildExecutionEnvironment( IReleaseSpec spec, in UInt256 effectiveGasPrice, ICodeInfoRepository codeInfoRepository, - HashSet
accessedAddresses) + in StackAccessTracker accessTracker) { Address recipient = tx.GetRecipient(tx.IsContractCreation ? WorldState.GetNonce(tx.SenderAddress!) : 0); if (recipient is null) ThrowInvalidDataException("Recipient has not been resolved properly before tx execution"); - accessedAddresses.Add(recipient); - accessedAddresses.Add(tx.SenderAddress!); - TxExecutionContext executionContext = new(in blCtx, tx.SenderAddress, effectiveGasPrice, tx.BlobVersionedHashes, codeInfoRepository); Address? delegationAddress = null; CodeInfo codeInfo = tx.IsContractCreation ? new(tx.Data ?? Memory.Empty) : codeInfoRepository.GetCachedCodeInfo(WorldState, recipient, spec, out delegationAddress); + codeInfo.AnalyseInBackgroundIfRequired(); - if (delegationAddress is not null) - accessedAddresses.Add(delegationAddress); + if (spec.UseHotAndColdStorage) + { + if (spec.UseTxAccessLists) + accessTracker.WarmUp(tx.AccessList); // eip-2930 - codeInfo.AnalyseInBackgroundIfRequired(); + accessTracker.WarmUp(recipient); + accessTracker.WarmUp(tx.SenderAddress!); + + if (spec.AddCoinbaseToTxAccessList) + accessTracker.WarmUp(blCtx.Header.GasBeneficiary!); + + //We assume eip-7702 must be active if it is a delegation + if (delegationAddress is not null) + accessTracker.WarmUp(delegationAddress); + } ReadOnlyMemory inputData = tx.IsMessageCall ? tx.Data ?? default : default; @@ -575,7 +596,7 @@ protected virtual void ExecuteEvmCall( ITxTracer tracer, ExecutionOptions opts, int delegationRefunds, - IEnumerable
accessedAddresses, + in StackAccessTracker accessedItems, in long gasAvailable, in ExecutionEnvironment env, out TransactionSubstate? substate, @@ -605,11 +626,13 @@ protected virtual void ExecuteEvmCall( } } - ExecutionType executionType = tx.IsContractCreation ? ExecutionType.CREATE : ExecutionType.TRANSACTION; - - using (EvmState state = new(unspentGas, env, executionType, true, snapshot, false)) + using (EvmState state = new EvmState( + unspentGas, + env, + tx.IsContractCreation ? ExecutionType.CREATE : ExecutionType.TRANSACTION, + snapshot, + accessedItems)) { - WarmUp(tx, header, spec, state, accessedAddresses); substate = !tracer.IsTracingActions ? VirtualMachine.Run(state, WorldState, tracer) @@ -619,7 +642,7 @@ protected virtual void ExecuteEvmCall( if (tracer.IsTracingAccess) { - tracer.ReportAccess(state.AccessedAddresses, state.AccessedStorageCells); + tracer.ReportAccess(state.AccessTracker.AccessedAddresses, state.AccessTracker.AccessedStorageCells); } } @@ -690,27 +713,6 @@ protected virtual void PayValue(Transaction tx, IReleaseSpec spec, ExecutionOpti WorldState.SubtractFromBalance(tx.SenderAddress!, tx.Value, spec); } - private void WarmUp(Transaction tx, BlockHeader header, IReleaseSpec spec, EvmState state, IEnumerable
accessedAddresses) - { - if (spec.UseTxAccessLists) - { - state.WarmUp(tx.AccessList); // eip-2930 - } - - if (spec.UseHotAndColdStorage) // eip-2929 - { - foreach (Address accessed in accessedAddresses) - { - state.WarmUp(accessed); - } - } - - if (spec.AddCoinbaseToTxAccessList) - { - state.WarmUp(header.GasBeneficiary!); - } - } - protected virtual void PayFees(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, in TransactionSubstate substate, in long spentGas, in UInt256 premiumPerGas, in UInt256 blobBaseFee, in byte statusCode) { bool gasBeneficiaryNotDestroyed = substate?.DestroyList.Contains(header.GasBeneficiary) != true; diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index b9fa6506d3c..3a8677da6be 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -315,8 +315,8 @@ public TransactionSubstate Run(EvmState state, IWorldState worl return new TransactionSubstate( callResult.Output, currentState.Refund, - (IReadOnlyCollection
)currentState.DestroyList, - (IReadOnlyCollection)currentState.Logs, + currentState.AccessTracker.DestroyList, + (IReadOnlyCollection)currentState.AccessTracker.Logs, callResult.ShouldRevert, isTracerConnected: isTracing, _logger); @@ -510,13 +510,13 @@ bool ChargeAccountGas(ref long gasAvailable, EvmState vmState, Address address, bool result = true; if (_txTracer.IsTracingAccess) // when tracing access we want cost as if it was warmed up from access list { - vmState.WarmUp(address); + vmState.AccessTracker.WarmUp(address); } - if (vmState.IsCold(address) && !address.IsPrecompile(spec)) + if (vmState.AccessTracker.IsCold(address) && !address.IsPrecompile(spec)) { result = UpdateGas(GasCostOf.ColdAccountAccess, ref gasAvailable); - vmState.WarmUp(address); + vmState.AccessTracker.WarmUp(address); } else if (chargeForWarm) { @@ -546,13 +546,13 @@ private bool ChargeStorageAccessGas( { if (_txTracer.IsTracingAccess) // when tracing access we want cost as if it was warmed up from access list { - vmState.WarmUp(in storageCell); + vmState.AccessTracker.WarmUp(in storageCell); } - if (vmState.IsCold(in storageCell)) + if (vmState.AccessTracker.IsCold(in storageCell)) { result = UpdateGas(GasCostOf.ColdSLoad, ref gasAvailable); - vmState.WarmUp(in storageCell); + vmState.AccessTracker.WarmUp(in storageCell); } else if (storageAccessType == StorageAccessType.SLOAD) { @@ -2236,13 +2236,11 @@ private EvmExceptionType InstructionCall( gasLimitUl, callEnv, executionType, - isTopLevel: false, snapshot, outputOffset.ToLong(), outputLength.ToLong(), instruction == Instruction.STATICCALL || vmState.IsStatic, - vmState, - isContinuation: false, + vmState.AccessTracker, isCreateOnPreExistingAccount: false); return EvmExceptionType.None; @@ -2324,9 +2322,9 @@ private EvmExceptionType InstructionSelfDestruct(EvmState vmState, ref if (!ChargeAccountAccessGas(ref gasAvailable, vmState, inheritor, false, spec, false)) return EvmExceptionType.OutOfGas; Address executingAccount = vmState.Env.ExecutingAccount; - bool createInSameTx = vmState.CreateList.Contains(executingAccount); + bool createInSameTx = vmState.AccessTracker.CreateList.Contains(executingAccount); if (!spec.SelfdestructOnlyOnSameTransaction || createInSameTx) - vmState.DestroyList.Add(executingAccount); + vmState.AccessTracker.ToBeDestroyed(executingAccount); UInt256 result = _state.GetBalance(executingAccount); if (_txTracer.IsTracingActions) _txTracer.ReportSelfDestruct(executingAccount, result, inheritor); @@ -2437,7 +2435,7 @@ private EvmExceptionType InstructionSelfDestruct(EvmState vmState, ref if (spec.UseHotAndColdStorage) { // EIP-2929 assumes that warm-up cost is included in the costs of CREATE and CREATE2 - vmState.WarmUp(contractAddress); + vmState.AccessTracker.WarmUp(contractAddress); } _state.IncrementNonce(env.ExecutingAccount); @@ -2484,13 +2482,11 @@ private EvmExceptionType InstructionSelfDestruct(EvmState vmState, ref callGas, callEnv, instruction == Instruction.CREATE2 ? ExecutionType.CREATE2 : ExecutionType.CREATE, - false, snapshot, 0L, 0L, vmState.IsStatic, - vmState, - false, + vmState.AccessTracker, accountExists); return (EvmExceptionType.None, callState); @@ -2519,7 +2515,7 @@ private EvmExceptionType InstructionLog(EvmState vmState, ref EvmStack vmState.Env.ExecutingAccount, data.ToArray(), topics); - vmState.Logs.Add(logEntry); + vmState.AccessTracker.Logs.Add(logEntry); if (_txTracer.IsTracingLogs) { diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateVirtualMachine.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateVirtualMachine.cs index 5ea81093e80..f6b70140320 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateVirtualMachine.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateVirtualMachine.cs @@ -14,7 +14,7 @@ public TransactionSubstate Run(EvmState state, IWorldState worl { if (typeof(TTracingActions) == typeof(VirtualMachine.IsTracing) && TryGetLogsMutator(txTracer, out ITxLogsMutator logsMutator)) { - logsMutator.SetLogsToMutate(state.Logs); + logsMutator.SetLogsToMutate(state.AccessTracker.Logs); } return virtualMachine.Run(state, worldState, txTracer);