Skip to content

StorageValue #8482

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 43 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e8be057
StorageValue introduced
Scooletz Apr 8, 2025
9e9e68a
more by ref
Scooletz Apr 8, 2025
ef5cbb8
spacing
Scooletz Apr 8, 2025
4e67b16
compile
Scooletz Apr 8, 2025
e994649
base test fixed
Scooletz Apr 8, 2025
2e42d7f
comparison fixed
Scooletz Apr 8, 2025
95ccb5c
healing test fixed
Scooletz Apr 8, 2025
10f6ccd
tostring
Scooletz Apr 8, 2025
17acda8
resolution
Scooletz Apr 8, 2025
2bd79b4
force update on after equal to zero
Scooletz Apr 8, 2025
dfeef27
fixed test
Scooletz Apr 8, 2025
c392731
Merge branch 'master' into storage-value
benaadams Apr 9, 2025
2fd44e2
hash store amendment
Scooletz Apr 10, 2025
c19e0ff
uint256 property
Scooletz Apr 10, 2025
b9a0cab
Merge branch 'storage-value' of https://github.com/NethermindEth/neth…
Scooletz Apr 10, 2025
349c065
direct stack push
Scooletz Apr 10, 2025
6415c2d
sstore amended
Scooletz Apr 10, 2025
0e4313c
Trailing zero bytes made 2x faster
Scooletz Apr 10, 2025
c56e1dd
trailing zeros fixed
Scooletz Apr 10, 2025
478d678
benchmarks redone
Scooletz Apr 11, 2025
276bad6
tracers
Scooletz Apr 11, 2025
17a830b
benchmark moved
Scooletz Apr 11, 2025
5f42613
benchmarks for storage retrieval
Scooletz Apr 11, 2025
730b2ea
by pointer
Scooletz Apr 15, 2025
e4a4f8e
updates
Scooletz Apr 15, 2025
36a8eb0
local allocation
Scooletz Apr 16, 2025
bd6296c
memory reuse
Scooletz Apr 17, 2025
a9bb991
merged
Scooletz Apr 17, 2025
bdfae5b
minors
Scooletz Apr 17, 2025
0ca0013
no materliazation for sstore
Scooletz Apr 17, 2025
f461292
epoch based storage value map
Scooletz Apr 23, 2025
262988d
StorageValueMap is concurrent and is used in a concurrent way
Scooletz Apr 23, 2025
7357f67
benchmarks
Scooletz Apr 23, 2025
82e04bc
benchmark
Scooletz Apr 24, 2025
36facc5
updated bench
Scooletz Apr 24, 2025
5d01e5a
mapping made smaller
Scooletz Apr 24, 2025
0708319
Merge branch 'master' into storage-value
Scooletz Apr 24, 2025
a77cfcb
coarse grained benchmark
Scooletz Apr 25, 2025
a613c9e
Merge branch 'master' into storage-value
Scooletz Apr 25, 2025
7211928
benchmark fix
Scooletz Apr 25, 2025
ec123b2
review remarks addressed
Scooletz Apr 28, 2025
6577982
Merge branch 'master' into storage-value
Scooletz Apr 28, 2025
0fa3463
Merge branch 'master' into storage-value
benaadams Apr 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -362,24 +362,24 @@ private List<string> RunAssertions(BlockchainTest test, Block headBlock, IWorldS
differencesBefore = differences.Count;

KeyValuePair<UInt256, byte[]>[] clearedStorages = new KeyValuePair<UInt256, byte[]>[0];
if (test.Pre.ContainsKey(acountAddress))
if (test.Pre.TryGetValue(acountAddress, out var v))
{
clearedStorages = test.Pre[acountAddress].Storage.Where(s => !accountState.Storage.ContainsKey(s.Key)).ToArray();
clearedStorages = v.Storage.Where(s => !accountState.Storage.ContainsKey(s.Key)).ToArray();
}

foreach (KeyValuePair<UInt256, byte[]> clearedStorage in clearedStorages)
{
ReadOnlySpan<byte> value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key));
if (!value.IsZero())
StorageValue value = !stateProvider.AccountExists(acountAddress) ? StorageValue.Zero : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key));
if (!value.IsZero)
{
differences.Add($"{acountAddress} storage[{clearedStorage.Key}] exp: 0x00, actual: {value.ToHexString(true)}");
}
}

foreach (KeyValuePair<UInt256, byte[]> storageItem in accountState.Storage)
{
ReadOnlySpan<byte> value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key));
if (!Bytes.AreEqual(storageItem.Value, value))
StorageValue value = !stateProvider.AccountExists(acountAddress) ? StorageValue.Zero : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key));
if (!new StorageValue(storageItem.Value).Equals(value))
{
differences.Add($"{acountAddress} storage[{storageItem.Key}] exp: {storageItem.Value.ToHexString(true)}, actual: {value.ToHexString(true)}");
}
Expand Down
60 changes: 31 additions & 29 deletions src/Nethermind/Nethermind.Benchmark.Runner/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Linq;
using BenchmarkDotNet.Toolchains.InProcess.NoEmit;
using BenchmarkDotNet.Columns;
using Nethermind.Evm.Benchmark;
using Nethermind.Precompiles.Benchmark;

namespace Nethermind.Benchmark.Runner
Expand Down Expand Up @@ -48,35 +49,36 @@ public static class Program
{
public static void Main(string[] args)
{
List<Assembly> additionalJobAssemblies = [
typeof(JsonRpc.Benchmark.EthModuleBenchmarks).Assembly,
typeof(Benchmarks.Core.Keccak256Benchmarks).Assembly,
typeof(Evm.Benchmark.EvmStackBenchmarks).Assembly,
typeof(Network.Benchmarks.DiscoveryBenchmarks).Assembly,
];

List<Assembly> simpleJobAssemblies = [
// typeof(EthereumTests.Benchmark.EthereumTests).Assembly,
];

if (Debugger.IsAttached)
{
BenchmarkSwitcher.FromAssemblies(additionalJobAssemblies.Union(simpleJobAssemblies).ToArray()).RunAll(new DebugInProcessConfig());
}
else
{
foreach (Assembly assembly in additionalJobAssemblies)
{
BenchmarkRunner.Run(assembly, new DashboardConfig(Job.MediumRun.WithRuntime(CoreRuntime.Core90)), args);
}

foreach (Assembly assembly in simpleJobAssemblies)
{
BenchmarkRunner.Run(assembly, new DashboardConfig(), args);
}

BenchmarkRunner.Run(typeof(KeccakBenchmark).Assembly, new PrecompileBenchmarkConfig(), args);
}
BenchmarkRunner.Run(typeof(StorageValueBenchmarks));
// List<Assembly> additionalJobAssemblies = [
// typeof(JsonRpc.Benchmark.EthModuleBenchmarks).Assembly,
// typeof(Benchmarks.Core.Keccak256Benchmarks).Assembly,
// typeof(Evm.Benchmark.EvmStackBenchmarks).Assembly,
// typeof(Network.Benchmarks.DiscoveryBenchmarks).Assembly,
// ];
//
// List<Assembly> simpleJobAssemblies = [
// // typeof(EthereumTests.Benchmark.EthereumTests).Assembly,
// ];
//
// if (Debugger.IsAttached)
// {
// BenchmarkSwitcher.FromAssemblies(additionalJobAssemblies.Union(simpleJobAssemblies).ToArray()).RunAll(new DebugInProcessConfig());
// }
// else
// {
// foreach (Assembly assembly in additionalJobAssemblies)
// {
// BenchmarkRunner.Run(assembly, new DashboardConfig(Job.MediumRun.WithRuntime(CoreRuntime.Core90)), args);
// }
//
// foreach (Assembly assembly in simpleJobAssemblies)
// {
// BenchmarkRunner.Run(assembly, new DashboardConfig(), args);
// }
//
// BenchmarkRunner.Run(typeof(KeccakBenchmark).Assembly, new PrecompileBenchmarkConfig(), args);
// }
}
}
}
8 changes: 3 additions & 5 deletions src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ namespace Nethermind.Blockchain.Blocks;
public class BlockhashStore(ISpecProvider specProvider, IWorldState worldState)
: IBlockhashStore
{
private static readonly byte[] EmptyBytes = [0];

public void ApplyBlockhashStateChanges(BlockHeader blockHeader)
{
IReleaseSpec spec = specProvider.GetSpec(blockHeader);
Expand All @@ -30,7 +28,7 @@ public void ApplyBlockhashStateChanges(BlockHeader blockHeader)
Hash256 parentBlockHash = blockHeader.ParentHash;
var parentBlockIndex = new UInt256((ulong)((blockHeader.Number - 1) % Eip2935Constants.RingBufferSize));
StorageCell blockHashStoreCell = new(eip2935Account, parentBlockIndex);
worldState.Set(blockHashStoreCell, parentBlockHash!.Bytes.WithoutLeadingZeros().ToArray());
worldState.Set(blockHashStoreCell, new StorageValue(parentBlockHash!.Bytes));
}

public Hash256? GetBlockHashFromState(BlockHeader currentHeader, long requiredBlockNumber)
Expand All @@ -44,7 +42,7 @@ public void ApplyBlockhashStateChanges(BlockHeader blockHeader)
var blockIndex = new UInt256((ulong)(requiredBlockNumber % Eip2935Constants.RingBufferSize));
Address? eip2935Account = spec.Eip2935ContractAddress ?? Eip2935Constants.BlockHashHistoryAddress;
StorageCell blockHashStoreCell = new(eip2935Account, blockIndex);
ReadOnlySpan<byte> data = worldState.Get(blockHashStoreCell);
return data.SequenceEqual(EmptyBytes) ? null : Hash256.FromBytesWithPadding(data);
ref readonly StorageValue data = ref worldState.Get(blockHashStoreCell);
return data.IsZero ? null : Hash256.FromBytesWithPadding(data.Bytes);
}
}
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Blockchain/GenesisLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ private void Preallocate(Block genesis)
foreach (KeyValuePair<UInt256, byte[]> storage in allocation.Storage)
{
_stateProvider.Set(new StorageCell(address, storage.Key),
storage.Value.WithoutLeadingZeros().ToArray());
new StorageValue(storage.Value));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ protected virtual async Task<TestBlockchain> Build(Action<ContainerBuilder>? con
byte[] code = Bytes.FromHexString("0xabcd");
state.InsertCode(TestItem.AddressA, code, SpecProvider.GenesisSpec);

state.Set(new StorageCell(TestItem.AddressA, UInt256.One), Bytes.FromHexString("0xabcdef"));
state.Set(new StorageCell(TestItem.AddressA, UInt256.One), new StorageValue(Bytes.FromHexString("0xabcdef")));

state.Commit(SpecProvider.GenesisSpec);
state.CommitTree(0);
Expand Down
40 changes: 40 additions & 0 deletions src/Nethermind/Nethermind.Evm.Benchmark/StorageValueBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using BenchmarkDotNet.Attributes;
using Nethermind.State;

namespace Nethermind.Evm.Benchmark;

public class StorageValueBenchmarks
{
[Benchmark(OperationsPerInvoke = 8)]
[Arguments(0)]
[Arguments(1)]
[Arguments(8)]
[Arguments(9)]
[Arguments(17)]
[Arguments(18)]
[Arguments(23)]
[Arguments(24)]
[Arguments(31)]
public int LeadingZeros(int nonZero)
{
Span<byte> span = stackalloc byte[32];
span[nonZero] = 1;

var v = new StorageValue(span);

return
v.BytesWithNoLeadingZeroes.Length +
v.BytesWithNoLeadingZeroes.Length +
v.BytesWithNoLeadingZeroes.Length +
v.BytesWithNoLeadingZeroes.Length +

v.BytesWithNoLeadingZeroes.Length +
v.BytesWithNoLeadingZeroes.Length +
v.BytesWithNoLeadingZeroes.Length +
v.BytesWithNoLeadingZeroes.Length;
}
}
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public void Test_out_of_gas_existing_account_with_storage()
Address expectedAddress = ContractAddress.From(TestItem.AddressC, salt.PadLeft(32).AsSpan(), initCode.AsSpan());

TestState.CreateAccount(expectedAddress, 1.Ether());
TestState.Set(new StorageCell(expectedAddress, 1), new byte[] { 1, 2, 3, 4, 5 });
TestState.Set(new StorageCell(expectedAddress, 1), new StorageValue([1, 2, 3, 4, 5]));
TestState.Commit(Spec);
TestState.CommitTree(0);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public void Execute_TxHasAuthorizationWithCodeThatSavesCallerAddress_ExpectedAdd

_transactionProcessor.Execute(tx, new BlockExecutionContext(block.Header, _specProvider.GetSpec(block.Header)), NullTxTracer.Instance);

ReadOnlySpan<byte> cell = _stateProvider.Get(new StorageCell(signer.Address, 0));
StorageValue cell = _stateProvider.Get(new StorageCell(signer.Address, 0));

Assert.That(new Address(cell.ToArray()), Is.EqualTo(sender.Address));
}
Expand Down Expand Up @@ -154,7 +154,7 @@ public void Execute_SenderAndSignerIsTheSameOrNotWithCodeThatSavesCallerAddress_

_transactionProcessor.Execute(tx, new BlockExecutionContext(block.Header, _specProvider.GetSpec(block.Header)), NullTxTracer.Instance);

ReadOnlySpan<byte> cellValue = _stateProvider.Get(new StorageCell(signer.Address, 0));
StorageValue cellValue = _stateProvider.Get(new StorageCell(signer.Address, 0));

Assert.That(cellValue.ToArray(), Is.EqualTo(sender.Address.Bytes));
}
Expand Down Expand Up @@ -636,7 +636,7 @@ public void Execute_CodeSavesEXTCODEHASHWhenAccountIsDelegatedOrNot_SavesExpecte
.WithGasLimit(10000000).TestObject;
_ = _transactionProcessor.Execute(tx, new BlockExecutionContext(block.Header, _specProvider.GetSpec(block.Header)), NullTxTracer.Instance);

ReadOnlySpan<byte> actual = _stateProvider.Get(new StorageCell(codeSource, 0));
StorageValue actual = _stateProvider.Get(new StorageCell(codeSource, 0));
Assert.That(actual.ToArray(), Is.EquivalentTo(expected));
}
public static IEnumerable<object[]> AccountAccessGasCases()
Expand Down
6 changes: 3 additions & 3 deletions src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -345,17 +345,17 @@ protected void AssertGas(TestAllTracerWithOutput receipt, long gas)

protected void AssertStorage(UInt256 address, Address value)
{
Assert.That(TestState.Get(new StorageCell(Recipient, address)).PadLeft(32), Is.EqualTo(value.Bytes.PadLeft(32)), "storage");
Assert.That(TestState.Get(new StorageCell(Recipient, address)).Bytes.ToArray(), Is.EqualTo(value.Bytes.PadLeft(32)), "storage");
}

protected void AssertStorage(UInt256 address, Hash256 value)
{
Assert.That(TestState.Get(new StorageCell(Recipient, address)).PadLeft(32), Is.EqualTo(value.BytesToArray()), "storage");
Assert.That(TestState.Get(new StorageCell(Recipient, address)).Bytes.ToArray(), Is.EqualTo(value.BytesToArray()), "storage");
}

protected void AssertStorage(UInt256 address, ReadOnlySpan<byte> value)
{
Assert.That(TestState.Get(new StorageCell(Recipient, address)).PadLeft(32), Is.EqualTo(new ZeroPaddedSpan(value, 32 - value.Length, PadDirection.Left).ToArray()), "storage");
Assert.That(TestState.Get(new StorageCell(Recipient, address)).Bytes.ToArray(), Is.EqualTo(new ZeroPaddedSpan(value, 32 - value.Length, PadDirection.Left).ToArray()), "storage");
}

protected void AssertStorage(UInt256 address, BigInteger expectedValue)
Expand Down
8 changes: 4 additions & 4 deletions src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ public void Regression_mainnet_6108276()
.Done;

TestAllTracerWithOutput receipt = Execute(code);
byte[] result = TestState.Get(storageCell).ToArray();
byte[] result = TestState.Get(storageCell).BytesWithNoLeadingZeroes.ToArray();
Assert.That(result, Is.EqualTo(new byte[] { 0 }), "storage reverted");
Assert.That(receipt.GasSpent, Is.EqualTo(98777), "no refund");

byte[] returnData = TestState.Get(new StorageCell(TestItem.AddressC, 0)).ToArray();
byte[] returnData = TestState.Get(new StorageCell(TestItem.AddressC, 0)).BytesWithNoLeadingZeroes.ToArray();
Assert.That(returnData, Is.EqualTo(new byte[1]), "address returned");
}

Expand Down Expand Up @@ -96,11 +96,11 @@ public void Regression_mainnet_226522()
.Done;

TestAllTracerWithOutput receipt = Execute(code);
byte[] result = TestState.Get(storageCell).ToArray();
byte[] result = TestState.Get(storageCell).BytesWithNoLeadingZeroes.ToArray();
Assert.That(result, Is.EqualTo(new byte[] { 0 }), "storage reverted");
Assert.That(receipt.GasSpent, Is.EqualTo(83199), "with refund");

byte[] returnData = TestState.Get(new StorageCell(TestItem.AddressC, 0)).ToArray();
byte[] returnData = TestState.Get(new StorageCell(TestItem.AddressC, 0)).BytesWithNoLeadingZeroes.ToArray();
Assert.That(returnData, Is.EqualTo(deployed.Bytes), "address returned");
}
}
Expand Down
13 changes: 13 additions & 0 deletions src/Nethermind/Nethermind.Evm/EvmStack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.Diagnostics;
using System.Runtime.Intrinsics.X86;
using Nethermind.Core.Extensions;
using Nethermind.State;

namespace Nethermind.Evm;

Expand Down Expand Up @@ -51,6 +52,18 @@ public ref byte PushBytesRef()
return ref Unsafe.Add(ref MemoryMarshal.GetReference(_bytes), head * WordSize);
}

/// <summary>
/// An optimized version of the push, accepting directly <see cref="StorageValue"/>
/// and using it's size alignment with the stack.
/// </summary>
public void PushBytes(in StorageValue value)
{
if (typeof(TTracing) == typeof(IsTracing)) _tracer.ReportStackPush(value.BytesWithNoLeadingZeroes);

ref byte bytes = ref PushBytesRef();
Unsafe.As<byte, Word>(ref bytes) = value.UnsafeRef;
}

public void PushBytes(scoped ReadOnlySpan<byte> value)
{
if (typeof(TTracing) == typeof(IsTracing)) _tracer.ReportStackPush(value);
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Evm/StateOverridesExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ void ApplyState(Dictionary<UInt256, Hash256> diff)
{
foreach ((UInt256 index, Hash256 value) in diff)
{
stateProvider.Set(new StorageCell(address, index), value.Bytes.WithoutLeadingZeros().ToArray());
stateProvider.Set(new StorageCell(address, index), new StorageValue(value.Bytes));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ public ITypedArray<byte> getState(object address, object hash)
{
using var handle = ArrayPoolDisposableReturn.Rent(32, out byte[] array);

ReadOnlySpan<byte> bytes = WorldState.Get(new StorageCell(address.ToAddress(), hash.GetHash()));
StorageValue v = WorldState.Get(new StorageCell(address.ToAddress(), hash.GetHash()));
var bytes = v.BytesWithNoLeadingZeroes;

if (bytes.Length < array.Length)
{
Array.Clear(array);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ private void LookupStorage(Address addr, UInt256 index)

if (!account.Storage.ContainsKey(index))
{
UInt256 storage = new(_worldState!.Get(new StorageCell(addr, index)), true);
UInt256 storage = new(_worldState!.Get(new StorageCell(addr, index)).BytesWithNoLeadingZeroes, true);
account.Storage.Add(index, storage);
}
}
Expand Down Expand Up @@ -259,7 +259,7 @@ private void ProcessDiffState()
if (prestateStorage.IsZero)
prestateAccount.Storage.Remove(index);

UInt256 poststateStorage = new(_worldState!.Get(new StorageCell(addr, index)), true);
UInt256 poststateStorage = new(_worldState!.Get(new StorageCell(addr, index)).BytesWithNoLeadingZeroes, true);
if (!prestateStorage.Equals(poststateStorage))
{
modified = true;
Expand Down
Loading
Loading