From def608fbecbfc4456dffdf136c035d16ca1311de Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Tue, 23 Jan 2024 22:48:11 +0100 Subject: [PATCH 01/16] hunting allocations --- .../Nethermind.Analytics/SupplyVerifier.cs | 3 +- .../FullPruning/CopyTreeVisitor.cs | 4 +- .../Receipts/KeccaksIterator.cs | 2 +- .../Receipts/LogEntriesIterator.cs | 2 +- src/Nethermind/Nethermind.Core/Address.cs | 4 +- src/Nethermind/Nethermind.Core/Bloom.cs | 56 +------------------ .../Nethermind.Core/Crypto/Hash256.cs | 4 +- .../Nethermind.Core/IKeyValueStore.cs | 2 +- .../KeyValueStoreExtensions.cs | 2 +- src/Nethermind/Nethermind.Core/LogEntry.cs | 6 +- .../Nethermind.Core/TransactionReceipt.cs | 2 +- .../Nethermind.Db.Rocks/ColumnDb.cs | 2 +- .../Nethermind.Db.Rocks/DbOnTheRocks.cs | 2 +- src/Nethermind/Nethermind.Db.Rpc/RpcDb.cs | 2 +- src/Nethermind/Nethermind.Db/MemDb.cs | 2 +- src/Nethermind/Nethermind.Db/ReadOnlyDb.cs | 2 +- .../Modules/Proof/ProofRpcModuleTests.cs | 5 +- .../AccountDecoder.cs | 54 +++++++++++++++++- .../CompactReceiptStorageDecoder.cs | 2 +- .../IRlpDecoder.cs | 11 ++++ .../ReceiptStorageDecoder.cs | 2 +- .../Nethermind.Serialization.Rlp/Rlp.cs | 40 +++++++------ .../Nethermind.Serialization.Rlp/TxDecoder.cs | 4 +- .../Proofs/AccountProofCollector.cs | 2 +- .../Nethermind.State/Proofs/ProofCollector.cs | 2 +- .../Nethermind.State/Proofs/ProofVerifier.cs | 5 +- .../FastSync/TreeSync.cs | 2 +- .../Nethermind.Trie/ITreeVisitor.cs | 3 +- .../Nethermind.Trie/RootCheckVisitor.cs | 3 +- src/Nethermind/Nethermind.Trie/TreeDumper.cs | 8 ++- .../Nethermind.Trie/TrieNode.Visitor.cs | 4 +- .../Nethermind.Trie/TrieStatsCollector.cs | 2 +- 32 files changed, 135 insertions(+), 111 deletions(-) diff --git a/src/Nethermind/Nethermind.Analytics/SupplyVerifier.cs b/src/Nethermind/Nethermind.Analytics/SupplyVerifier.cs index 239f76c1600..d5f56556674 100644 --- a/src/Nethermind/Nethermind.Analytics/SupplyVerifier.cs +++ b/src/Nethermind/Nethermind.Analytics/SupplyVerifier.cs @@ -1,6 +1,7 @@ // 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.Crypto; @@ -78,7 +79,7 @@ public void VisitExtension(TrieNode node, TrieVisitContext trieVisitContext) } } - public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, byte[] value = null) + public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value) { _nodesVisited++; diff --git a/src/Nethermind/Nethermind.Blockchain/FullPruning/CopyTreeVisitor.cs b/src/Nethermind/Nethermind.Blockchain/FullPruning/CopyTreeVisitor.cs index cd411837ed0..152747e523b 100644 --- a/src/Nethermind/Nethermind.Blockchain/FullPruning/CopyTreeVisitor.cs +++ b/src/Nethermind/Nethermind.Blockchain/FullPruning/CopyTreeVisitor.cs @@ -69,7 +69,7 @@ public void VisitMissingNode(Hash256 nodeHash, TrieVisitContext trieVisitContext public void VisitExtension(TrieNode node, TrieVisitContext trieVisitContext) => PersistNode(node); - public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, byte[]? value = null) => PersistNode(node); + public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value) => PersistNode(node); public void VisitCode(Hash256 codeHash, TrieVisitContext trieVisitContext) { } @@ -78,7 +78,7 @@ private void PersistNode(TrieNode node) if (node.Keccak is not null) { // simple copy of nodes RLP - _pruningContext.Set(node.Keccak.Bytes, node.FullRlp.ToArray(), _writeFlags); + _pruningContext.PutSpan(node.Keccak.Bytes, node.FullRlp.AsSpan(), _writeFlags); Interlocked.Increment(ref _persistedNodes); // log message every 1 mln nodes diff --git a/src/Nethermind/Nethermind.Blockchain/Receipts/KeccaksIterator.cs b/src/Nethermind/Nethermind.Blockchain/Receipts/KeccaksIterator.cs index c346a4300c1..e883f6d5616 100644 --- a/src/Nethermind/Nethermind.Blockchain/Receipts/KeccaksIterator.cs +++ b/src/Nethermind/Nethermind.Blockchain/Receipts/KeccaksIterator.cs @@ -15,7 +15,7 @@ public ref struct KeccaksIterator private readonly Span _buffer; public long Index { get; private set; } - public KeccaksIterator(Span data, Span buffer) + public KeccaksIterator(ReadOnlySpan data, Span buffer) { if (buffer.Length != 32) throw new ArgumentException("Buffer must be 32 bytes long"); _decoderContext = new Rlp.ValueDecoderContext(data); diff --git a/src/Nethermind/Nethermind.Blockchain/Receipts/LogEntriesIterator.cs b/src/Nethermind/Nethermind.Blockchain/Receipts/LogEntriesIterator.cs index 62a1cfff39f..0a20a36ea88 100644 --- a/src/Nethermind/Nethermind.Blockchain/Receipts/LogEntriesIterator.cs +++ b/src/Nethermind/Nethermind.Blockchain/Receipts/LogEntriesIterator.cs @@ -15,7 +15,7 @@ public ref struct LogEntriesIterator private readonly IReceiptRefDecoder _receiptRefDecoder; public long Index { get; private set; } - public LogEntriesIterator(Span data, IReceiptRefDecoder receiptRefDecoder) + public LogEntriesIterator(ReadOnlySpan data, IReceiptRefDecoder receiptRefDecoder) { _decoderContext = new Rlp.ValueDecoderContext(data); _length = _decoderContext.ReadSequenceLength(); diff --git a/src/Nethermind/Nethermind.Core/Address.cs b/src/Nethermind/Nethermind.Core/Address.cs index 98b1e919b72..817d5600e76 100644 --- a/src/Nethermind/Nethermind.Core/Address.cs +++ b/src/Nethermind/Nethermind.Core/Address.cs @@ -235,7 +235,7 @@ public ref struct AddressStructRef private const int HexCharsCount = 2 * ByteLength; // 5a4eab120fb44eb6684e5e32785702ff45ea344d private const int PrefixedHexCharsCount = 2 + HexCharsCount; // 0x5a4eab120fb44eb6684e5e32785702ff45ea344d - public Span Bytes { get; } + public ReadOnlySpan Bytes { get; } public AddressStructRef(Hash256StructRef keccak) : this(keccak.Bytes.Slice(12, ByteLength)) { } @@ -274,7 +274,7 @@ public static bool IsValidAddress(string hexString, bool allowPrefix) public AddressStructRef(string hexString) : this(Extensions.Bytes.FromHexString(hexString)) { } - public AddressStructRef(Span bytes) + public AddressStructRef(ReadOnlySpan bytes) { if (bytes.Length != ByteLength) { diff --git a/src/Nethermind/Nethermind.Core/Bloom.cs b/src/Nethermind/Nethermind.Core/Bloom.cs index 8624a3a69a7..9d2ba871539 100644 --- a/src/Nethermind/Nethermind.Core/Bloom.cs +++ b/src/Nethermind/Nethermind.Core/Bloom.cs @@ -229,37 +229,12 @@ public ref struct BloomStructRef public const int BitLength = 2048; public const int ByteLength = BitLength / 8; - public BloomStructRef(LogEntry[] logEntries, Bloom? blockBloom = null) - { - Bytes = new byte[ByteLength]; - Add(logEntries, blockBloom); - } - - public BloomStructRef(Span bytes) + public BloomStructRef(ReadOnlySpan bytes) { Bytes = bytes; } - public Span Bytes { get; } - - public void Set(ReadOnlySpan sequence) - { - Set(sequence, null); - } - - private readonly void Set(ReadOnlySpan sequence, Bloom? masterBloom = null) - { - Bloom.BloomExtract indexes = GetExtract(sequence); - Set(indexes.Index1); - Set(indexes.Index2); - Set(indexes.Index3); - if (masterBloom is not null) - { - masterBloom.Set(indexes.Index1); - masterBloom.Set(indexes.Index2); - masterBloom.Set(indexes.Index3); - } - } + public ReadOnlySpan Bytes { get; } public bool Matches(ReadOnlySpan sequence) { @@ -306,26 +281,6 @@ public override readonly int GetHashCode() return Core.Extensions.Bytes.GetSimplifiedHashCode(Bytes); } - public void Add(LogEntry[] logEntries, Bloom? blockBloom) - { - for (int entryIndex = 0; entryIndex < logEntries.Length; entryIndex++) - { - LogEntry logEntry = logEntries[entryIndex]; - byte[] addressBytes = logEntry.LoggersAddress.Bytes; - Set(addressBytes, blockBloom); - for (int topicIndex = 0; topicIndex < logEntry.Topics.Length; topicIndex++) - { - Hash256 topic = logEntry.Topics[topicIndex]; - Set(topic.Bytes, blockBloom); - } - } - } - - public readonly void Accumulate(BloomStructRef bloom) - { - Bytes.Or(bloom.Bytes); - } - public bool Matches(LogEntry logEntry) { if (Matches(logEntry.LoggersAddress)) @@ -351,13 +306,6 @@ private readonly bool Get(int index) return Bytes[bytePosition].GetBit(shift); } - private readonly void Set(int index) - { - int bytePosition = index / 8; - int shift = index % 8; - Bytes[bytePosition].SetBit(shift); - } - public bool Matches(Address address) => Matches(address.Bytes); public bool Matches(Hash256 topic) => Matches(topic.Bytes); diff --git a/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs b/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs index 65b7f75464f..07aad0b8a3b 100644 --- a/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs +++ b/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs @@ -282,9 +282,9 @@ public ref struct Hash256StructRef public static int MemorySize => MemorySizes.ArrayOverhead + Size; - public Span Bytes { get; } + public ReadOnlySpan Bytes { get; } - public Hash256StructRef(Span bytes) + public Hash256StructRef(ReadOnlySpan bytes) { if (bytes.Length != Size) { diff --git a/src/Nethermind/Nethermind.Core/IKeyValueStore.cs b/src/Nethermind/Nethermind.Core/IKeyValueStore.cs index f205b7cffc1..68271142da0 100644 --- a/src/Nethermind/Nethermind.Core/IKeyValueStore.cs +++ b/src/Nethermind/Nethermind.Core/IKeyValueStore.cs @@ -38,7 +38,7 @@ bool KeyExists(ReadOnlySpan key) return result; } - void DangerousReleaseMemory(in Span span) { } + void DangerousReleaseMemory(in ReadOnlySpan span) { } } public interface IWriteOnlyKeyValueStore diff --git a/src/Nethermind/Nethermind.Core/KeyValueStoreExtensions.cs b/src/Nethermind/Nethermind.Core/KeyValueStoreExtensions.cs index 282e2726f4e..d4f6e4a46cc 100644 --- a/src/Nethermind/Nethermind.Core/KeyValueStoreExtensions.cs +++ b/src/Nethermind/Nethermind.Core/KeyValueStoreExtensions.cs @@ -108,7 +108,7 @@ public static void Set(this IWriteOnlyKeyValueStore db, Hash256 key, in CappedAr { if (value.IsUncapped && db.PreferWriteByArray) { - db.Set(key.Bytes, value.ToArray(), writeFlags); + db.PutSpan(key.Bytes, value.AsSpan(), writeFlags); return; } diff --git a/src/Nethermind/Nethermind.Core/LogEntry.cs b/src/Nethermind/Nethermind.Core/LogEntry.cs index fadecd85f9a..94e22c8323d 100644 --- a/src/Nethermind/Nethermind.Core/LogEntry.cs +++ b/src/Nethermind/Nethermind.Core/LogEntry.cs @@ -22,7 +22,7 @@ public LogEntry(Address address, byte[] data, Hash256[] topics) public ref struct LogEntryStructRef { - public LogEntryStructRef(AddressStructRef address, Span data, Span topicsRlp) + public LogEntryStructRef(AddressStructRef address, ReadOnlySpan data, ReadOnlySpan topicsRlp) { LoggersAddress = address; Data = data; @@ -45,8 +45,8 @@ public LogEntryStructRef(LogEntry logEntry) /// /// Rlp encoded array of Keccak /// - public Span TopicsRlp { get; } + public ReadOnlySpan TopicsRlp { get; } - public Span Data { get; } + public ReadOnlySpan Data { get; } } } diff --git a/src/Nethermind/Nethermind.Core/TransactionReceipt.cs b/src/Nethermind/Nethermind.Core/TransactionReceipt.cs index 5de0b0d85f3..3c0a267201e 100644 --- a/src/Nethermind/Nethermind.Core/TransactionReceipt.cs +++ b/src/Nethermind/Nethermind.Core/TransactionReceipt.cs @@ -83,7 +83,7 @@ public ref struct TxReceiptStructRef /// /// Rlp encoded logs /// - public Span LogsRlp { get; set; } + public ReadOnlySpan LogsRlp { get; set; } public LogEntry[]? Logs { get; set; } diff --git a/src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs b/src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs index f4601b5f0e4..0911f874989 100644 --- a/src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs +++ b/src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs @@ -143,7 +143,7 @@ public void Compact() public long GetIndexSize() => _mainDb.GetIndexSize(); public long GetMemtableSize() => _mainDb.GetMemtableSize(); - public void DangerousReleaseMemory(in Span span) + public void DangerousReleaseMemory(in ReadOnlySpan span) { _mainDb.DangerousReleaseMemory(span); } diff --git a/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs b/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs index 8c707e50326..820ec5d823a 100644 --- a/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs +++ b/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs @@ -609,7 +609,7 @@ public void PutSpan(ReadOnlySpan key, ReadOnlySpan value, WriteFlags SetWithColumnFamily(key, null, value, writeFlags); } - public void DangerousReleaseMemory(in Span span) + public void DangerousReleaseMemory(in ReadOnlySpan span) { if (!span.IsNullOrEmpty()) { diff --git a/src/Nethermind/Nethermind.Db.Rpc/RpcDb.cs b/src/Nethermind/Nethermind.Db.Rpc/RpcDb.cs index c9adaa5b6a8..d0d361d7df1 100644 --- a/src/Nethermind/Nethermind.Db.Rpc/RpcDb.cs +++ b/src/Nethermind/Nethermind.Db.Rpc/RpcDb.cs @@ -114,7 +114,7 @@ public void PutSpan(ReadOnlySpan key, ReadOnlySpan value, WriteFlags Set(key, value.ToArray(), writeFlags); } - public void DangerousReleaseMemory(in Span span) + public void DangerousReleaseMemory(in ReadOnlySpan span) { } } diff --git a/src/Nethermind/Nethermind.Db/MemDb.cs b/src/Nethermind/Nethermind.Db/MemDb.cs index 24a9c820255..25bbaac3819 100644 --- a/src/Nethermind/Nethermind.Db/MemDb.cs +++ b/src/Nethermind/Nethermind.Db/MemDb.cs @@ -118,7 +118,7 @@ public virtual Span GetSpan(ReadOnlySpan key) return Get(key).AsSpan(); } - public void DangerousReleaseMemory(in Span span) + public void DangerousReleaseMemory(in ReadOnlySpan span) { } diff --git a/src/Nethermind/Nethermind.Db/ReadOnlyDb.cs b/src/Nethermind/Nethermind.Db/ReadOnlyDb.cs index 26f1628b720..b4779f856b2 100644 --- a/src/Nethermind/Nethermind.Db/ReadOnlyDb.cs +++ b/src/Nethermind/Nethermind.Db/ReadOnlyDb.cs @@ -108,7 +108,7 @@ public void PutSpan(ReadOnlySpan keyBytes, ReadOnlySpan value, Write _memDb.Set(keyBytes, value.ToArray(), writeFlags); } - public void DangerousReleaseMemory(in Span span) { } + public void DangerousReleaseMemory(in ReadOnlySpan span) { } public bool PreferWriteByArray => true; // Because of memdb buffer } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs index aabb92d9c02..bbd658cc2cd 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs @@ -27,6 +27,7 @@ using NUnit.Framework; using System.Threading.Tasks; using Nethermind.Consensus.Processing; +using Nethermind.Core.Buffers; using Nethermind.State.Tracing; using NSubstitute; @@ -850,8 +851,8 @@ private async Task TestCallWithStorageAndCode(byte[] code, UInt256 gasPrice, Add // the exception will be thrown if the account did not exist before the call try { - byte[] verifyOneProof = ProofVerifier.VerifyOneProof(accountProof.Proof!, block.StateRoot!)!; - new AccountDecoder().Decode(new RlpStream(verifyOneProof)); + CappedArray verifyOneProof = ProofVerifier.VerifyOneProof(accountProof.Proof!, block.StateRoot!); + new AccountDecoder().Decode(verifyOneProof.AsSpan()); } catch (Exception) { diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs index 05a119f5366..41a0c1b876c 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs @@ -7,7 +7,7 @@ namespace Nethermind.Serialization.Rlp { - public class AccountDecoder : IRlpObjectDecoder, IRlpStreamDecoder + public class AccountDecoder : IRlpObjectDecoder, IRlpStreamDecoder, IRlpValueDecoder { private readonly bool _slimFormat; @@ -201,5 +201,57 @@ private Hash256 DecodeCodeHash(RlpStream rlpStream) return codeHash; } + + public Account? Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + int length = decoderContext.ReadSequenceLength(); + if (length == 1) + { + return null; + } + + UInt256 nonce = decoderContext.DecodeUInt256(); + UInt256 balance = decoderContext.DecodeUInt256(); + Hash256 storageRoot = DecodeStorageRoot(ref decoderContext); + Hash256 codeHash = DecodeCodeHash(ref decoderContext); + if (ReferenceEquals(storageRoot, Keccak.EmptyTreeHash) && ReferenceEquals(codeHash, Keccak.OfAnEmptyString)) + { + return new(nonce, balance); + } + + return new(nonce, balance, storageRoot, codeHash); + } + + private Hash256 DecodeStorageRoot(ref Rlp.ValueDecoderContext rlpStream) + { + Hash256 storageRoot; + if (_slimFormat && rlpStream.IsNextItemEmptyArray()) + { + rlpStream.ReadByte(); + storageRoot = Keccak.EmptyTreeHash; + } + else + { + storageRoot = rlpStream.DecodeKeccak(); + } + + return storageRoot; + } + + private Hash256 DecodeCodeHash(ref Rlp.ValueDecoderContext rlpStream) + { + Hash256 codeHash; + if (_slimFormat && rlpStream.IsNextItemEmptyArray()) + { + rlpStream.ReadByte(); + codeHash = Keccak.OfAnEmptyString; + } + else + { + codeHash = rlpStream.DecodeKeccak(); + } + + return codeHash; + } } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/CompactReceiptStorageDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/CompactReceiptStorageDecoder.cs index beb6af45701..25e8ff25576 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/CompactReceiptStorageDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/CompactReceiptStorageDecoder.cs @@ -128,7 +128,7 @@ public void DecodeStructRef(scoped ref Rlp.ValueDecoderContext decoderContext, R decoderContext.SkipLength(); - Span firstItem = decoderContext.DecodeByteArraySpan(); + ReadOnlySpan firstItem = decoderContext.DecodeByteArraySpan(); if (firstItem.Length == 1) { item.StatusCode = firstItem[0]; diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/IRlpDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/IRlpDecoder.cs index fa869eb1a2d..4895b9e46d2 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/IRlpDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/IRlpDecoder.cs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; + namespace Nethermind.Serialization.Rlp { public interface IRlpDecoder @@ -27,4 +29,13 @@ public interface IRlpValueDecoder : IRlpDecoder { T Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None); } + + public static class RlpValueDecoderExtensions + { + public static T Decode(this IRlpValueDecoder decoder, ReadOnlySpan bytes, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + Rlp.ValueDecoderContext context = new(bytes); + return decoder.Decode(ref context, rlpBehaviors); + } + } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptStorageDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptStorageDecoder.cs index cbbcf234331..2d27f141112 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptStorageDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptStorageDecoder.cs @@ -346,7 +346,7 @@ public void DecodeStructRef(scoped ref Rlp.ValueDecoderContext decoderContext, R } decoderContext.ReadSequenceLength(); - Span firstItem = decoderContext.DecodeByteArraySpan(); + ReadOnlySpan firstItem = decoderContext.DecodeByteArraySpan(); if (firstItem.Length == 1) { item.StatusCode = firstItem[0]; diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs index 809e2a6b330..50a6a763db2 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs @@ -542,7 +542,7 @@ public static Rlp Encode(params Rlp[] sequence) public ref struct ValueDecoderContext { - public ValueDecoderContext(scoped in Span data) + public ValueDecoderContext(scoped in ReadOnlySpan data) { Data = data; Position = 0; @@ -563,7 +563,7 @@ public ValueDecoderContext(Memory memory, bool sliceMemory = false) private bool _sliceMemory = false; - public Span Data { get; } + public ReadOnlySpan Data { get; } public readonly bool IsEmpty => Data.IsEmpty; @@ -633,9 +633,9 @@ public int PeekNextRlpLength() return a + b; } - public Span Peek(int length) + public ReadOnlySpan Peek(int length) { - Span item = Read(length); + ReadOnlySpan item = Read(length); Position -= item.Length; return item; } @@ -762,9 +762,9 @@ public byte ReadByte() return Data[Position++]; } - public Span Read(int length) + public ReadOnlySpan Read(int length) { - Span data = Data.Slice(Position, length); + ReadOnlySpan data = Data.Slice(Position, length); Position += length; return data; } @@ -832,7 +832,7 @@ public DecodeKeccakRlpException(in int prefix, in int position, in int dataLengt throw new DecodeKeccakRlpException(prefix, Position, Data.Length); } - Span keccakSpan = Read(32); + ReadOnlySpan keccakSpan = Read(32); if (keccakSpan.SequenceEqual(Keccak.OfAnEmptyString.Bytes)) { return Keccak.OfAnEmptyString; @@ -874,7 +874,7 @@ public void DecodeKeccakStructRef(out Hash256StructRef keccak) } else { - Span keccakSpan = Read(32); + ReadOnlySpan keccakSpan = Read(32); if (keccakSpan.SequenceEqual(Keccak.OfAnEmptyString.Bytes)) { keccak = new Hash256StructRef(Keccak.OfAnEmptyString.Bytes); @@ -906,7 +906,7 @@ public void DecodeZeroPrefixedKeccakStructRef(out Hash256StructRef keccak, Span< else if (prefix == 128 + 32) { ReadByte(); - Span keccakSpan = Read(32); + ReadOnlySpan keccakSpan = Read(32); if (keccakSpan.SequenceEqual(Keccak.OfAnEmptyString.Bytes)) { keccak = new Hash256StructRef(Keccak.OfAnEmptyString.Bytes); @@ -968,7 +968,7 @@ public void DecodeAddressStructRef(out AddressStructRef address) public UInt256 DecodeUInt256(int length = -1) { - Span byteSpan = DecodeByteArraySpan(); + ReadOnlySpan byteSpan = DecodeByteArraySpan(); if (byteSpan.Length > 32) { throw new RlpException("UInt256 cannot be longer than 32 bytes"); @@ -1002,7 +1002,7 @@ public BigInteger DecodeUBigInt() public Bloom? DecodeBloom() { - Span bloomBytes; + ReadOnlySpan bloomBytes; // tks: not sure why but some nodes send us Blooms in a sequence form // https://github.com/NethermindEth/nethermind/issues/113 @@ -1030,7 +1030,7 @@ public BigInteger DecodeUBigInt() public void DecodeBloomStructRef(out BloomStructRef bloom) { - Span bloomBytes; + ReadOnlySpan bloomBytes; // tks: not sure why but some nodes send us Blooms in a sequence form // https://github.com/NethermindEth/nethermind/issues/113 @@ -1057,10 +1057,10 @@ public void DecodeBloomStructRef(out BloomStructRef bloom) bloom = bloomBytes.SequenceEqual(Bloom.Empty.Bytes) ? new BloomStructRef(Bloom.Empty.Bytes) : new BloomStructRef(bloomBytes); } - public Span PeekNextItem() + public ReadOnlySpan PeekNextItem() { int length = PeekNextRlpLength(); - Span item = Read(length); + ReadOnlySpan item = Read(length); Position -= item.Length; return item; } @@ -1111,7 +1111,7 @@ public int DecodeInt() public byte[] DecodeByteArray() => DecodeByteArraySpan().ToArray(); - public Span DecodeByteArraySpan() + public ReadOnlySpan DecodeByteArraySpan() { int prefix = ReadByte(); @@ -1128,7 +1128,7 @@ public Span DecodeByteArraySpan() if (prefix <= 183) { int length = prefix - 128; - Span buffer = Read(length); + ReadOnlySpan buffer = Read(length); if (length == 1 && buffer[0] < 128) { throw new RlpException($"Unexpected byte value {buffer[0]}"); @@ -1286,7 +1286,7 @@ private void SkipBytes(int length) public string DecodeString() { - Span bytes = DecodeByteArraySpan(); + ReadOnlySpan bytes = DecodeByteArraySpan(); return Encoding.UTF8.GetString(bytes); } @@ -1416,6 +1416,12 @@ public T[] DecodeArray(IRlpValueDecoder? decoder = null, bool checkPositio return result; } + + public bool IsNextItemEmptyArray() + { + return PeekByte() == EmptyArrayByte; + } + } public override bool Equals(object? other) diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs index f8898f0b11f..b99f719f1fd 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs @@ -165,7 +165,7 @@ static Span DecodeTxType(RlpStream rlpStream, int length, out TxType txTyp return transactionSequence; } - private static Hash256 CalculateHashForNetworkPayloadForm(TxType type, Span transactionSequence) + private static Hash256 CalculateHashForNetworkPayloadForm(TxType type, ReadOnlySpan transactionSequence) { KeccakHash hash = KeccakHash.Create(); Span txType = stackalloc byte[1]; @@ -405,7 +405,7 @@ public void Decode(ref Rlp.ValueDecoderContext decoderContext, ref T? transactio transaction.Type = TxType.Legacy; int txSequenceStart = decoderContext.Position; - Span transactionSequence = decoderContext.PeekNextItem(); + ReadOnlySpan transactionSequence = decoderContext.PeekNextItem(); if ((rlpBehaviors & RlpBehaviors.SkipTypedWrapping) == RlpBehaviors.SkipTypedWrapping) { diff --git a/src/Nethermind/Nethermind.State/Proofs/AccountProofCollector.cs b/src/Nethermind/Nethermind.State/Proofs/AccountProofCollector.cs index 357fba93d3e..e63ed8d41c3 100644 --- a/src/Nethermind/Nethermind.State/Proofs/AccountProofCollector.cs +++ b/src/Nethermind/Nethermind.State/Proofs/AccountProofCollector.cs @@ -271,7 +271,7 @@ private void AddEmpty(TrieNode node, TrieVisitContext trieVisitContext) } } - public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, byte[] value) + public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value) { AddProofItem(node, trieVisitContext); _nodeToVisitFilter.Remove(node.Keccak); diff --git a/src/Nethermind/Nethermind.State/Proofs/ProofCollector.cs b/src/Nethermind/Nethermind.State/Proofs/ProofCollector.cs index bb29de189d1..42fd43a5316 100644 --- a/src/Nethermind/Nethermind.State/Proofs/ProofCollector.cs +++ b/src/Nethermind/Nethermind.State/Proofs/ProofCollector.cs @@ -69,7 +69,7 @@ protected virtual void AddProofBits(TrieNode node) _proofBits.Add(node.FullRlp.ToArray()); } - public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, byte[] value) + public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value) { AddProofBits(node); _visitingFilter.Remove(node.Keccak); diff --git a/src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs b/src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs index 0a96042bc31..e5908f5aabb 100644 --- a/src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs +++ b/src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.IO; using System.Linq; using Nethermind.Core.Crypto; @@ -15,7 +16,7 @@ public static class ProofVerifier /// Verifies one proof - address path from the bottom to the root. /// /// The Value of the bottom most proof node. For example an Account. - public static byte[]? VerifyOneProof(byte[][] proof, Hash256 root) + public static CappedArray VerifyOneProof(byte[][] proof, Hash256 root) { if (proof.Length == 0) { @@ -44,7 +45,7 @@ public static class ProofVerifier TrieNode trieNode = new(NodeType.Unknown, proof.Last()); trieNode.ResolveNode(null); - return trieNode.Value.ToArray(); + return trieNode.Value; } } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs index 7937f6c5f35..7d416e6e13a 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs @@ -873,7 +873,7 @@ private void HandleTrieNode(StateSyncItem currentStateSyncItem, byte[] currentRe { _pendingItems.MaxStateLevel = 64; DependentItem dependentItem = new(currentStateSyncItem, currentResponseItem, 2, true); - (Hash256 codeHash, Hash256 storageRoot) = AccountDecoder.DecodeHashesOnly(new RlpStream(trieNode.Value.ToArray())); + (Hash256 codeHash, Hash256 storageRoot) = AccountDecoder.DecodeHashesOnly(trieNode.Value.AsRlpStream()); if (codeHash != Keccak.OfAnEmptyString) { // prepare a branch without the code DB diff --git a/src/Nethermind/Nethermind.Trie/ITreeVisitor.cs b/src/Nethermind/Nethermind.Trie/ITreeVisitor.cs index 48579ca1804..ad701332f5f 100644 --- a/src/Nethermind/Nethermind.Trie/ITreeVisitor.cs +++ b/src/Nethermind/Nethermind.Trie/ITreeVisitor.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -25,7 +26,7 @@ public interface ITreeVisitor void VisitExtension(TrieNode node, TrieVisitContext trieVisitContext); - void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, byte[] value = null); + void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value); void VisitCode(Hash256 codeHash, TrieVisitContext trieVisitContext); } diff --git a/src/Nethermind/Nethermind.Trie/RootCheckVisitor.cs b/src/Nethermind/Nethermind.Trie/RootCheckVisitor.cs index 789f80600c8..dd7be36be01 100644 --- a/src/Nethermind/Nethermind.Trie/RootCheckVisitor.cs +++ b/src/Nethermind/Nethermind.Trie/RootCheckVisitor.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using Nethermind.Core.Crypto; namespace Nethermind.Trie @@ -33,7 +34,7 @@ public void VisitExtension(TrieNode node, TrieVisitContext trieVisitContext) { } - public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, byte[] value = null) + public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value) { } diff --git a/src/Nethermind/Nethermind.Trie/TreeDumper.cs b/src/Nethermind/Nethermind.Trie/TreeDumper.cs index 09dfa87cd6c..c7199c09877 100644 --- a/src/Nethermind/Nethermind.Trie/TreeDumper.cs +++ b/src/Nethermind/Nethermind.Trie/TreeDumper.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Text; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -59,20 +60,21 @@ public void VisitExtension(TrieNode node, TrieVisitContext trieVisitContext) private readonly AccountDecoder decoder = new(); - public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, byte[] value = null) + public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value) { string leafDescription = trieVisitContext.IsStorage ? "LEAF " : "ACCOUNT "; _builder.AppendLine($"{GetPrefix(trieVisitContext)}{leafDescription} {Nibbles.FromBytes(node.Key).ToPackedByteArray().ToHexString(false)} -> {KeccakOrRlpStringOfNode(node)}"); + Rlp.ValueDecoderContext valueDecoderContext = new(value); if (!trieVisitContext.IsStorage) { - Account account = decoder.Decode(new RlpStream(value)); + Account account = decoder.Decode(ref valueDecoderContext); _builder.AppendLine($"{GetPrefix(trieVisitContext)} NONCE: {account.Nonce}"); _builder.AppendLine($"{GetPrefix(trieVisitContext)} BALANCE: {account.Balance}"); _builder.AppendLine($"{GetPrefix(trieVisitContext)} IS_CONTRACT: {account.IsContract}"); } else { - _builder.AppendLine($"{GetPrefix(trieVisitContext)} VALUE: {new RlpStream(value).DecodeByteArray().ToHexString(true, true)}"); + _builder.AppendLine($"{GetPrefix(trieVisitContext)} VALUE: {valueDecoderContext.DecodeByteArray().ToHexString(true, true)}"); } } diff --git a/src/Nethermind/Nethermind.Trie/TrieNode.Visitor.cs b/src/Nethermind/Nethermind.Trie/TrieNode.Visitor.cs index 2fd7fcc6a0c..cca3b3b0ccd 100644 --- a/src/Nethermind/Nethermind.Trie/TrieNode.Visitor.cs +++ b/src/Nethermind/Nethermind.Trie/TrieNode.Visitor.cs @@ -85,7 +85,7 @@ internal void AcceptResolvedNode(ITreeVisitor visitor, ITrieNodeResolver nodeRes case NodeType.Leaf: { - visitor.VisitLeaf(this, trieVisitContext.ToVisitContext(), Value.ToArray()); + visitor.VisitLeaf(this, trieVisitContext.ToVisitContext(), Value.AsSpan()); if (!trieVisitContext.IsStorage && trieVisitContext.ExpectAccounts) // can combine these conditions { @@ -246,7 +246,7 @@ void VisitMultiThread(ITreeVisitor treeVisitor, ITrieNodeResolver trieNodeResolv case NodeType.Leaf: { - visitor.VisitLeaf(this, trieVisitContext, Value.ToArray()); + visitor.VisitLeaf(this, trieVisitContext, Value.AsSpan()); trieVisitContext.AddVisited(); if (!trieVisitContext.IsStorage && trieVisitContext.ExpectAccounts) // can combine these conditions { diff --git a/src/Nethermind/Nethermind.Trie/TrieStatsCollector.cs b/src/Nethermind/Nethermind.Trie/TrieStatsCollector.cs index ea8c731f08b..259a1e96139 100644 --- a/src/Nethermind/Nethermind.Trie/TrieStatsCollector.cs +++ b/src/Nethermind/Nethermind.Trie/TrieStatsCollector.cs @@ -79,7 +79,7 @@ public void VisitExtension(TrieNode node, TrieVisitContext trieVisitContext) IncrementLevel(trieVisitContext); } - public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, byte[] value = null) + public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value) { if (Stats.NodesCount - _lastAccountNodeCount > 1_000_000) { From bb20f01285354a81a2292f118b80137760fad707 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Tue, 23 Jan 2024 23:53:28 +0100 Subject: [PATCH 02/16] hunting more allocations --- .../Nethermind.Core/Crypto/Keccak.cs | 13 +-- .../Nethermind.Core/Extensions/Bytes.cs | 4 +- .../Nethermind.Core/Nethermind.Core.csproj | 5 ++ .../VirtualMachineTests.cs | 22 ++--- .../VirtualMachineTestsBase.cs | 6 +- .../Nethermind.Evm.Test/VmCodeDepositTests.cs | 8 +- src/Nethermind/Nethermind.Evm/EvmStack.cs | 7 +- src/Nethermind/Nethermind.Evm/StatusCode.cs | 6 +- .../Tracing/GethStyle/JavaScript/Db.cs | 4 +- .../Nethermind.Evm/Tracing/ITxTracer.cs | 6 +- .../Nethermind.Evm/VirtualMachine.cs | 13 +-- .../Modules/Eth/EthRpcModule.cs | 4 +- .../Eth/V68/Eth68ProtocolHandler.cs | 2 +- .../Nethermind.Serialization.Rlp/RlpStream.cs | 2 +- .../ValueRlpStream.cs | 2 +- .../Nethermind.State.Test/StateReaderTests.cs | 9 +- .../StorageProviderTests.cs | 34 +++---- .../Nethermind.State/IStateReader.cs | 3 +- .../Nethermind.State/IWorldState.cs | 4 +- .../PartialStorageProviderBase.cs | 4 +- .../PersistentStorageProvider.cs | 4 +- .../Proofs/AccountProofCollector.cs | 5 +- .../Nethermind.State/Proofs/ProofVerifier.cs | 1 + .../Nethermind.State/StateReader.cs | 6 +- src/Nethermind/Nethermind.State/StateTree.cs | 9 +- .../Nethermind.State/StorageTree.cs | 8 +- .../TransientStorageProvider.cs | 3 +- src/Nethermind/Nethermind.State/WorldState.cs | 4 +- .../LesSync/CanonicalHashTrie.cs | 4 +- .../LesSync/ChtDecoder.cs | 16 +++- .../Trie/HealingStateTree.cs | 2 +- .../Trie/HealingStorageTree.cs | 2 +- .../PruningScenariosTests.cs | 2 +- .../Nethermind.Trie.Test/TrieTests.cs | 90 +++++++++---------- .../Nethermind.Trie/PatriciaTree.cs | 6 +- 35 files changed, 177 insertions(+), 143 deletions(-) diff --git a/src/Nethermind/Nethermind.Core/Crypto/Keccak.cs b/src/Nethermind/Nethermind.Core/Crypto/Keccak.cs index 94345f74f1f..318ae899c45 100644 --- a/src/Nethermind/Nethermind.Core/Crypto/Keccak.cs +++ b/src/Nethermind/Nethermind.Core/Crypto/Keccak.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using Nethermind.Serialization.Rlp; namespace Nethermind.Core.Crypto { @@ -15,17 +16,17 @@ public static class ValueKeccak /// /// 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 /// - public static readonly ValueHash256 OfAnEmptyString = InternalCompute(new byte[] { }); + public static readonly ValueHash256 OfAnEmptyString = InternalCompute(Array.Empty()); /// /// 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347 /// - public static readonly ValueHash256 OfAnEmptySequenceRlp = InternalCompute(new byte[] { 192 }); + public static readonly ValueHash256 OfAnEmptySequenceRlp = InternalCompute([Rlp.NullObjectByte]); /// /// 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421 /// - public static readonly ValueHash256 EmptyTreeHash = InternalCompute(new byte[] { 128 }); + public static readonly ValueHash256 EmptyTreeHash = InternalCompute([Rlp.EmptyArrayByte]); /// /// 0x0000000000000000000000000000000000000000000000000000000000000000 @@ -82,17 +83,17 @@ public static class Keccak /// /// 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 /// - public static readonly Hash256 OfAnEmptyString = new Hash256(ValueKeccak.InternalCompute(new byte[] { })); + public static readonly Hash256 OfAnEmptyString = new Hash256(ValueKeccak.InternalCompute(Array.Empty())); /// /// 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347 /// - public static readonly Hash256 OfAnEmptySequenceRlp = new Hash256(ValueKeccak.InternalCompute(new byte[] { 192 })); + public static readonly Hash256 OfAnEmptySequenceRlp = new Hash256(ValueKeccak.InternalCompute([Rlp.NullObjectByte])); /// /// 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421 /// - public static Hash256 EmptyTreeHash = new Hash256(ValueKeccak.InternalCompute(new byte[] { 128 })); + public static Hash256 EmptyTreeHash = new Hash256(ValueKeccak.InternalCompute([Rlp.EmptyArrayByte])); /// /// 0x0000000000000000000000000000000000000000000000000000000000000000 diff --git a/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs b/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs index 152a4607792..1c19a6ede66 100644 --- a/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs +++ b/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs @@ -27,6 +27,8 @@ public static unsafe partial class Bytes public static readonly IEqualityComparer NullableEqualityComparer = new NullableBytesEqualityComparer(); public static readonly ISpanEqualityComparer SpanEqualityComparer = new SpanBytesEqualityComparer(); public static readonly BytesComparer Comparer = new(); + public static readonly byte[] ZeroByte = [0]; + public static readonly byte[] OneByte = [1]; private class BytesEqualityComparer : EqualityComparer { @@ -217,7 +219,7 @@ public static Span WithoutLeadingZerosOrEmpty(this Span bytes) public static Span WithoutLeadingZeros(this Span bytes) { - if (bytes.Length == 0) return new byte[] { 0 }; + if (bytes.Length == 0) return ZeroByte; int nonZeroIndex = bytes.IndexOfAnyExcept((byte)0); // Keep one or it will be interpreted as null diff --git a/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj b/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj index 6ddeabf9513..cd0cc16548b 100644 --- a/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj +++ b/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj @@ -16,4 +16,9 @@ + + + ..\artifacts\bin\Nethermind.Evm.Test\debug\Nethermind.Serialization.Rlp.dll + + diff --git a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs index baa5d866b0a..f14a93c7bed 100644 --- a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs @@ -154,7 +154,7 @@ public void Add_0_0() 0, (byte)Instruction.SSTORE); Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + 4 * GasCostOf.VeryLow + GasCostOf.SReset), "gas"); - Assert.That(TestState.Get(new StorageCell(Recipient, 0)), Is.EqualTo(new byte[] { 0 }), "storage"); + Assert.That(TestState.Get(new StorageCell(Recipient, 0)).ToArray(), Is.EqualTo(new byte[] { 0 }), "storage"); } [Test] @@ -170,7 +170,7 @@ public void Add_0_1() 0, (byte)Instruction.SSTORE); Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + 4 * GasCostOf.VeryLow + GasCostOf.SSet), "gas"); - Assert.That(TestState.Get(new StorageCell(Recipient, 0)), Is.EqualTo(new byte[] { 1 }), "storage"); + Assert.That(TestState.Get(new StorageCell(Recipient, 0)).ToArray(), Is.EqualTo(new byte[] { 1 }), "storage"); } [Test] @@ -186,7 +186,7 @@ public void Add_1_0() 0, (byte)Instruction.SSTORE); Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + 4 * GasCostOf.VeryLow + GasCostOf.SSet), "gas"); - Assert.That(TestState.Get(new StorageCell(Recipient, 0)), Is.EqualTo(new byte[] { 1 }), "storage"); + Assert.That(TestState.Get(new StorageCell(Recipient, 0)).ToArray(), Is.EqualTo(new byte[] { 1 }), "storage"); } [Test] @@ -302,7 +302,7 @@ public void Exp_2_160() 0, (byte)Instruction.SSTORE); Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + GasCostOf.VeryLow * 3 + GasCostOf.SSet + GasCostOf.Exp + GasCostOf.ExpByteEip160), "gas"); - Assert.That(TestState.Get(new StorageCell(Recipient, 0)), Is.EqualTo(BigInteger.Pow(2, 160).ToBigEndianByteArray()), "storage"); + Assert.That(TestState.Get(new StorageCell(Recipient, 0)).ToArray(), Is.EqualTo(BigInteger.Pow(2, 160).ToBigEndianByteArray()), "storage"); } [Test] @@ -318,7 +318,7 @@ public void Exp_0_0() 0, (byte)Instruction.SSTORE); Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + GasCostOf.VeryLow * 3 + GasCostOf.Exp + GasCostOf.SSet), "gas"); - Assert.That(TestState.Get(new StorageCell(Recipient, 0)), Is.EqualTo(BigInteger.One.ToBigEndianByteArray()), "storage"); + Assert.That(TestState.Get(new StorageCell(Recipient, 0)).ToArray(), Is.EqualTo(BigInteger.One.ToBigEndianByteArray()), "storage"); } [Test] @@ -334,7 +334,7 @@ public void Exp_0_160() 0, (byte)Instruction.SSTORE); Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + GasCostOf.VeryLow * 3 + GasCostOf.Exp + GasCostOf.ExpByteEip160 + GasCostOf.SReset), "gas"); - Assert.That(TestState.Get(new StorageCell(Recipient, 0)), Is.EqualTo(BigInteger.Zero.ToBigEndianByteArray()), "storage"); + Assert.That(TestState.Get(new StorageCell(Recipient, 0)).ToArray(), Is.EqualTo(BigInteger.Zero.ToBigEndianByteArray()), "storage"); } [Test] @@ -350,7 +350,7 @@ public void Exp_1_160() 0, (byte)Instruction.SSTORE); Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + GasCostOf.VeryLow * 3 + GasCostOf.Exp + GasCostOf.ExpByteEip160 + GasCostOf.SSet), "gas"); - Assert.That(TestState.Get(new StorageCell(Recipient, 0)), Is.EqualTo(BigInteger.One.ToBigEndianByteArray()), "storage"); + Assert.That(TestState.Get(new StorageCell(Recipient, 0)).ToArray(), Is.EqualTo(BigInteger.One.ToBigEndianByteArray()), "storage"); } [Test] @@ -366,7 +366,7 @@ public void Sub_0_0() 0, (byte)Instruction.SSTORE); Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + GasCostOf.VeryLow * 4 + GasCostOf.SReset), "gas"); - Assert.That(TestState.Get(new StorageCell(Recipient, 0)), Is.EqualTo(new byte[] { 0 }), "storage"); + Assert.That(TestState.Get(new StorageCell(Recipient, 0)).ToArray(), Is.EqualTo(new byte[] { 0 }), "storage"); } [Test] @@ -380,7 +380,7 @@ public void Not_0() 0, (byte)Instruction.SSTORE); Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + GasCostOf.VeryLow * 3 + GasCostOf.SSet), "gas"); - Assert.That(TestState.Get(new StorageCell(Recipient, 0)), Is.EqualTo((BigInteger.Pow(2, 256) - 1).ToBigEndianByteArray()), "storage"); + Assert.That(TestState.Get(new StorageCell(Recipient, 0)).ToArray(), Is.EqualTo((BigInteger.Pow(2, 256) - 1).ToBigEndianByteArray()), "storage"); } [Test] @@ -396,7 +396,7 @@ public void Or_0_0() 0, (byte)Instruction.SSTORE); Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + GasCostOf.VeryLow * 4 + GasCostOf.SReset), "gas"); - Assert.That(TestState.Get(new StorageCell(Recipient, 0)), Is.EqualTo(BigInteger.Zero.ToBigEndianByteArray()), "storage"); + Assert.That(TestState.Get(new StorageCell(Recipient, 0)).ToArray(), Is.EqualTo(BigInteger.Zero.ToBigEndianByteArray()), "storage"); } [Test] @@ -409,7 +409,7 @@ public void Sstore_twice_0_same_storage_should_refund_only_once() 0, (byte)Instruction.SSTORE); Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + GasCostOf.VeryLow * 2 + GasCostOf.SReset), "gas"); - Assert.That(TestState.Get(new StorageCell(Recipient, 0)), Is.EqualTo(BigInteger.Zero.ToBigEndianByteArray()), "storage"); + Assert.That(TestState.Get(new StorageCell(Recipient, 0)).ToArray(), Is.EqualTo(BigInteger.Zero.ToBigEndianByteArray()), "storage"); } /// diff --git a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs index 773717ce9a6..da4554f0314 100644 --- a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs +++ b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs @@ -338,7 +338,7 @@ protected void AssertStorage(UInt256 address, ReadOnlySpan value) protected void AssertStorage(UInt256 address, BigInteger expectedValue) { - byte[] actualValue = TestState.Get(new StorageCell(Recipient, address)); + byte[] actualValue = TestState.Get(new StorageCell(Recipient, address)).ToArray(); byte[] expected = expectedValue < 0 ? expectedValue.ToBigEndianByteArray(32) : expectedValue.ToBigEndianByteArray(); Assert.That(actualValue, Is.EqualTo(expected), "storage"); } @@ -347,7 +347,7 @@ protected void AssertStorage(UInt256 address, UInt256 expectedValue) { byte[] bytes = ((BigInteger)expectedValue).ToBigEndianByteArray(); - byte[] actualValue = TestState.Get(new StorageCell(Recipient, address)); + byte[] actualValue = TestState.Get(new StorageCell(Recipient, address)).ToArray(); Assert.That(actualValue, Is.EqualTo(bytes), "storage"); } @@ -362,7 +362,7 @@ protected void AssertStorage(StorageCell storageCell, UInt256 expectedValue) } else { - byte[] actualValue = TestState.Get(storageCell); + byte[] actualValue = TestState.Get(storageCell).ToArray(); Assert.That(actualValue, Is.EqualTo(expectedValue.ToBigEndian().WithoutLeadingZeros().ToArray()), $"storage {storageCell}, call {_callIndex}"); } } diff --git a/src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs b/src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs index 99441287fa9..f01ba711186 100644 --- a/src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs @@ -56,11 +56,11 @@ public void Regression_mainnet_6108276() .Done; TestAllTracerWithOutput receipt = Execute(code); - byte[] result = TestState.Get(storageCell); + byte[] result = TestState.Get(storageCell).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)); + byte[] returnData = TestState.Get(new StorageCell(TestItem.AddressC, 0)).ToArray(); Assert.That(returnData, Is.EqualTo(new byte[1]), "address returned"); } @@ -96,11 +96,11 @@ public void Regression_mainnet_226522() .Done; TestAllTracerWithOutput receipt = Execute(code); - byte[] result = TestState.Get(storageCell); + byte[] result = TestState.Get(storageCell).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)); + byte[] returnData = TestState.Get(new StorageCell(TestItem.AddressC, 0)).ToArray(); Assert.That(returnData, Is.EqualTo(deployed.Bytes), "address returned"); } } diff --git a/src/Nethermind/Nethermind.Evm/EvmStack.cs b/src/Nethermind/Nethermind.Evm/EvmStack.cs index 0256eda50e2..76fa8cc4066 100644 --- a/src/Nethermind/Nethermind.Evm/EvmStack.cs +++ b/src/Nethermind/Nethermind.Evm/EvmStack.cs @@ -12,6 +12,7 @@ using System.Runtime.Intrinsics; using System.Diagnostics; using System.Runtime.Intrinsics.X86; +using Nethermind.Core.Extensions; namespace Nethermind.Evm; @@ -38,7 +39,7 @@ public EvmStack(scoped in Span bytes, scoped in int head, ITxTracer txTrac private readonly ITxTracer _tracer; - public void PushBytes(scoped in Span value) + public void PushBytes(scoped in ReadOnlySpan value) { if (typeof(TTracing) == typeof(IsTracing)) _tracer.ReportStackPush(value); @@ -105,7 +106,7 @@ public void PushByte(byte value) } } - private static ReadOnlySpan OneStackItem() => new byte[] { 1 }; + private static ReadOnlySpan OneStackItem() => Bytes.OneByte; public void PushOne() { @@ -120,7 +121,7 @@ public void PushOne() } } - private static ReadOnlySpan ZeroStackItem() => new byte[] { 0 }; + private static ReadOnlySpan ZeroStackItem() => Bytes.ZeroByte; public void PushZero() { diff --git a/src/Nethermind/Nethermind.Evm/StatusCode.cs b/src/Nethermind/Nethermind.Evm/StatusCode.cs index 76d43d5c9f5..bfbc5d3e83b 100644 --- a/src/Nethermind/Nethermind.Evm/StatusCode.cs +++ b/src/Nethermind/Nethermind.Evm/StatusCode.cs @@ -1,13 +1,15 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core.Extensions; + namespace Nethermind.Evm { public static class StatusCode { public const byte Failure = 0; - public static readonly byte[] FailureBytes = new byte[] { 0 }; + public static readonly byte[] FailureBytes = Bytes.ZeroByte; public const byte Success = 1; - public static readonly byte[] SuccessBytes = new byte[] { 1 }; + public static readonly byte[] SuccessBytes = Bytes.OneByte; } } diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/JavaScript/Db.cs b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/JavaScript/Db.cs index 5ba00d9e9bd..83c778930fb 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/JavaScript/Db.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/JavaScript/Db.cs @@ -33,12 +33,12 @@ public ITypedArray getState(object address, object hash) byte[] array = ArrayPool.Shared.Rent(32); try { - byte[] bytes = WorldState.Get(new StorageCell(address.ToAddress(), hash.GetHash())); + Span bytes = WorldState.Get(new StorageCell(address.ToAddress(), hash.GetHash())); if (bytes.Length < array.Length) { Array.Clear(array); } - bytes.CopyTo(array, array.Length - bytes.Length); + bytes.CopyTo(array.AsSpan(array.Length - bytes.Length)); return array.ToTypedScriptArray(); } finally diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs index 26057c97f89..92626270871 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs @@ -293,7 +293,7 @@ void ReportMemoryChange(long offset, in ZeroPaddedSpan data) /// /// /// Depends on - void SetOperationTransientStorage(Address storageCellAddress, UInt256 storageIndex, ReadOnlySpan newValue, byte[] currentValue) { } + void SetOperationTransientStorage(Address storageCellAddress, UInt256 storageIndex, ReadOnlySpan newValue, ReadOnlySpan currentValue) { } /// /// @@ -311,7 +311,7 @@ void SetOperationTransientStorage(Address storageCellAddress, UInt256 storageInd /// /// /// Depends on - void LoadOperationTransientStorage(Address storageCellAddress, UInt256 storageIndex, byte[] value) { } + void LoadOperationTransientStorage(Address storageCellAddress, UInt256 storageIndex, ReadOnlySpan value) { } /// /// @@ -375,7 +375,7 @@ void LoadOperationTransientStorage(Address storageCellAddress, UInt256 storageIn void ReportBlockHash(Hash256 blockHash); /// - /// + /// /// /// /// Depends on diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index ff7eeb636f5..ecb1bee59ac 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -19,6 +19,7 @@ using Nethermind.State; using System.Diagnostics.CodeAnalysis; using System.Diagnostics; +using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using static Nethermind.Evm.VirtualMachine; using static System.Runtime.CompilerServices.Unsafe; @@ -1659,8 +1660,9 @@ private CallResult ExecuteCode value = _state.Get(in storageCell); + Span valueBytes = MemoryMarshal.CreateSpan(ref MemoryMarshal.AsRef(value), value.Length); // TODO: how to do it? + stack.PushBytes(valueBytes); if (typeof(TTracingStorage) == typeof(IsTracing)) { @@ -2017,8 +2019,9 @@ private CallResult ExecuteCode value = _state.GetTransientState(in storageCell); + Span valueBytes = MemoryMarshal.CreateSpan(ref MemoryMarshal.AsRef(value), value.Length); // TODO: how to do it? + stack.PushBytes(valueBytes); if (typeof(TTracingStorage) == typeof(IsTracing)) { @@ -2058,7 +2061,7 @@ private CallResult ExecuteCode currentValue = _state.GetTransientState(in storageCell); _txTracer.SetOperationTransientStorage(storageCell.Address, result, bytes, currentValue); } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs index 547df1d13ff..c68009a2e9d 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs @@ -176,8 +176,8 @@ public ResultWrapper eth_getStorageAt(Address address, UInt256 positionI } BlockHeader? header = searchResult.Object; - byte[] storage = _stateReader.GetStorage(header!.StateRoot!, address, positionIndex); - if (storage is null) + Span storage = _stateReader.GetStorage(header!.StateRoot!, address, positionIndex); + if (storage.IsEmpty) { return ResultWrapper.Success(Array.Empty()); } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandler.cs index ee05d93fcdd..84ea6d4b167 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandler.cs @@ -109,7 +109,7 @@ protected override void SendNewTransactionCore(Transaction tx) } else { - SendMessage(new byte[] { (byte)tx.Type }, new int[] { tx.GetLength() }, new Hash256[] { tx.Hash }); + SendMessage(new[] { (byte)tx.Type }, new int[] { tx.GetLength() }, new Hash256[] { tx.Hash }); } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs b/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs index 12ca0b8c223..63cc234bce4 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs @@ -1309,7 +1309,7 @@ public ReadOnlySpan DecodeByteArraySpan() int prefix = ReadByte(); if (prefix == 0) { - return new byte[] { 0 }; + return Bytes.ZeroByte; } if (prefix < 128) diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/ValueRlpStream.cs b/src/Nethermind/Nethermind.Serialization.Rlp/ValueRlpStream.cs index 268940224dc..b286898d4b7 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/ValueRlpStream.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/ValueRlpStream.cs @@ -347,7 +347,7 @@ public ReadOnlySpan DecodeByteArraySpan() int prefix = ReadByte(); if (prefix == 0) { - return new byte[] { 0 }; + return Bytes.ZeroByte; } if (prefix < 128) diff --git a/src/Nethermind/Nethermind.State.Test/StateReaderTests.cs b/src/Nethermind/Nethermind.State.Test/StateReaderTests.cs index 2bb9622c0ac..5221abdd72b 100644 --- a/src/Nethermind/Nethermind.State.Test/StateReaderTests.cs +++ b/src/Nethermind/Nethermind.State.Test/StateReaderTests.cs @@ -148,7 +148,7 @@ void CommitEverything() StateReader reader = new(new TrieStore(stateDb, LimboLogs.Instance), Substitute.For(), Logger); - reader.GetStorage(stateRoot0, _address1, storageCell.Index + 1).Should().BeEquivalentTo(new byte[] { 0 }); + reader.GetStorage(stateRoot0, _address1, storageCell.Index + 1).ToArray().Should().BeEquivalentTo(new byte[] { 0 }); } private Task StartTask(StateReader reader, Hash256 stateRoot, UInt256 value) @@ -171,7 +171,7 @@ private Task StartStorageTask(StateReader reader, Hash256 stateRoot, StorageCell { for (int i = 0; i < 1000; i++) { - byte[] result = reader.GetStorage(stateRoot, storageCell.Address, storageCell.Index); + byte[] result = reader.GetStorage(stateRoot, storageCell.Address, storageCell.Index).ToArray(); result.Should().BeEquivalentTo(value); } }); @@ -203,7 +203,7 @@ public async Task Get_storage() StateReader reader = new( new TrieStore(dbProvider.StateDb, LimboLogs.Instance), dbProvider.CodeDb, Logger); - var retrieved = reader.GetStorage(state.StateRoot, _address1, storageCell.Index); + var retrieved = reader.GetStorage(state.StateRoot, _address1, storageCell.Index).ToArray(); retrieved.Should().BeEquivalentTo(initialValue); /* at this stage we set the value in storage to 1,2,3 at the tested storage cell */ @@ -225,8 +225,7 @@ It is a different stack of objects than the one that is used by the blockchain b /* At this stage the DB should have the storage value updated to 5. We will try to retrieve the value by taking the state root from the processor.*/ - retrieved = - reader.GetStorage(processorStateProvider.StateRoot, storageCell.Address, storageCell.Index); + retrieved = reader.GetStorage(processorStateProvider.StateRoot, storageCell.Address, storageCell.Index).ToArray(); retrieved.Should().BeEquivalentTo(newValue); /* If it failed then it means that the blockchain bridge cached the previous call value */ diff --git a/src/Nethermind/Nethermind.State.Test/StorageProviderTests.cs b/src/Nethermind/Nethermind.State.Test/StorageProviderTests.cs index efca083d28d..8e78cbf7f73 100644 --- a/src/Nethermind/Nethermind.State.Test/StorageProviderTests.cs +++ b/src/Nethermind/Nethermind.State.Test/StorageProviderTests.cs @@ -66,7 +66,7 @@ public void Same_address_same_index_different_values_restore(int snapshot) provider.Set(new StorageCell(ctx.Address1, 1), _values[3]); provider.Restore(Snapshot.EmptyPosition, snapshot, Snapshot.EmptyPosition); - Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)), Is.EqualTo(_values[snapshot + 1])); + Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[snapshot + 1])); } [Test] @@ -83,7 +83,7 @@ public void Keep_in_cache() provider.Restore(Snapshot.EmptyPosition, -1, Snapshot.EmptyPosition); provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); provider.Restore(Snapshot.EmptyPosition, -1, Snapshot.EmptyPosition); - Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)), Is.EqualTo(_values[1])); + Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[1])); } [TestCase(-1)] @@ -99,7 +99,7 @@ public void Same_address_different_index(int snapshot) provider.Set(new StorageCell(ctx.Address1, 3), _values[3]); provider.Restore(Snapshot.EmptyPosition, snapshot, Snapshot.EmptyPosition); - Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)), Is.EqualTo(_values[Math.Min(snapshot + 1, 1)])); + Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[Math.Min(snapshot + 1, 1)])); } [Test] @@ -125,12 +125,12 @@ public void Commit_restore() provider.Commit(Frontier.Instance); provider.Restore(Snapshot.Empty); - Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)), Is.EqualTo(_values[7])); - Assert.That(provider.Get(new StorageCell(ctx.Address1, 2)), Is.EqualTo(_values[8])); - Assert.That(provider.Get(new StorageCell(ctx.Address1, 3)), Is.EqualTo(_values[9])); - Assert.That(provider.Get(new StorageCell(ctx.Address2, 1)), Is.EqualTo(_values[10])); - Assert.That(provider.Get(new StorageCell(ctx.Address2, 2)), Is.EqualTo(_values[11])); - Assert.That(provider.Get(new StorageCell(ctx.Address2, 3)), Is.EqualTo(_values[12])); + Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[7])); + Assert.That(provider.Get(new StorageCell(ctx.Address1, 2)).ToArray(), Is.EqualTo(_values[8])); + Assert.That(provider.Get(new StorageCell(ctx.Address1, 3)).ToArray(), Is.EqualTo(_values[9])); + Assert.That(provider.Get(new StorageCell(ctx.Address2, 1)).ToArray(), Is.EqualTo(_values[10])); + Assert.That(provider.Get(new StorageCell(ctx.Address2, 2)).ToArray(), Is.EqualTo(_values[11])); + Assert.That(provider.Get(new StorageCell(ctx.Address2, 3)).ToArray(), Is.EqualTo(_values[12])); } [Test] @@ -199,7 +199,7 @@ public void Commit_trees_clear_caches_get_previous_root() storageProvider.Reset(); ctx.StateProvider.StateRoot = stateRoot; - byte[] valueAfter = storageProvider.Get(new StorageCell(ctx.Address1, 1)); + byte[] valueAfter = storageProvider.Get(new StorageCell(ctx.Address1, 1)).ToArray(); Assert.That(valueAfter, Is.EqualTo(_values[1])); } @@ -218,7 +218,7 @@ public void Can_commit_when_exactly_at_capacity_regression() storageProvider.Commit(Frontier.Instance); ctx.StateProvider.Commit(Frontier.Instance); - byte[] valueAfter = storageProvider.Get(new StorageCell(ctx.Address1, 1)); + byte[] valueAfter = storageProvider.Get(new StorageCell(ctx.Address1, 1)).ToArray(); Assert.That(valueAfter, Is.EqualTo(_values[(Resettable.StartCapacity + 1) % 2])); } @@ -251,7 +251,7 @@ public void Can_tload_after_tstore() WorldState provider = BuildStorageProvider(ctx); provider.SetTransientState(new StorageCell(ctx.Address1, 2), _values[1]); - Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)), Is.EqualTo(_values[1])); + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).ToArray(), Is.EqualTo(_values[1])); } /// @@ -281,7 +281,7 @@ public void Tload_same_address_same_index_different_values_restore(int snapshot) provider.Restore(snapshots[snapshot + 1]); - Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 1)), Is.EqualTo(_values[snapshot + 1])); + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[snapshot + 1])); } /// @@ -294,7 +294,7 @@ public void Commit_resets_transient_state() WorldState provider = BuildStorageProvider(ctx); provider.SetTransientState(new StorageCell(ctx.Address1, 2), _values[1]); - Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)), Is.EqualTo(_values[1])); + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).ToArray(), Is.EqualTo(_values[1])); provider.Commit(Frontier.Instance); Assert.True(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).IsZero()); @@ -310,7 +310,7 @@ public void Reset_resets_transient_state() WorldState provider = BuildStorageProvider(ctx); provider.SetTransientState(new StorageCell(ctx.Address1, 2), _values[1]); - Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)), Is.EqualTo(_values[1])); + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).ToArray(), Is.EqualTo(_values[1])); provider.Reset(); Assert.True(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).IsZero()); @@ -358,7 +358,7 @@ public void Transient_state_restores_independent_of_persistent_state(int snapsho snapshots[2].StorageSnapshot.Should().BeEquivalentTo(new Snapshot.Storage(0, 1)); snapshots[3].StorageSnapshot.Should().BeEquivalentTo(new Snapshot.Storage(1, 1)); - _values[snapshot + 1].Should().BeEquivalentTo(provider.GetTransientState(new StorageCell(ctx.Address1, 1))); + _values[snapshot + 1].Should().BeEquivalentTo(provider.GetTransientState(new StorageCell(ctx.Address1, 1)).ToArray()); } /// @@ -406,7 +406,7 @@ public void Persistent_state_restores_independent_of_transient_state(int snapsho new Snapshot(Snapshot.EmptyPosition, new Snapshot.Storage(1, 1)) ); - _values[snapshot + 1].Should().BeEquivalentTo(provider.Get(new StorageCell(ctx.Address1, 1))); + _values[snapshot + 1].Should().BeEquivalentTo(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray()); } private class Context diff --git a/src/Nethermind/Nethermind.State/IStateReader.cs b/src/Nethermind/Nethermind.State/IStateReader.cs index d4750ed840a..990b035a003 100644 --- a/src/Nethermind/Nethermind.State/IStateReader.cs +++ b/src/Nethermind/Nethermind.State/IStateReader.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Int256; @@ -12,7 +13,7 @@ public interface IStateReader { Account? GetAccount(Hash256 stateRoot, Address address); - byte[]? GetStorage(Hash256 stateRoot, Address address, in UInt256 index); + Span GetStorage(Hash256 stateRoot, Address address, in UInt256 index); byte[]? GetCode(Hash256 codeHash); diff --git a/src/Nethermind/Nethermind.State/IWorldState.cs b/src/Nethermind/Nethermind.State/IWorldState.cs index b25ef558f67..ddcaf3fa279 100644 --- a/src/Nethermind/Nethermind.State/IWorldState.cs +++ b/src/Nethermind/Nethermind.State/IWorldState.cs @@ -27,7 +27,7 @@ public interface IWorldState : IJournal, IReadOnlyStateProvider /// /// Storage location /// Value at cell - byte[] Get(in StorageCell storageCell); + Span Get(in StorageCell storageCell); /// /// Set the provided value to persistent storage at the specified storage cell @@ -41,7 +41,7 @@ public interface IWorldState : IJournal, IReadOnlyStateProvider /// /// Storage location /// Value at cell - byte[] GetTransientState(in StorageCell storageCell); + Span GetTransientState(in StorageCell storageCell); /// /// Set the provided value to transient storage at the specified storage cell diff --git a/src/Nethermind/Nethermind.State/PartialStorageProviderBase.cs b/src/Nethermind/Nethermind.State/PartialStorageProviderBase.cs index 1ca8de11af6..77eff0d27aa 100644 --- a/src/Nethermind/Nethermind.State/PartialStorageProviderBase.cs +++ b/src/Nethermind/Nethermind.State/PartialStorageProviderBase.cs @@ -41,7 +41,7 @@ protected PartialStorageProviderBase(ILogManager? logManager) /// /// Storage location /// Value at cell - public byte[] Get(in StorageCell storageCell) + public Span Get(in StorageCell storageCell) { return GetCurrentValue(storageCell); } @@ -235,7 +235,7 @@ protected bool TryGetCachedValue(in StorageCell storageCell, out byte[]? bytes) /// /// Storage location /// Value at location - protected abstract byte[] GetCurrentValue(in StorageCell storageCell); + protected abstract Span GetCurrentValue(in StorageCell storageCell); /// /// Update the storage cell with provided value diff --git a/src/Nethermind/Nethermind.State/PersistentStorageProvider.cs b/src/Nethermind/Nethermind.State/PersistentStorageProvider.cs index f4180447dc7..c0cdceaad00 100644 --- a/src/Nethermind/Nethermind.State/PersistentStorageProvider.cs +++ b/src/Nethermind/Nethermind.State/PersistentStorageProvider.cs @@ -60,7 +60,7 @@ public override void Reset() /// /// Storage location /// Value at location - protected override byte[] GetCurrentValue(in StorageCell storageCell) => + protected override Span GetCurrentValue(in StorageCell storageCell) => TryGetCachedValue(storageCell, out byte[]? bytes) ? bytes! : LoadFromTree(storageCell); /// @@ -234,7 +234,7 @@ private StorageTree GetOrCreateStorage(Address address) return value; } - private byte[] LoadFromTree(in StorageCell storageCell) + private Span LoadFromTree(in StorageCell storageCell) { StorageTree tree = GetOrCreateStorage(storageCell.Address); diff --git a/src/Nethermind/Nethermind.State/Proofs/AccountProofCollector.cs b/src/Nethermind/Nethermind.State/Proofs/AccountProofCollector.cs index e63ed8d41c3..9e304c54199 100644 --- a/src/Nethermind/Nethermind.State/Proofs/AccountProofCollector.cs +++ b/src/Nethermind/Nethermind.State/Proofs/AccountProofCollector.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Int256; using Nethermind.Serialization.Rlp; using Nethermind.Trie; @@ -89,7 +90,7 @@ public AccountProofCollector(ReadOnlySpan hashedAddress, ValueHash256[] ke _accountProof.StorageProofs[i] = new StorageProof(); // we don't know the key (index) //_accountProof.StorageProofs[i].Key = storageKeys[i]; - _accountProof.StorageProofs[i].Value = new byte[] { 0 }; + _accountProof.StorageProofs[i].Value = Bytes.ZeroByte; } } @@ -117,7 +118,7 @@ public AccountProofCollector(ReadOnlySpan hashedAddress, params byte[][] s _accountProof.StorageProofs[i] = new StorageProof(); _accountProof.StorageProofs[i].Key = storageKeys[i]; - _accountProof.StorageProofs[i].Value = new byte[] { 0 }; + _accountProof.StorageProofs[i].Value = Bytes.ZeroByte; } } diff --git a/src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs b/src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs index e5908f5aabb..f453d7a4c14 100644 --- a/src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs +++ b/src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Linq; +using Nethermind.Core.Buffers; using Nethermind.Core.Crypto; using Nethermind.Serialization.Rlp; using Nethermind.Trie; diff --git a/src/Nethermind/Nethermind.State/StateReader.cs b/src/Nethermind/Nethermind.State/StateReader.cs index 459c5ea6d91..f5744f841de 100644 --- a/src/Nethermind/Nethermind.State/StateReader.cs +++ b/src/Nethermind/Nethermind.State/StateReader.cs @@ -4,6 +4,7 @@ using System; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Db; using Nethermind.Int256; using Nethermind.Logging; @@ -33,7 +34,7 @@ public StateReader(ITrieStore? trieStore, IKeyValueStore? codeDb, ILogManager? l return GetState(stateRoot, address); } - public byte[] GetStorage(Hash256 stateRoot, Address address, in UInt256 index) + public Span GetStorage(Hash256 stateRoot, Address address, in UInt256 index) { Account? account = GetAccount(stateRoot, address); if (account is null) return null; @@ -41,10 +42,11 @@ public byte[] GetStorage(Hash256 stateRoot, Address address, in UInt256 index) Hash256 storageRoot = account.StorageRoot; if (storageRoot == Keccak.EmptyTreeHash) { - return new byte[] { 0 }; + return Bytes.ZeroByte; } Metrics.StorageTreeReads++; + return _storage.Get(index, storageRoot); } diff --git a/src/Nethermind/Nethermind.State/StateTree.cs b/src/Nethermind/Nethermind.State/StateTree.cs index 582c14e000e..49a63f8c6f3 100644 --- a/src/Nethermind/Nethermind.State/StateTree.cs +++ b/src/Nethermind/Nethermind.State/StateTree.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Diagnostics; using Nethermind.Core; using Nethermind.Core.Buffers; @@ -36,15 +37,15 @@ public StateTree(ITrieStore? store, ILogManager? logManager) [DebuggerStepThrough] public Account? Get(Address address, Hash256? rootHash = null) { - byte[]? bytes = Get(ValueKeccak.Compute(address.Bytes).BytesAsSpan, rootHash); - return bytes is null ? null : _decoder.Decode(bytes.AsRlpStream()); + Span bytes = Get(ValueKeccak.Compute(address.Bytes).BytesAsSpan, rootHash); + return bytes.IsEmpty ? null : _decoder.Decode(bytes); } [DebuggerStepThrough] internal Account? Get(Hash256 keccak) // for testing { - byte[]? bytes = Get(keccak.Bytes); - return bytes is null ? null : _decoder.Decode(bytes.AsRlpStream()); + Span bytes = Get(keccak.Bytes); + return bytes.IsEmpty ? null : _decoder.Decode(bytes); } public void Set(Address address, Account? account) diff --git a/src/Nethermind/Nethermind.State/StorageTree.cs b/src/Nethermind/Nethermind.State/StorageTree.cs index 395e1baa10e..a0139b47268 100644 --- a/src/Nethermind/Nethermind.State/StorageTree.cs +++ b/src/Nethermind/Nethermind.State/StorageTree.cs @@ -66,14 +66,14 @@ public byte[] Get(in UInt256 index, Hash256? storageRoot = null) Span key = stackalloc byte[32]; GetKey(index, key); - return Get(key, storageRoot); + return Get(key, storageRoot).ToArray(); } - public override byte[] Get(ReadOnlySpan rawKey, Hash256? rootHash = null) + public override Span Get(ReadOnlySpan rawKey, Hash256? rootHash = null) { - byte[]? value = base.Get(rawKey, rootHash); + Span value = base.Get(rawKey, rootHash); - if (value is null) + if (value.IsEmpty) { return _emptyBytes; } diff --git a/src/Nethermind/Nethermind.State/TransientStorageProvider.cs b/src/Nethermind/Nethermind.State/TransientStorageProvider.cs index 9c1c9d8fde9..7f0820fc626 100644 --- a/src/Nethermind/Nethermind.State/TransientStorageProvider.cs +++ b/src/Nethermind/Nethermind.State/TransientStorageProvider.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using Nethermind.Core; using Nethermind.Logging; @@ -20,7 +21,7 @@ public TransientStorageProvider(ILogManager? logManager) /// /// Storage location /// Value at cell - protected override byte[] GetCurrentValue(in StorageCell storageCell) => + protected override Span GetCurrentValue(in StorageCell storageCell) => TryGetCachedValue(storageCell, out byte[]? bytes) ? bytes! : _zeroValue; } } diff --git a/src/Nethermind/Nethermind.State/WorldState.cs b/src/Nethermind/Nethermind.State/WorldState.cs index 4d93ab22831..7c612e4997d 100644 --- a/src/Nethermind/Nethermind.State/WorldState.cs +++ b/src/Nethermind/Nethermind.State/WorldState.cs @@ -66,7 +66,7 @@ public byte[] GetOriginal(in StorageCell storageCell) { return _persistentStorageProvider.GetOriginal(storageCell); } - public byte[] Get(in StorageCell storageCell) + public Span Get(in StorageCell storageCell) { return _persistentStorageProvider.Get(storageCell); } @@ -74,7 +74,7 @@ public void Set(in StorageCell storageCell, byte[] newValue) { _persistentStorageProvider.Set(storageCell, newValue); } - public byte[] GetTransientState(in StorageCell storageCell) + public Span GetTransientState(in StorageCell storageCell) { return _transientStorageProvider.Get(storageCell); } diff --git a/src/Nethermind/Nethermind.Synchronization/LesSync/CanonicalHashTrie.cs b/src/Nethermind/Nethermind.Synchronization/LesSync/CanonicalHashTrie.cs index bbfd520eaef..9c1fecfbd49 100644 --- a/src/Nethermind/Nethermind.Synchronization/LesSync/CanonicalHashTrie.cs +++ b/src/Nethermind/Nethermind.Synchronization/LesSync/CanonicalHashTrie.cs @@ -102,8 +102,8 @@ public void Set(BlockHeader header) public (Hash256?, UInt256) Get(Span key) { - byte[]? val = base.Get(key); - if (val is null) + Span val = base.Get(key); + if (val.IsEmpty) { throw new InvalidDataException("Missing CHT data"); } diff --git a/src/Nethermind/Nethermind.Synchronization/LesSync/ChtDecoder.cs b/src/Nethermind/Nethermind.Synchronization/LesSync/ChtDecoder.cs index 50ca5e4277c..7fbfbb7e82e 100644 --- a/src/Nethermind/Nethermind.Synchronization/LesSync/ChtDecoder.cs +++ b/src/Nethermind/Nethermind.Synchronization/LesSync/ChtDecoder.cs @@ -8,7 +8,7 @@ namespace Nethermind.Synchronization.LesSync { - public class ChtDecoder : IRlpStreamDecoder<(Hash256?, UInt256)> + public class ChtDecoder : IRlpStreamDecoder<(Hash256?, UInt256)>, IRlpValueDecoder<(Hash256?, UInt256)> { public (Hash256?, UInt256) Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { @@ -53,5 +53,19 @@ private static int GetContentLength((Hash256?, UInt256) item, RlpBehaviors rlpBe (Hash256? hash, UInt256 totalDifficulty) = item; return Rlp.LengthOf(hash) + Rlp.LengthOf(totalDifficulty); } + + public (Hash256?, UInt256) Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + if (decoderContext.IsNextItemNull()) + { + decoderContext.ReadByte(); + return (null, 0); + } + + decoderContext.ReadSequenceLength(); + Hash256 hash = decoderContext.DecodeKeccak(); + UInt256 totalDifficulty = decoderContext.DecodeUInt256(); + return (hash, totalDifficulty); + } } } diff --git a/src/Nethermind/Nethermind.Synchronization/Trie/HealingStateTree.cs b/src/Nethermind/Nethermind.Synchronization/Trie/HealingStateTree.cs index 8d38d46c9cf..75f11e95d65 100644 --- a/src/Nethermind/Nethermind.Synchronization/Trie/HealingStateTree.cs +++ b/src/Nethermind/Nethermind.Synchronization/Trie/HealingStateTree.cs @@ -27,7 +27,7 @@ public void InitializeNetwork(ITrieNodeRecovery recovery) _recovery = recovery; } - public override byte[]? Get(ReadOnlySpan rawKey, Hash256? rootHash = null) + public override Span Get(ReadOnlySpan rawKey, Hash256? rootHash = null) { try { diff --git a/src/Nethermind/Nethermind.Synchronization/Trie/HealingStorageTree.cs b/src/Nethermind/Nethermind.Synchronization/Trie/HealingStorageTree.cs index d3fb0a13d50..6288d16f009 100644 --- a/src/Nethermind/Nethermind.Synchronization/Trie/HealingStorageTree.cs +++ b/src/Nethermind/Nethermind.Synchronization/Trie/HealingStorageTree.cs @@ -26,7 +26,7 @@ public HealingStorageTree(ITrieStore? trieStore, Hash256 rootHash, ILogManager? _recovery = recovery; } - public override byte[]? Get(ReadOnlySpan rawKey, Hash256? rootHash = null) + public override Span Get(ReadOnlySpan rawKey, Hash256? rootHash = null) { try { diff --git a/src/Nethermind/Nethermind.Trie.Test/PruningScenariosTests.cs b/src/Nethermind/Nethermind.Trie.Test/PruningScenariosTests.cs index 9ce405ed6a5..7b69f8c3856 100644 --- a/src/Nethermind/Nethermind.Trie.Test/PruningScenariosTests.cs +++ b/src/Nethermind/Nethermind.Trie.Test/PruningScenariosTests.cs @@ -213,7 +213,7 @@ public PruningContext VerifyAccountBalance(int account, int balance) public PruningContext VerifyStorageValue(int account, UInt256 index, int value) { - _stateProvider.Get(new StorageCell(Address.FromNumber((UInt256)account), index)) + _stateProvider.Get(new StorageCell(Address.FromNumber((UInt256)account), index)).ToArray() .Should().BeEquivalentTo(((UInt256)value).ToBigEndian()); return this; } diff --git a/src/Nethermind/Nethermind.Trie.Test/TrieTests.cs b/src/Nethermind/Nethermind.Trie.Test/TrieTests.cs index fc3e1a734bc..8e97d737f7b 100644 --- a/src/Nethermind/Nethermind.Trie.Test/TrieTests.cs +++ b/src/Nethermind/Nethermind.Trie.Test/TrieTests.cs @@ -81,8 +81,8 @@ public void Single_leaf_update_same_block() memDb.Keys.Should().HaveCount(1); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().NotBeEquivalentTo(_longLeaf1); - checkTree.Get(_keyA).Should().BeEquivalentTo(_longLeaf2); + checkTree.Get(_keyA).ToArray().Should().NotBeEquivalentTo(_longLeaf1); + checkTree.Get(_keyA).ToArray().Should().BeEquivalentTo(_longLeaf2); } [Test] @@ -101,8 +101,8 @@ public void Single_leaf_update_next_blocks() memDb.Keys.Should().HaveCount(2); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().NotBeEquivalentTo(_longLeaf1); - checkTree.Get(_keyA).Should().BeEquivalentTo(_longLeaf2); + checkTree.Get(_keyA).ToArray().Should().NotBeEquivalentTo(_longLeaf1); + checkTree.Get(_keyA).ToArray().Should().BeEquivalentTo(_longLeaf2); } [Test] @@ -119,7 +119,7 @@ public void Single_leaf_delete_same_block() memDb.Keys.Should().HaveCount(0); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().BeNull(); + checkTree.Get(_keyA).ToArray().Should().BeNull(); } [Test] @@ -138,7 +138,7 @@ public void Single_leaf_delete_next_block() memDb.Keys.Should().HaveCount(1); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().BeNull(); + checkTree.Get(_keyA).ToArray().Should().BeNull(); } [Test] @@ -171,8 +171,8 @@ public void Single_leaf_and_keep_for_multiple_dispatches_then_delete() memDb.Keys.Should().HaveCount(2); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().BeNull(); - checkTree.Get(_keyB).Should().BeNull(); + checkTree.Get(_keyA).ToArray().Should().BeNull(); + checkTree.Get(_keyB).ToArray().Should().BeNull(); } [Test] @@ -189,9 +189,9 @@ public void Branch_with_branch_and_leaf() // leaf (root) memDb.Keys.Should().HaveCount(6); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyB).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyC).Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyA).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyB).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyC).ToArray().Should().BeEquivalentTo(_longLeaf1); } // [Test] @@ -225,9 +225,9 @@ public void Branch_with_branch_and_leaf_then_deleted() // leaf (root) memDb.Keys.Should().HaveCount(6); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().BeNull(); - checkTree.Get(_keyB).Should().BeNull(); - checkTree.Get(_keyC).Should().BeNull(); + checkTree.Get(_keyA).ToArray().Should().BeNull(); + checkTree.Get(_keyB).ToArray().Should().BeNull(); + checkTree.Get(_keyC).ToArray().Should().BeNull(); } public void Test_add_many(int i) @@ -251,7 +251,7 @@ public void Test_add_many(int i) { Hash256 key = TestItem.Keccaks[j]; byte[] value = TestItem.GenerateIndexedAccountRlp(j); - checkTree.Get(key.Bytes).Should().BeEquivalentTo(value, $@"{i} {j}"); + checkTree.Get(key.Bytes).ToArray().Should().BeEquivalentTo(value, $@"{i} {j}"); } } @@ -285,14 +285,14 @@ public void Test_try_delete_and_read_missing_nodes(int i) { Hash256 key = TestItem.Keccaks[j]; byte[] value = TestItem.GenerateIndexedAccountRlp(j); - checkTree.Get(key.Bytes).Should().BeEquivalentTo(value, $@"{i} {j}"); + checkTree.Get(key.Bytes).ToArray().Should().BeEquivalentTo(value, $@"{i} {j}"); } // read missing for (int j = 0; j < i; j++) { Hash256 key = TestItem.Keccaks[j + 100]; - checkTree.Get(key.Bytes).Should().BeNull(); + checkTree.Get(key.Bytes).ToArray().Should().BeNull(); } } @@ -324,7 +324,7 @@ public void Test_update_many(int i) { Hash256 key = TestItem.Keccaks[j]; byte[] value = TestItem.GenerateIndexedAccountRlp(j + 1); - checkTree.Get(key.Bytes).Should().BeEquivalentTo(value, $@"{i} {j}"); + checkTree.Get(key.Bytes).ToArray().Should().BeEquivalentTo(value, $@"{i} {j}"); } } @@ -361,7 +361,7 @@ public void Test_update_many_next_block(int i) byte[] value = TestItem.GenerateIndexedAccountRlp(j + 1); _logger.Trace($"Checking {key.Bytes.ToHexString()} = {value.ToHexString()}"); - checkTree.Get(key.Bytes).Should().BeEquivalentTo(value, $@"{i} {j}"); + checkTree.Get(key.Bytes).ToArray().Should().BeEquivalentTo(value, $@"{i} {j}"); } } @@ -393,7 +393,7 @@ public void Test_add_and_delete_many_same_block(int i) for (int j = 0; j < i; j++) { Hash256 key = TestItem.Keccaks[j]; - checkTree.Get(key.Bytes).Should().BeNull($@"{i} {j}"); + checkTree.Get(key.Bytes).ToArray().Should().BeNull($@"{i} {j}"); } } @@ -425,7 +425,7 @@ public void Test_add_and_delete_many_next_block(int i) for (int j = 0; j < i; j++) { Hash256 key = TestItem.Keccaks[j]; - checkTree.Get(key.Bytes).Should().BeNull($@"{i} {j}"); + checkTree.Get(key.Bytes).ToArray().Should().BeNull($@"{i} {j}"); } } @@ -461,10 +461,10 @@ public void Two_branches_exactly_same_leaf() // leaf (root) memDb.Keys.Should().HaveCount(5); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyB).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyC).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyD).Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyA).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyB).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyC).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyD).ToArray().Should().BeEquivalentTo(_longLeaf1); } [Test] @@ -487,10 +487,10 @@ public void Two_branches_exactly_same_leaf_then_one_removed() // leaf (root) memDb.Keys.Should().HaveCount(6); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().BeNull(); - checkTree.Get(_keyB).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyC).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyD).Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyA).ToArray().Should().BeNull(); + checkTree.Get(_keyB).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyC).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyD).ToArray().Should().BeEquivalentTo(_longLeaf1); } private static PatriciaTree CreateCheckTree(MemDb memDb, PatriciaTree patriciaTree) @@ -511,8 +511,8 @@ public void Extension_with_branch_with_two_different_children() patriciaTree.Commit(0); memDb.Keys.Should().HaveCount(4); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyB).Should().BeEquivalentTo(_longLeaf2); + checkTree.Get(_keyA).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyB).ToArray().Should().BeEquivalentTo(_longLeaf2); } [Test] @@ -526,8 +526,8 @@ public void Extension_with_branch_with_two_same_children() patriciaTree.Commit(0); memDb.Keys.Should().HaveCount(4); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyB).Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyA).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyB).ToArray().Should().BeEquivalentTo(_longLeaf1); } [Test] @@ -568,8 +568,8 @@ public void When_branch_with_two_same_children_change_one_and_change_back_next_b memDb.Keys.Should().HaveCount(4); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyB).Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyA).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyB).ToArray().Should().BeEquivalentTo(_longLeaf1); } [Test] @@ -598,9 +598,9 @@ L L - - - - - - - - - - - - - - */ memDb.Keys.Should().HaveCount(7); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(key1).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(key2).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(key3).Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(key1).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(key2).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(key3).ToArray().Should().BeEquivalentTo(_longLeaf1); } [Test] @@ -649,9 +649,9 @@ L L - - - - - - - - - - - - - - */ memDb.Keys.Should().HaveCount(8); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(key1).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(key2).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(key3).Should().BeNull(); + checkTree.Get(key1).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(key2).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(key3).ToArray().Should().BeNull(); } [Test] @@ -673,10 +673,10 @@ public void When_two_branches_with_two_same_children_change_one_and_change_back_ memDb.Keys.Should().HaveCount(5); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyB).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyC).Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(_keyD).Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyA).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyB).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyC).ToArray().Should().BeEquivalentTo(_longLeaf1); + checkTree.Get(_keyD).ToArray().Should().BeEquivalentTo(_longLeaf1); } // [TestCase(256, 128, 128, 32)] diff --git a/src/Nethermind/Nethermind.Trie/PatriciaTree.cs b/src/Nethermind/Nethermind.Trie/PatriciaTree.cs index 3330ae28aaa..c46239591ad 100644 --- a/src/Nethermind/Nethermind.Trie/PatriciaTree.cs +++ b/src/Nethermind/Nethermind.Trie/PatriciaTree.cs @@ -355,7 +355,7 @@ private void SetRootHash(Hash256? value, bool resetObjects) [SkipLocalsInit] [DebuggerStepThrough] - public virtual byte[]? Get(ReadOnlySpan rawKey, Hash256? rootHash = null) + public virtual Span Get(ReadOnlySpan rawKey, Hash256? rootHash = null) { try { @@ -367,10 +367,10 @@ private void SetRootHash(Hash256? value, bool resetObjects) [..nibblesCount]; // Slice to exact size; Nibbles.BytesToNibbleBytes(rawKey, nibbles); - var result = Run(nibbles, nibblesCount, in CappedArray.Empty, isUpdate: false, startRootHash: rootHash).ToArray(); + var result = Run(nibbles, nibblesCount, in CappedArray.Empty, isUpdate: false, startRootHash: rootHash); if (array is not null) ArrayPool.Shared.Return(array); - return result; + return result.AsSpan(); } catch (TrieException e) { From 351d35d5befef13632577054fec881259c475d68 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Wed, 24 Jan 2024 01:10:02 +0100 Subject: [PATCH 03/16] AccountStruct --- .../Ethereum.Test.Base/BlockchainTestBase.cs | 4 +- .../AccountAbstractionRpcModuleTests.cs | 2 +- .../UserOperationTracerTests.cs | 4 +- .../Executor/UserOperationSimulator.cs | 4 +- .../GeneratedTxSourceSealerTests.cs | 2 +- .../SpecificBlockReadOnlyStateProvider.cs | 35 ++++---------- src/Nethermind/Nethermind.Core/Account.cs | 41 +++++++++++++++- .../Nethermind.Core/Crypto/Hash256.cs | 1 + .../Crypto/ValueHash256Converter.cs | 29 ++++++++++++ .../Nethermind.Core/IAccountStateProvider.cs | 2 +- .../Nethermind.Evm.Test/Eip1014Tests.cs | 2 +- .../Nethermind.Evm/VirtualMachine.cs | 9 ++-- .../Modules/TraceRpcModuleTests.cs | 6 +-- .../Nethermind.JsonRpc/Data/AccountForRpc.cs | 20 +++++--- .../Modules/Eth/EthRpcModule.cs | 24 ++++------ .../Modules/Eth/IEthRpcModule.cs | 2 +- .../EngineModuleTests.HelperFunctions.cs | 8 ++-- .../Nethermind.Mev.Test/TestBundlePool.cs | 2 +- .../AccountDecoder.cs | 47 +++++++++++++++++++ .../Nethermind.Serialization.Rlp/Rlp.cs | 27 +++++++++++ .../IReadOnlyStateProvider.cs | 10 ++-- .../Nethermind.State/IStateReader.cs | 3 +- .../Nethermind.State/IWorldState.cs | 2 +- .../Nethermind.State/IWorldStateExtensions.cs | 2 +- .../Nethermind.State/StateProvider.cs | 13 ++--- .../Nethermind.State/StateReader.cs | 30 +++++------- .../Nethermind.State/StateReaderExtensions.cs | 4 +- src/Nethermind/Nethermind.State/StateTree.cs | 8 ++++ .../Nethermind.State/StorageTree.cs | 1 + src/Nethermind/Nethermind.State/WorldState.cs | 21 ++++++++- .../NonceManagerTests.cs | 4 +- .../TransactionPoolInfoProviderTests.cs | 2 +- .../Collections/TxDistinctSortedPool.cs | 8 ++-- .../Filters/BalanceTooLowFilter.cs | 2 +- .../Filters/BalanceZeroFilter.cs | 2 +- .../Filters/LowNonceFilter.cs | 2 +- .../Nethermind.TxPool/TxFilteringState.cs | 4 +- src/Nethermind/Nethermind.TxPool/TxPool.cs | 6 +-- 38 files changed, 274 insertions(+), 121 deletions(-) create mode 100644 src/Nethermind/Nethermind.Core/Crypto/ValueHash256Converter.cs diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs index 844ac274c1c..c002949c647 100644 --- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs +++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs @@ -406,7 +406,7 @@ private List RunAssertions(BlockchainTest test, Block headBlock, IWorldS foreach (KeyValuePair clearedStorage in clearedStorages) { - byte[] value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key)); + Span value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key)); if (!value.IsZero()) { differences.Add($"{acountAddress} storage[{clearedStorage.Key}] exp: 0x00, actual: {value.ToHexString(true)}"); @@ -415,7 +415,7 @@ private List RunAssertions(BlockchainTest test, Block headBlock, IWorldS foreach (KeyValuePair storageItem in accountState.Storage) { - byte[] value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key)) ?? new byte[0]; + Span value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key)); if (!Bytes.AreEqual(storageItem.Value, value)) { differences.Add($"{acountAddress} storage[{storageItem.Key}] exp: {storageItem.Value.ToHexString(true)}, actual: {value.ToHexString(true)}"); diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.cs index 026dfdb5063..a08ba710e10 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.cs @@ -222,7 +222,7 @@ public async Task Should_execute_well_formed_op_successfully_if_codehash_not_cha chain.SendUserOperation(entryPointAddress[0], op); if (changeCodeHash) { - chain.State.InsertCode(walletAddress[0]!, Bytes.Concat(chain.State.GetCode(walletAddress[0]!), 0x00), chain.SpecProvider.GenesisSpec); + chain.State.InsertCode(walletAddress[0]!, Bytes.Concat(chain.State.GetCode(walletAddress[0]!)!, 0x00), chain.SpecProvider.GenesisSpec); chain.State.Commit(chain.SpecProvider.GenesisSpec); chain.State.RecalculateStateRoot(); chain.State.CommitTree(chain.BlockTree.Head!.Number); diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationTracerTests.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationTracerTests.cs index 4e546819c4b..b3131f01e94 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationTracerTests.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationTracerTests.cs @@ -145,8 +145,8 @@ public void Should_make_sure_external_contract_extcodehashes_stays_same_after_si .Op(Instruction.STOP) .Done; - Hash256 initialCodeHash = TestState.GetCodeHash(externalContractAddress); - (UserOperationTxTracer tracer, _, _) = ExecuteAndTraceAccessCall(SenderRecipientAndMiner.Default, code, whitelisted); + ValueHash256 initialCodeHash = TestState.GetCodeHash(externalContractAddress); + ExecuteAndTraceAccessCall(SenderRecipientAndMiner.Default, code, whitelisted); if (shouldMatch) { TestState.GetCodeHash(externalContractAddress).Should().Be(initialCodeHash); diff --git a/src/Nethermind/Nethermind.AccountAbstraction/Executor/UserOperationSimulator.cs b/src/Nethermind/Nethermind.AccountAbstraction/Executor/UserOperationSimulator.cs index cf762b719d6..2bcb6a7a940 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction/Executor/UserOperationSimulator.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction/Executor/UserOperationSimulator.cs @@ -77,7 +77,7 @@ public ResultWrapper Simulate(UserOperation userOperation, foreach (KeyValuePair kv in userOperation.AddressesToCodeHashes) { (Address address, Hash256 expectedCodeHash) = kv; - Hash256 codeHash = _stateProvider.GetCodeHash(address); + ValueHash256 codeHash = _stateProvider.GetCodeHash(address); if (codeHash != expectedCodeHash) { return ResultWrapper.Fail($"codehash of address {address} changed since initial simulation"); @@ -148,7 +148,7 @@ private UserOperationSimulationResult SimulateValidation( IDictionary addressesToCodeHashes = new Dictionary(); foreach (Address accessedAddress in txTracer.AccessedAddresses) { - addressesToCodeHashes[accessedAddress] = _stateProvider.GetCodeHash(accessedAddress); + addressesToCodeHashes[accessedAddress] = new Hash256(_stateProvider.GetCodeHash(accessedAddress)); } return new UserOperationSimulationResult() diff --git a/src/Nethermind/Nethermind.AuRa.Test/Transactions/GeneratedTxSourceSealerTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Transactions/GeneratedTxSourceSealerTests.cs index 76447cde3f3..ebb8669a677 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Transactions/GeneratedTxSourceSealerTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Transactions/GeneratedTxSourceSealerTests.cs @@ -32,7 +32,7 @@ public void transactions_are_addable_to_block_after_sealing() Address nodeAddress = TestItem.AddressA; UInt256 expectedNonce = 10; - stateReader.GetAccount(blockHeader.StateRoot, nodeAddress).Returns(Account.TotallyEmpty.WithChangedNonce(expectedNonce)); + stateReader.GetAccount(blockHeader.StateRoot, nodeAddress).Returns(new AccountStruct(expectedNonce, UInt256.Zero)); ulong expectedTimeStamp = 100; timestamper.UnixTime.Returns(UnixTime.FromSeconds(expectedTimeStamp)); diff --git a/src/Nethermind/Nethermind.Blockchain/SpecificBlockReadOnlyStateProvider.cs b/src/Nethermind/Nethermind.Blockchain/SpecificBlockReadOnlyStateProvider.cs index 8cff916445a..a2a4de1f3fc 100644 --- a/src/Nethermind/Nethermind.Blockchain/SpecificBlockReadOnlyStateProvider.cs +++ b/src/Nethermind/Nethermind.Blockchain/SpecificBlockReadOnlyStateProvider.cs @@ -22,7 +22,7 @@ public SpecificBlockReadOnlyStateProvider(IStateReader stateReader, Hash256? sta public virtual Hash256 StateRoot { get; } - public Account GetAccount(Address address) => _stateReader.GetAccount(StateRoot, address) ?? Account.TotallyEmpty; + public AccountStruct GetAccount(Address address) => _stateReader.GetAccount(StateRoot, address) ?? default; public bool IsContract(Address address) => GetAccount(address).IsContract; @@ -30,26 +30,18 @@ public SpecificBlockReadOnlyStateProvider(IStateReader stateReader, Hash256? sta public UInt256 GetBalance(Address address) => GetAccount(address).Balance; - public Hash256? GetStorageRoot(Address address) => GetAccount(address).StorageRoot; + public ValueHash256 GetStorageRoot(Address address) => GetAccount(address).StorageRoot; - public byte[] GetCode(Address address) + public byte[]? GetCode(Address address) { - Account account = GetAccount(address); - if (!account.HasCode) - { - return Array.Empty(); - } - - return _stateReader.GetCode(account.CodeHash); + AccountStruct account = GetAccount(address); + return !account.HasCode ? Array.Empty() : _stateReader.GetCode(account.CodeHash); } - public byte[] GetCode(Hash256 codeHash) => _stateReader.GetCode(codeHash); + public byte[]? GetCode(Hash256 codeHash) => _stateReader.GetCode(codeHash); + public byte[]? GetCode(ValueHash256 codeHash) => _stateReader.GetCode(codeHash); - public Hash256 GetCodeHash(Address address) - { - Account account = GetAccount(address); - return account.CodeHash; - } + public ValueHash256 GetCodeHash(Address address) => GetAccount(address).CodeHash; public void Accept(ITreeVisitor visitor, Hash256 stateRoot, VisitingOptions? visitingOptions) { @@ -59,15 +51,8 @@ public void Accept(ITreeVisitor visitor, Hash256 stateRoot, VisitingOptions? vis public bool AccountExists(Address address) => _stateReader.GetAccount(StateRoot, address) is not null; public bool IsEmptyAccount(Address address) => GetAccount(address).IsEmpty; - public bool HasStateForRoot(Hash256 stateRoot) - { - return _stateReader.HasStateForRoot(stateRoot); - } + public bool HasStateForRoot(Hash256 stateRoot) => _stateReader.HasStateForRoot(stateRoot); - public bool IsDeadAccount(Address address) - { - Account account = GetAccount(address); - return account.IsEmpty; - } + public bool IsDeadAccount(Address address) => GetAccount(address).IsEmpty; } } diff --git a/src/Nethermind/Nethermind.Core/Account.cs b/src/Nethermind/Nethermind.Core/Account.cs index 6d0c0688c83..92df94240c9 100644 --- a/src/Nethermind/Nethermind.Core/Account.cs +++ b/src/Nethermind/Nethermind.Core/Account.cs @@ -8,7 +8,7 @@ namespace Nethermind.Core { public class Account { - public static Account TotallyEmpty = new(); + public static readonly Account TotallyEmpty = new(); private readonly Hash256? _codeHash; private readonly Hash256? _storageRoot; @@ -100,5 +100,44 @@ public Account WithChangedCodeHash(Hash256 newCodeHash) { return new(newCodeHash, this); } + + public AccountStruct ToStruct() => new(Nonce, Balance, StorageRoot, CodeHash); + } + + public struct AccountStruct + { + private readonly ValueHash256 _codeHash = Keccak.OfAnEmptyString.ValueHash256; + private readonly ValueHash256 _storageRoot = Keccak.EmptyTreeHash.ValueHash256; + + public AccountStruct(in UInt256 nonce, in UInt256 balance, in ValueHash256 storageRoot, in ValueHash256 codeHash) + { + _codeHash = codeHash; + _storageRoot = storageRoot; + Nonce = nonce; + Balance = balance; + } + + public AccountStruct(in UInt256 nonce, in UInt256 balance) + { + Nonce = nonce; + Balance = balance; + } + + public AccountStruct(in UInt256 balance) + { + Balance = balance; + } + + public bool HasCode => _codeHash != Keccak.OfAnEmptyString.ValueHash256; + + public bool HasStorage => _storageRoot != Keccak.EmptyTreeHash.ValueHash256; + + public UInt256 Nonce { get; } + public UInt256 Balance { get; } + public ValueHash256 StorageRoot => _storageRoot; + public ValueHash256 CodeHash => _codeHash; + public bool IsTotallyEmpty => _storageRoot == Keccak.EmptyTreeHash.ValueHash256 && IsEmpty; + public bool IsEmpty => _codeHash == Keccak.OfAnEmptyString.ValueHash256 && Balance.IsZero && Nonce.IsZero; + public bool IsContract => _codeHash != Keccak.OfAnEmptyString.ValueHash256; } } diff --git a/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs b/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs index 07aad0b8a3b..394253b3342 100644 --- a/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs +++ b/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs @@ -15,6 +15,7 @@ namespace Nethermind.Core.Crypto { [DebuggerStepThrough] [DebuggerDisplay("{ToString()}")] + [JsonConverter(typeof(ValueHash256Converter))] public readonly struct ValueHash256 : IEquatable, IComparable, IEquatable { private readonly Vector256 _bytes; diff --git a/src/Nethermind/Nethermind.Core/Crypto/ValueHash256Converter.cs b/src/Nethermind/Nethermind.Core/Crypto/ValueHash256Converter.cs new file mode 100644 index 00000000000..0f4f0c65757 --- /dev/null +++ b/src/Nethermind/Nethermind.Core/Crypto/ValueHash256Converter.cs @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Nethermind.Core.Crypto; + +namespace Nethermind.Serialization.Json; + +public class ValueHash256Converter : JsonConverter +{ + public override ValueHash256 Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) + { + byte[]? bytes = ByteArrayConverter.Convert(ref reader); + return bytes is null ? null : new ValueHash256(bytes); + } + + public override void Write( + Utf8JsonWriter writer, + ValueHash256 keccak, + JsonSerializerOptions options) + { + ByteArrayConverter.Convert(writer, keccak.Bytes, skipLeadingZeros: false); + } +} diff --git a/src/Nethermind/Nethermind.Core/IAccountStateProvider.cs b/src/Nethermind/Nethermind.Core/IAccountStateProvider.cs index 0f5ccc25728..d43b0527f4b 100644 --- a/src/Nethermind/Nethermind.Core/IAccountStateProvider.cs +++ b/src/Nethermind/Nethermind.Core/IAccountStateProvider.cs @@ -5,6 +5,6 @@ namespace Nethermind.Core { public interface IAccountStateProvider { - Account GetAccount(Address address); + AccountStruct GetAccount(Address address); } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs index 3ec2002df2b..3a7a31de376 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs @@ -110,7 +110,7 @@ public void Test_out_of_gas_existing_account_with_storage() TestState.Commit(Spec); TestState.CommitTree(0); - Hash256 storageRoot = TestState.GetAccount(expectedAddress).StorageRoot; + ValueHash256 storageRoot = TestState.GetAccount(expectedAddress).StorageRoot; storageRoot.Should().NotBe(PatriciaTree.EmptyTreeHash); TestState.CreateAccount(TestItem.AddressC, 1.Ether()); diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index ecb1bee59ac..8d5ad8c49fe 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -23,6 +23,7 @@ using System.Runtime.Intrinsics; using static Nethermind.Evm.VirtualMachine; using static System.Runtime.CompilerServices.Unsafe; +using ValueHash256 = Nethermind.Core.Crypto.ValueHash256; #if DEBUG using Nethermind.Evm.Tracing.Debugger; @@ -533,8 +534,8 @@ public CodeInfo GetCachedCodeInfo(IWorldState worldState, Address codeSource, IR } CodeInfo cachedCodeInfo = null; - Hash256 codeHash = worldState.GetCodeHash(codeSource); - if (ReferenceEquals(codeHash, Keccak.OfAnEmptyString)) + ValueHash256 codeHash = worldState.GetCodeHash(codeSource); + if (codeHash == Keccak.OfAnEmptyString.ValueHash256) { cachedCodeInfo = CodeInfo.Empty; } @@ -542,7 +543,7 @@ public CodeInfo GetCachedCodeInfo(IWorldState worldState, Address codeSource, IR cachedCodeInfo ??= CodeCache.Get(codeHash); if (cachedCodeInfo is null) { - byte[] code = worldState.GetCode(codeHash); + byte[]? code = worldState.GetCode(codeHash); if (code is null) { @@ -563,7 +564,7 @@ public CodeInfo GetCachedCodeInfo(IWorldState worldState, Address codeSource, IR [DoesNotReturn] [StackTraceHidden] - static void MissingCode(Address codeSource, Hash256 codeHash) + static void MissingCode(Address codeSource, in ValueHash256 codeHash) { throw new NullReferenceException($"Code {codeHash} missing in the state for address {codeSource}"); } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs index f4567383645..86797613b53 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs @@ -823,9 +823,9 @@ public async Task Trace_replayBlockTransactions_stateDiff() .WithGasLimit(50000) .WithGasPrice(10).SignedAndResolved(TestItem.PrivateKeyA).TestObject; - Account accountA = blockchain.State.GetAccount(TestItem.AddressA); - Account accountD = blockchain.State.GetAccount(TestItem.AddressD); - Account accountF = blockchain.State.GetAccount(TestItem.AddressF); + AccountStruct accountA = blockchain.State.GetAccount(TestItem.AddressA); + AccountStruct accountD = blockchain.State.GetAccount(TestItem.AddressD); + AccountStruct accountF = blockchain.State.GetAccount(TestItem.AddressF); string[] traceTypes = { "stateDiff" }; diff --git a/src/Nethermind/Nethermind.JsonRpc/Data/AccountForRpc.cs b/src/Nethermind/Nethermind.JsonRpc/Data/AccountForRpc.cs index e8a9693b4b5..4c6fbf730b3 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Data/AccountForRpc.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Data/AccountForRpc.cs @@ -7,17 +7,23 @@ namespace Nethermind.JsonRpc.Data; -public class AccountForRpc +public struct AccountForRpc { - private Account _Account { get; set; } + private readonly Account? _account; + private readonly AccountStruct? _accountStruct; public AccountForRpc(Account account) { - _Account = account; + _account = account; } - public Hash256 CodeHash => _Account.CodeHash; - public Hash256 StorageRoot => _Account.StorageRoot; - public UInt256 Balance => _Account.Balance; - public UInt256 Nonce => _Account.Nonce; + public AccountForRpc(in AccountStruct? account) + { + _accountStruct = account; + } + + public ValueHash256 CodeHash => (_accountStruct?.CodeHash ?? _account?.CodeHash.ValueHash256)!.Value; + public ValueHash256 StorageRoot => (_accountStruct?.StorageRoot ?? _account?.StorageRoot.ValueHash256)!.Value; + public UInt256 Balance => (_accountStruct?.Balance ?? _account?.Balance)!.Value; + public UInt256 Nonce => (_accountStruct?.Nonce ?? _account?.Nonce)!.Value; } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs index c68009a2e9d..c5070e6f77f 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs @@ -162,7 +162,7 @@ public ResultWrapper> eth_accounts() return Task.FromResult(GetStateFailureResult(header)); } - Account account = _stateReader.GetAccount(header!.StateRoot!, address); + AccountStruct? account = _stateReader.GetAccount(header!.StateRoot!, address); return Task.FromResult(ResultWrapper.Success(account?.Balance ?? UInt256.Zero)); } @@ -204,7 +204,7 @@ public Task> eth_getTransactionCount(Address address, Blo return Task.FromResult(GetStateFailureResult(header)); } - Account account = _stateReader.GetAccount(header!.StateRoot!, address); + AccountStruct? account = _stateReader.GetAccount(header!.StateRoot!, address); UInt256 nonce = account?.Nonce ?? 0; return Task.FromResult(ResultWrapper.Success(nonce)); @@ -261,14 +261,8 @@ public ResultWrapper eth_getCode(Address address, BlockParameter? blockP return GetStateFailureResult(header); } - Account account = _stateReader.GetAccount(header!.StateRoot!, address); - if (account is null) - { - return ResultWrapper.Success(Array.Empty()); - } - - byte[]? code = _stateReader.GetCode(account.CodeHash); - return ResultWrapper.Success(code); + AccountStruct? account = _stateReader.GetAccount(header!.StateRoot!, address); + return ResultWrapper.Success(account is null ? Array.Empty() : _stateReader.GetCode(account.Value.CodeHash)); } public ResultWrapper eth_sign(Address addressData, byte[] message) @@ -705,22 +699,22 @@ private static IEnumerable GetLogs(IEnumerable logs, Cance } } - public ResultWrapper eth_getAccount(Address accountAddress, BlockParameter? blockParameter) + public ResultWrapper eth_getAccount(Address accountAddress, BlockParameter? blockParameter) { SearchResult searchResult = _blockFinder.SearchForHeader(blockParameter); if (searchResult.IsError) { - return GetFailureResult(searchResult, _ethSyncingInfo.SyncMode.HaveNotSyncedHeadersYet()); + return GetFailureResult(searchResult, _ethSyncingInfo.SyncMode.HaveNotSyncedHeadersYet()); } BlockHeader header = searchResult.Object; if (!HasStateForBlock(_blockchainBridge, header!)) { - return GetStateFailureResult(header); + return GetStateFailureResult(header); } - Account account = _stateReader.GetAccount(header!.StateRoot!, accountAddress); - return ResultWrapper.Success(account is null ? null : new AccountForRpc(account)); + AccountStruct? account = _stateReader.GetAccount(header!.StateRoot!, accountAddress); + return ResultWrapper.Success(account is null ? null : new AccountForRpc(account.Value)); } private static ResultWrapper GetFailureResult(SearchResult searchResult, bool isTemporary) where TSearch : class => diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/IEthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/IEthRpcModule.cs index 505dafa991d..479c0f24b4e 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/IEthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/IEthRpcModule.cs @@ -261,6 +261,6 @@ ResultWrapper eth_getTransactionByBlockNumberAndIndex( ResultWrapper eth_getProof([JsonRpcParameter(ExampleValue = "[\"0x7F0d15C7FAae65896648C8273B6d7E43f58Fa842\",[ \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\" ],\"latest\"]")] Address accountAddress, UInt256[] hashRate, BlockParameter blockParameter); [JsonRpcMethod(IsImplemented = true, Description = "Retrieves Accounts via Address and Blocknumber", IsSharable = true)] - ResultWrapper eth_getAccount([JsonRpcParameter(ExampleValue = "[\"0xaa00000000000000000000000000000000000000\", \"latest\"]")] Address accountAddress, BlockParameter blockParameter = null); + ResultWrapper eth_getAccount([JsonRpcParameter(ExampleValue = "[\"0xaa00000000000000000000000000000000000000\", \"latest\"]")] Address accountAddress, BlockParameter blockParameter = null); } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs index c58a367c56a..ef3f4add6b1 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs @@ -44,16 +44,16 @@ private void AssertExecutionStatusChanged(IBlockFinder blockFinder, Hash256 head private (UInt256, UInt256) AddTransactions(MergeTestBlockchain chain, ExecutionPayload executePayloadRequest, PrivateKey from, Address to, uint count, int value, out BlockHeader parentHeader) { - Transaction[] transactions = BuildTransactions(chain, executePayloadRequest.ParentHash, from, to, count, value, out Account accountFrom, out parentHeader); + Transaction[] transactions = BuildTransactions(chain, executePayloadRequest.ParentHash, from, to, count, value, out AccountStruct accountFrom, out parentHeader); executePayloadRequest.SetTransactions(transactions); UInt256 totalValue = ((int)(count * value)).GWei(); return (accountFrom.Balance - totalValue, chain.StateReader.GetBalance(parentHeader.StateRoot!, to) + totalValue); } private Transaction[] BuildTransactions(MergeTestBlockchain chain, Hash256 parentHash, PrivateKey from, - Address to, uint count, int value, out Account accountFrom, out BlockHeader parentHeader, int blobCountPerTx = 0) + Address to, uint count, int value, out AccountStruct accountFrom, out BlockHeader parentHeader, int blobCountPerTx = 0) { - Transaction BuildTransaction(uint index, Account senderAccount) => + Transaction BuildTransaction(uint index, AccountStruct senderAccount) => Build.A.Transaction.WithNonce(senderAccount.Nonce + index) .WithTimestamp(Timestamper.UnixTime.Seconds) .WithTo(to) @@ -66,7 +66,7 @@ Transaction BuildTransaction(uint index, Account senderAccount) => .SignedAndResolved(from).TestObject; parentHeader = chain.BlockTree.FindHeader(parentHash, BlockTreeLookupOptions.None)!; - Account account = chain.StateReader.GetAccount(parentHeader.StateRoot!, from.Address)!; + AccountStruct account = chain.StateReader.GetAccount(parentHeader.StateRoot!, from.Address)!.Value; accountFrom = account; return Enumerable.Range(0, (int)count).Select(i => BuildTransaction((uint)i, account)).ToArray(); diff --git a/src/Nethermind/Nethermind.Mev.Test/TestBundlePool.cs b/src/Nethermind/Nethermind.Mev.Test/TestBundlePool.cs index 7320a09bfe5..577c2b61338 100644 --- a/src/Nethermind/Nethermind.Mev.Test/TestBundlePool.cs +++ b/src/Nethermind/Nethermind.Mev.Test/TestBundlePool.cs @@ -74,6 +74,6 @@ public TestBundlePool(IBlockTree blockTree, public class MockProvider : IAccountStateProvider { - public Account GetAccount(Address address) => new Account(0); + public AccountStruct GetAccount(Address address) => new(0); } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs index 41a0c1b876c..6e7b5932275 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs @@ -253,5 +253,52 @@ private Hash256 DecodeCodeHash(ref Rlp.ValueDecoderContext rlpStream) return codeHash; } + + private ValueHash256 DecodeStorageRootStruct(ref Rlp.ValueDecoderContext rlpStream) + { + ValueHash256 storageRoot; + if (_slimFormat && rlpStream.IsNextItemEmptyArray()) + { + rlpStream.ReadByte(); + storageRoot = Keccak.EmptyTreeHash.ValueHash256; + } + else + { + storageRoot = rlpStream.DecodeValueKeccak()!.Value; + } + + return storageRoot; + } + + private ValueHash256 DecodeCodeHashStruct(ref Rlp.ValueDecoderContext rlpStream) + { + ValueHash256 codeHash; + if (_slimFormat && rlpStream.IsNextItemEmptyArray()) + { + rlpStream.ReadByte(); + codeHash = Keccak.OfAnEmptyString.ValueHash256; + } + else + { + codeHash = rlpStream.DecodeValueKeccak()!.Value; + } + + return codeHash; + } + + public AccountStruct? DecodeStruct(ref Rlp.ValueDecoderContext decoderContext) + { + int length = decoderContext.ReadSequenceLength(); + if (length == 1) + { + return null; + } + + UInt256 nonce = decoderContext.DecodeUInt256(); + UInt256 balance = decoderContext.DecodeUInt256(); + ValueHash256 storageRoot = DecodeStorageRootStruct(ref decoderContext); + ValueHash256 codeHash = DecodeCodeHashStruct(ref decoderContext); + return new AccountStruct(nonce, balance, storageRoot, codeHash); + } } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs index 50a6a763db2..d14c2cfaccc 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs @@ -846,6 +846,33 @@ public DecodeKeccakRlpException(in int prefix, in int position, in int dataLengt return new Hash256(keccakSpan); } + public ValueHash256? DecodeValueKeccak() + { + int prefix = ReadByte(); + if (prefix == 128) + { + return null; + } + + if (prefix != 128 + 32) + { + throw new DecodeKeccakRlpException(prefix, Position, Data.Length); + } + + ReadOnlySpan keccakSpan = Read(32); + if (keccakSpan.SequenceEqual(Keccak.OfAnEmptyString.Bytes)) + { + return Keccak.OfAnEmptyString.ValueHash256; + } + + if (keccakSpan.SequenceEqual(Keccak.EmptyTreeHash.Bytes)) + { + return Keccak.EmptyTreeHash.ValueHash256; + } + + return new ValueHash256(keccakSpan); + } + public Hash256? DecodeZeroPrefixKeccak() { int prefix = PeekByte(); diff --git a/src/Nethermind/Nethermind.State/IReadOnlyStateProvider.cs b/src/Nethermind/Nethermind.State/IReadOnlyStateProvider.cs index 71ad0981461..d13754211a9 100644 --- a/src/Nethermind/Nethermind.State/IReadOnlyStateProvider.cs +++ b/src/Nethermind/Nethermind.State/IReadOnlyStateProvider.cs @@ -16,13 +16,15 @@ public interface IReadOnlyStateProvider : IAccountStateProvider UInt256 GetBalance(Address address); - Hash256 GetStorageRoot(Address address); + ValueHash256 GetStorageRoot(Address address); - byte[] GetCode(Address address); + byte[]? GetCode(Address address); - byte[] GetCode(Hash256 codeHash); + byte[]? GetCode(Hash256 codeHash); - Hash256 GetCodeHash(Address address); + byte[]? GetCode(ValueHash256 codeHash); + + ValueHash256 GetCodeHash(Address address); public bool IsContract(Address address); diff --git a/src/Nethermind/Nethermind.State/IStateReader.cs b/src/Nethermind/Nethermind.State/IStateReader.cs index 990b035a003..89ec6972bf6 100644 --- a/src/Nethermind/Nethermind.State/IStateReader.cs +++ b/src/Nethermind/Nethermind.State/IStateReader.cs @@ -11,11 +11,12 @@ namespace Nethermind.State { public interface IStateReader { - Account? GetAccount(Hash256 stateRoot, Address address); + AccountStruct? GetAccount(Hash256 stateRoot, Address address); Span GetStorage(Hash256 stateRoot, Address address, in UInt256 index); byte[]? GetCode(Hash256 codeHash); + byte[]? GetCode(in ValueHash256 codeHash); void RunTreeVisitor(ITreeVisitor treeVisitor, Hash256 stateRoot, VisitingOptions? visitingOptions = null); bool HasStateForRoot(Hash256 stateRoot); diff --git a/src/Nethermind/Nethermind.State/IWorldState.cs b/src/Nethermind/Nethermind.State/IWorldState.cs index ddcaf3fa279..231ba223da8 100644 --- a/src/Nethermind/Nethermind.State/IWorldState.cs +++ b/src/Nethermind/Nethermind.State/IWorldState.cs @@ -109,5 +109,5 @@ public interface IWorldState : IJournal, IReadOnlyStateProvider /// For witness /// /// - void TouchCode(Hash256 codeHash); + void TouchCode(in ValueHash256 codeHash); } diff --git a/src/Nethermind/Nethermind.State/IWorldStateExtensions.cs b/src/Nethermind/Nethermind.State/IWorldStateExtensions.cs index b5e7dc0a99f..22002394efe 100644 --- a/src/Nethermind/Nethermind.State/IWorldStateExtensions.cs +++ b/src/Nethermind/Nethermind.State/IWorldStateExtensions.cs @@ -15,7 +15,7 @@ public static class WorldStateExtensions { public static byte[] GetCode(this IWorldState stateProvider, Address address) { - Account account = stateProvider.GetAccount(address); + AccountStruct account = stateProvider.GetAccount(address); return !account.HasCode ? Array.Empty() : stateProvider.GetCode(account.CodeHash); } diff --git a/src/Nethermind/Nethermind.State/StateProvider.cs b/src/Nethermind/Nethermind.State/StateProvider.cs index 5fd453c0ed9..d0c6b923dca 100644 --- a/src/Nethermind/Nethermind.State/StateProvider.cs +++ b/src/Nethermind/Nethermind.State/StateProvider.cs @@ -307,7 +307,7 @@ public void DecrementNonce(Address address) PushUpdate(address, changedAccount); } - public void TouchCode(Hash256 codeHash) + public void TouchCode(in ValueHash256 codeHash) { if (_codeDb is WitnessingStore witnessingStore) { @@ -324,12 +324,13 @@ public Hash256 GetCodeHash(Address address) public byte[] GetCode(Hash256 codeHash) { byte[]? code = codeHash == Keccak.OfAnEmptyString ? Array.Empty() : _codeDb[codeHash.Bytes]; - if (code is null) - { - throw new InvalidOperationException($"Code {codeHash} is missing from the database."); - } + return code ?? throw new InvalidOperationException($"Code {codeHash} is missing from the database."); + } - return code; + public byte[] GetCode(ValueHash256 codeHash) + { + byte[]? code = codeHash == Keccak.OfAnEmptyString.ValueHash256 ? Array.Empty() : _codeDb[codeHash.Bytes]; + return code ?? throw new InvalidOperationException($"Code {codeHash} is missing from the database."); } public byte[] GetCode(Address address) diff --git a/src/Nethermind/Nethermind.State/StateReader.cs b/src/Nethermind/Nethermind.State/StateReader.cs index f5744f841de..8b6b38d7910 100644 --- a/src/Nethermind/Nethermind.State/StateReader.cs +++ b/src/Nethermind/Nethermind.State/StateReader.cs @@ -29,17 +29,17 @@ public StateReader(ITrieStore? trieStore, IKeyValueStore? codeDb, ILogManager? l _storage = new StorageTree(trieStore, Keccak.EmptyTreeHash, logManager); } - public Account? GetAccount(Hash256 stateRoot, Address address) + public AccountStruct? GetAccount(Hash256 stateRoot, Address address) { return GetState(stateRoot, address); } public Span GetStorage(Hash256 stateRoot, Address address, in UInt256 index) { - Account? account = GetAccount(stateRoot, address); + AccountStruct? account = GetAccount(stateRoot, address); if (account is null) return null; - Hash256 storageRoot = account.StorageRoot; + ValueHash256 storageRoot = account.Value.StorageRoot; if (storageRoot == Keccak.EmptyTreeHash) { return Bytes.ZeroByte; @@ -47,7 +47,7 @@ public Span GetStorage(Hash256 stateRoot, Address address, in UInt256 inde Metrics.StorageTreeReads++; - return _storage.Get(index, storageRoot); + return _storage.Get(index, new Hash256(storageRoot)); } public UInt256 GetBalance(Hash256 stateRoot, Address address) @@ -55,15 +55,7 @@ public UInt256 GetBalance(Hash256 stateRoot, Address address) return GetState(stateRoot, address)?.Balance ?? UInt256.Zero; } - public byte[]? GetCode(Hash256 codeHash) - { - if (codeHash == Keccak.OfAnEmptyString) - { - return Array.Empty(); - } - - return _codeDb[codeHash.Bytes]; - } + public byte[]? GetCode(Hash256 codeHash) => codeHash == Keccak.OfAnEmptyString ? Array.Empty() : _codeDb[codeHash.Bytes]; public void RunTreeVisitor(ITreeVisitor treeVisitor, Hash256 rootHash, VisitingOptions? visitingOptions = null) { @@ -77,13 +69,15 @@ public bool HasStateForRoot(Hash256 stateRoot) return visitor.HasRoot; } - public byte[] GetCode(Hash256 stateRoot, Address address) + public byte[]? GetCode(Hash256 stateRoot, Address address) { - Account? account = GetState(stateRoot, address); - return account is null ? Array.Empty() : GetCode(account.CodeHash); + AccountStruct? account = GetState(stateRoot, address); + return account is null ? Array.Empty() : GetCode(account.Value.CodeHash); } - private Account? GetState(Hash256 stateRoot, Address address) + public byte[]? GetCode(in ValueHash256 codeHash) => codeHash == Keccak.OfAnEmptyString ? Array.Empty() : _codeDb[codeHash.Bytes]; + + private AccountStruct? GetState(Hash256 stateRoot, Address address) { if (stateRoot == Keccak.EmptyTreeHash) { @@ -91,7 +85,7 @@ public byte[] GetCode(Hash256 stateRoot, Address address) } Metrics.StateTreeReads++; - Account? account = _state.Get(address, stateRoot); + AccountStruct? account = _state.GetStruct(address, stateRoot); return account; } } diff --git a/src/Nethermind/Nethermind.State/StateReaderExtensions.cs b/src/Nethermind/Nethermind.State/StateReaderExtensions.cs index 7d2d9168959..bc1435bff1d 100644 --- a/src/Nethermind/Nethermind.State/StateReaderExtensions.cs +++ b/src/Nethermind/Nethermind.State/StateReaderExtensions.cs @@ -21,7 +21,7 @@ public static UInt256 GetBalance(this IStateReader stateReader, Hash256 stateRoo return stateReader.GetAccount(stateRoot, address)?.Balance ?? UInt256.Zero; } - public static Hash256 GetStorageRoot(this IStateReader stateReader, Hash256 stateRoot, Address address) + public static ValueHash256 GetStorageRoot(this IStateReader stateReader, Hash256 stateRoot, Address address) { return stateReader.GetAccount(stateRoot, address)?.StorageRoot ?? Keccak.EmptyTreeHash; } @@ -31,7 +31,7 @@ public static byte[] GetCode(this IStateReader stateReader, Hash256 stateRoot, A return stateReader.GetCode(GetCodeHash(stateReader, stateRoot, address)) ?? Array.Empty(); } - public static Hash256 GetCodeHash(this IStateReader stateReader, Hash256 stateRoot, Address address) + public static ValueHash256 GetCodeHash(this IStateReader stateReader, Hash256 stateRoot, Address address) { return stateReader.GetAccount(stateRoot, address)?.CodeHash ?? Keccak.OfAnEmptyString; } diff --git a/src/Nethermind/Nethermind.State/StateTree.cs b/src/Nethermind/Nethermind.State/StateTree.cs index 49a63f8c6f3..c076a2ff46f 100644 --- a/src/Nethermind/Nethermind.State/StateTree.cs +++ b/src/Nethermind/Nethermind.State/StateTree.cs @@ -41,6 +41,14 @@ public StateTree(ITrieStore? store, ILogManager? logManager) return bytes.IsEmpty ? null : _decoder.Decode(bytes); } + [DebuggerStepThrough] + public AccountStruct? GetStruct(Address address, Hash256? rootHash = null) + { + Span bytes = Get(ValueKeccak.Compute(address.Bytes).BytesAsSpan, rootHash); + Rlp.ValueDecoderContext valueDecoderContext = new Rlp.ValueDecoderContext(bytes); + return bytes.IsEmpty ? null : _decoder.DecodeStruct(ref valueDecoderContext); + } + [DebuggerStepThrough] internal Account? Get(Hash256 keccak) // for testing { diff --git a/src/Nethermind/Nethermind.State/StorageTree.cs b/src/Nethermind/Nethermind.State/StorageTree.cs index a0139b47268..d20ed562292 100644 --- a/src/Nethermind/Nethermind.State/StorageTree.cs +++ b/src/Nethermind/Nethermind.State/StorageTree.cs @@ -69,6 +69,7 @@ public byte[] Get(in UInt256 index, Hash256? storageRoot = null) return Get(key, storageRoot).ToArray(); } + public override Span Get(ReadOnlySpan rawKey, Hash256? rootHash = null) { Span value = base.Get(rawKey, rootHash); diff --git a/src/Nethermind/Nethermind.State/WorldState.cs b/src/Nethermind/Nethermind.State/WorldState.cs index 7c612e4997d..d5cd58b4528 100644 --- a/src/Nethermind/Nethermind.State/WorldState.cs +++ b/src/Nethermind/Nethermind.State/WorldState.cs @@ -57,6 +57,11 @@ public Account GetAccount(Address address) return _stateProvider.GetAccount(address); } + AccountStruct IAccountStateProvider.GetAccount(Address address) + { + return _stateProvider.GetAccount(address).ToStruct(); + } + public bool IsContract(Address address) { return _stateProvider.IsContract(address); @@ -144,7 +149,7 @@ public void CommitTree(long blockNumber) _persistentStorageProvider.StateRoot = _stateProvider.StateRoot; } - public void TouchCode(Hash256 codeHash) + public void TouchCode(in ValueHash256 codeHash) { _stateProvider.TouchCode(codeHash); } @@ -157,7 +162,7 @@ public UInt256 GetBalance(Address address) { return _stateProvider.GetBalance(address); } - public Hash256 GetStorageRoot(Address address) + public ValueHash256 GetStorageRoot(Address address) { return _stateProvider.GetStorageRoot(address); } @@ -169,10 +174,22 @@ public byte[] GetCode(Hash256 codeHash) { return _stateProvider.GetCode(codeHash); } + + public byte[] GetCode(ValueHash256 codeHash) + { + return _stateProvider.GetCode(codeHash); + } + public Hash256 GetCodeHash(Address address) { return _stateProvider.GetCodeHash(address); } + + ValueHash256 IReadOnlyStateProvider.GetCodeHash(Address address) + { + return _stateProvider.GetCodeHash(address); + } + public void Accept(ITreeVisitor visitor, Hash256 stateRoot, VisitingOptions? visitingOptions = null) { _stateProvider.Accept(visitor, stateRoot, visitingOptions); diff --git a/src/Nethermind/Nethermind.TxPool.Test/NonceManagerTests.cs b/src/Nethermind/Nethermind.TxPool.Test/NonceManagerTests.cs index 45455ced528..1544a23fd48 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/NonceManagerTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/NonceManagerTests.cs @@ -116,7 +116,7 @@ public void should_increment_own_transaction_nonces_locally_when_requesting_rese public void should_pick_account_nonce_as_initial_value() { IAccountStateProvider accountStateProvider = Substitute.For(); - Account account = new(0); + AccountStruct account = new(0); accountStateProvider.GetAccount(TestItem.AddressA).Returns(account); _nonceManager = new NonceManager(accountStateProvider); using (NonceLocker locker = _nonceManager.ReserveNonce(TestItem.AddressA, out UInt256 nonce)) @@ -124,7 +124,7 @@ public void should_pick_account_nonce_as_initial_value() nonce.Should().Be(0); } - accountStateProvider.GetAccount(TestItem.AddressA).Returns(account.WithChangedNonce(10)); + accountStateProvider.GetAccount(TestItem.AddressA).Returns(new AccountStruct(10, account.Balance)); using (NonceLocker locker = _nonceManager.ReserveNonce(TestItem.AddressA, out UInt256 nonce)) { nonce.Should().Be(10); diff --git a/src/Nethermind/Nethermind.TxPool.Test/TransactionPoolInfoProviderTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TransactionPoolInfoProviderTests.cs index 7636641aef8..7dbbdec9555 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TransactionPoolInfoProviderTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TransactionPoolInfoProviderTests.cs @@ -33,7 +33,7 @@ public void Setup() public void should_return_valid_pending_and_queued_transactions() { uint nonce = 3; - _stateReader.GetAccount(_address).Returns(Account.TotallyEmpty.WithChangedNonce(nonce)); + _stateReader.GetAccount(_address).Returns(new AccountStruct(nonce, UInt256.Zero)); var transactions = GetTransactions(); _txPool.GetPendingTransactionsBySender() diff --git a/src/Nethermind/Nethermind.TxPool/Collections/TxDistinctSortedPool.cs b/src/Nethermind/Nethermind.TxPool/Collections/TxDistinctSortedPool.cs index abb9a8bd3b7..2aefc29731d 100644 --- a/src/Nethermind/Nethermind.TxPool/Collections/TxDistinctSortedPool.cs +++ b/src/Nethermind/Nethermind.TxPool/Collections/TxDistinctSortedPool.cs @@ -71,7 +71,7 @@ protected override void UpdateGroup(Address groupKey, EnhancedSortedSet, IEnumerable<(Transaction Tx, UInt256? changedGasBottleneck)>> changingElements) + public void UpdatePool(IAccountStateProvider accounts, Func, IEnumerable<(Transaction Tx, UInt256? changedGasBottleneck)>> changingElements) { using var lockRelease = Lock.Acquire(); @@ -79,12 +79,12 @@ public void UpdatePool(IAccountStateProvider accounts, Func 0); - Account? account = accounts.GetAccount(address); + AccountStruct account = accounts.GetAccount(address); UpdateGroupNonLocked(address, account, bucket, changingElements); } } - private void UpdateGroupNonLocked(Address groupKey, Account groupValue, EnhancedSortedSet bucket, Func, IEnumerable<(Transaction Tx, UInt256? changedGasBottleneck)>> changingElements) + private void UpdateGroupNonLocked(Address groupKey, AccountStruct groupValue, EnhancedSortedSet bucket, Func, IEnumerable<(Transaction Tx, UInt256? changedGasBottleneck)>> changingElements) { _transactionsToRemove.Clear(); Transaction? lastElement = bucket.Max; @@ -119,7 +119,7 @@ private void UpdateGroupNonLocked(Address groupKey, Account groupValue, Enhanced } } - public void UpdateGroup(Address groupKey, Account groupValue, Func, IEnumerable<(Transaction Tx, UInt256? changedGasBottleneck)>> changingElements) + public void UpdateGroup(Address groupKey, AccountStruct groupValue, Func, IEnumerable<(Transaction Tx, UInt256? changedGasBottleneck)>> changingElements) { using var lockRelease = Lock.Acquire(); diff --git a/src/Nethermind/Nethermind.TxPool/Filters/BalanceTooLowFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/BalanceTooLowFilter.cs index dc8e0925519..b82335d378f 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/BalanceTooLowFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/BalanceTooLowFilter.cs @@ -31,7 +31,7 @@ public AcceptTxResult Accept(Transaction tx, TxFilteringState state, TxHandlingO return AcceptTxResult.Accepted; } - Account account = state.SenderAccount; + AccountStruct account = state.SenderAccount; UInt256 balance = account.Balance; UInt256 cumulativeCost = UInt256.Zero; diff --git a/src/Nethermind/Nethermind.TxPool/Filters/BalanceZeroFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/BalanceZeroFilter.cs index 30d457dd049..7e45d2e09af 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/BalanceZeroFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/BalanceZeroFilter.cs @@ -23,7 +23,7 @@ public BalanceZeroFilter(bool thereIsPriorityContract, ILogger logger) public AcceptTxResult Accept(Transaction tx, TxFilteringState state, TxHandlingOptions handlingOptions) { - Account account = state.SenderAccount; + AccountStruct account = state.SenderAccount; UInt256 balance = account.Balance; bool isNotLocal = (handlingOptions & TxHandlingOptions.PersistentBroadcast) == 0; diff --git a/src/Nethermind/Nethermind.TxPool/Filters/LowNonceFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/LowNonceFilter.cs index 3d31557ab7e..fb11b413278 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/LowNonceFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/LowNonceFilter.cs @@ -25,7 +25,7 @@ public AcceptTxResult Accept(Transaction tx, TxFilteringState state, TxHandlingO // high-priority garbage transactions. We need to filter them as much as possible to use the tx pool space // efficiently. One call to get account from state is not that costly and it only happens after previous checks. // This was modeled by OpenEthereum behavior. - Account account = state.SenderAccount; + AccountStruct account = state.SenderAccount; UInt256 currentNonce = account.Nonce; if (tx.Nonce < currentNonce) { diff --git a/src/Nethermind/Nethermind.TxPool/TxFilteringState.cs b/src/Nethermind/Nethermind.TxPool/TxFilteringState.cs index c07749c183c..38dff33f54b 100644 --- a/src/Nethermind/Nethermind.TxPool/TxFilteringState.cs +++ b/src/Nethermind/Nethermind.TxPool/TxFilteringState.cs @@ -17,6 +17,6 @@ public TxFilteringState(Transaction tx, IAccountStateProvider accounts) _tx = tx; } - private Account? _senderAccount = null; - public Account SenderAccount { get { return _senderAccount ??= _accounts.GetAccount(_tx.SenderAddress!); } } + private AccountStruct? _senderAccount = null; + public AccountStruct SenderAccount { get { return _senderAccount ??= _accounts.GetAccount(_tx.SenderAddress!); } } } diff --git a/src/Nethermind/Nethermind.TxPool/TxPool.cs b/src/Nethermind/Nethermind.TxPool/TxPool.cs index 0ff64aa839f..e83a16ee82b 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPool.cs @@ -52,7 +52,7 @@ public class TxPool : ITxPool, IDisposable private readonly Channel _headBlocksChannel = Channel.CreateUnbounded(new UnboundedChannelOptions() { SingleReader = true, SingleWriter = true }); - private readonly Func, IEnumerable<(Transaction Tx, UInt256? changedGasBottleneck)>> _updateBucket; + private readonly Func, IEnumerable<(Transaction Tx, UInt256? changedGasBottleneck)>> _updateBucket; /// /// Indexes transactions @@ -485,7 +485,7 @@ private AcceptTxResult AddCore(Transaction tx, TxFilteringState state, bool isPe } private IEnumerable<(Transaction Tx, UInt256? changedGasBottleneck)> UpdateBucketWithAddedTransaction( - Address address, Account account, EnhancedSortedSet transactions) + Address address, AccountStruct account, EnhancedSortedSet transactions) { if (transactions.Count != 0) { @@ -560,7 +560,7 @@ private void UpdateBuckets() _blobTransactions.UpdatePool(_accounts, _updateBucket); } - private IEnumerable<(Transaction Tx, UInt256? changedGasBottleneck)> UpdateBucket(Address address, Account account, EnhancedSortedSet transactions) + private IEnumerable<(Transaction Tx, UInt256? changedGasBottleneck)> UpdateBucket(Address address, AccountStruct account, EnhancedSortedSet transactions) { if (transactions.Count != 0) { From 5d5af5158f846c8e1d3f3a9d09f107a74f76aa04 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Wed, 24 Jan 2024 01:29:11 +0100 Subject: [PATCH 04/16] fix --- src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs b/src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs index e5908f5aabb..f453d7a4c14 100644 --- a/src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs +++ b/src/Nethermind/Nethermind.State/Proofs/ProofVerifier.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Linq; +using Nethermind.Core.Buffers; using Nethermind.Core.Crypto; using Nethermind.Serialization.Rlp; using Nethermind.Trie; From 7835b2d5a4faf15ee61797b4a9d3962b63583d66 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Wed, 24 Jan 2024 02:00:36 +0100 Subject: [PATCH 05/16] fix mock --- .../Nethermind.Trie.Test/TrieNodeTests.cs | 82 ++++++++++++++----- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs b/src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs index a67cad39c11..85ace68d993 100644 --- a/src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs +++ b/src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Threading.Tasks; using FluentAssertions; using Nethermind.Core; @@ -339,7 +340,7 @@ public void Unknown_node_with_missing_data_can_accept_visitor() [Test] public void Leaf_with_simple_account_can_accept_visitors() { - ITreeVisitor visitor = Substitute.For(); + TreeVisitorMock visitor = new(); TrieVisitContext context = new(); Account account = new(100); AccountDecoder decoder = new(); @@ -347,13 +348,13 @@ public void Leaf_with_simple_account_can_accept_visitors() node.Accept(visitor, NullTrieNodeResolver.Instance, context); - visitor.Received().VisitLeaf(node, context, node.Value.ToArray()); + visitor.VisitLeafReceived[(node, context, node.Value.ToArray())].Should().Be(1); } [Test] public void Leaf_with_contract_without_storage_and_empty_code_can_accept_visitors() { - ITreeVisitor visitor = Substitute.For(); + TreeVisitorMock visitor = new(); TrieVisitContext context = new(); Account account = new(1, 100, Keccak.EmptyTreeHash, Keccak.OfAnEmptyString); AccountDecoder decoder = new(); @@ -361,13 +362,13 @@ public void Leaf_with_contract_without_storage_and_empty_code_can_accept_visitor node.Accept(visitor, NullTrieNodeResolver.Instance, context); - visitor.Received().VisitLeaf(node, context, node.Value.ToArray()); + visitor.VisitLeafReceived[(node, context, node.Value.ToArray())].Should().Be(1); } [Test] public void Leaf_with_contract_without_storage_and_with_code_can_accept_visitors() { - ITreeVisitor visitor = Substitute.For(); + TreeVisitorMock visitor = new(); visitor.ShouldVisit(Arg.Any()).Returns(true); TrieVisitContext context = new(); @@ -377,15 +378,13 @@ public void Leaf_with_contract_without_storage_and_with_code_can_accept_visitors node.Accept(visitor, NullTrieNodeResolver.Instance, context); - visitor.Received().VisitLeaf(node, context, node.Value.ToArray()); + visitor.VisitLeafReceived[(node, context, node.Value.ToArray())].Should().Be(1); } [Test] public void Leaf_with_contract_with_storage_and_without_code_can_accept_visitors() { - ITreeVisitor visitor = Substitute.For(); - visitor.ShouldVisit(Arg.Any()).Returns(true); - + TreeVisitorMock visitor = new(); TrieVisitContext context = new(); Account account = new(1, 100, Keccak.Zero, Keccak.OfAnEmptyString); AccountDecoder decoder = new(); @@ -393,32 +392,28 @@ public void Leaf_with_contract_with_storage_and_without_code_can_accept_visitors node.Accept(visitor, NullTrieNodeResolver.Instance, context); - visitor.Received().VisitLeaf(node, context, node.Value.ToArray()); + visitor.VisitLeafReceived[(node, context, node.Value.ToArray())].Should().Be(1); } [Test] public void Extension_with_leaf_can_be_visited() { Context ctx = new(); - ITreeVisitor visitor = Substitute.For(); - visitor.ShouldVisit(Arg.Any()).Returns(true); - + TreeVisitorMock visitor = new(); TrieVisitContext context = new(); TrieNode node = TrieNodeFactory.CreateExtension(Bytes.FromHexString("aa"), ctx.AccountLeaf); node.Accept(visitor, NullTrieNodeResolver.Instance, context); - visitor.Received().VisitExtension(node, context); - visitor.Received().VisitLeaf(ctx.AccountLeaf, context, ctx.AccountLeaf.Value.ToArray()); + visitor.VisitExtensionReceived[(node, context)].Should().Be(1); + visitor.VisitLeafReceived[(ctx.AccountLeaf, context, ctx.AccountLeaf.Value.ToArray())].Should().Be(1); } [Test] public void Branch_with_children_can_be_visited() { Context ctx = new(); - ITreeVisitor visitor = Substitute.For(); - visitor.ShouldVisit(Arg.Any()).Returns(true); - + TreeVisitorMock visitor = new(); TrieVisitContext context = new(); TrieNode node = new(NodeType.Branch); for (int i = 0; i < 16; i++) @@ -428,8 +423,8 @@ public void Branch_with_children_can_be_visited() node.Accept(visitor, NullTrieNodeResolver.Instance, context); - visitor.Received().VisitBranch(node, context); - visitor.Received(16).VisitLeaf(ctx.AccountLeaf, context, ctx.AccountLeaf.Value.ToArray()); + visitor.VisitBranchReceived[(node, context)].Should().Be(1); + visitor.VisitLeafReceived[(ctx.AccountLeaf, context, ctx.AccountLeaf.Value.ToArray())].Should().Be(16); } [Test] @@ -967,5 +962,52 @@ public Context() decoder.Encode(account).Bytes); } } + + private class TreeVisitorMock : ITreeVisitor + { + public readonly Dictionary<(TrieNode, TrieVisitContext), int> VisitExtensionReceived = new(); + public readonly Dictionary<(TrieNode, TrieVisitContext), int> VisitBranchReceived = new(); + public readonly Dictionary<(TrieNode, TrieVisitContext, byte[]), int> VisitLeafReceived = new(new LeafComparer()); + + public bool IsFullDbScan => true; + + public bool ShouldVisit(Hash256 nextNode) => true; + + public void VisitTree(Hash256 rootHash, TrieVisitContext trieVisitContext) + { + } + + public void VisitMissingNode(Hash256 nodeHash, TrieVisitContext trieVisitContext) + { + } + + public void VisitBranch(TrieNode node, TrieVisitContext trieVisitContext) + { + CollectionsMarshal.GetValueRefOrAddDefault(VisitBranchReceived, (node, trieVisitContext), out _) += 1; + } + + public void VisitExtension(TrieNode node, TrieVisitContext trieVisitContext) + { + CollectionsMarshal.GetValueRefOrAddDefault(VisitExtensionReceived, (node, trieVisitContext), out _) += 1; + } + + public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value) + { + CollectionsMarshal.GetValueRefOrAddDefault(VisitLeafReceived, (node, trieVisitContext, value.ToArray()), out _) += 1; + } + + public void VisitCode(Hash256 codeHash, TrieVisitContext trieVisitContext) + { + } + + private class LeafComparer : IEqualityComparer<(TrieNode, TrieVisitContext, byte[])> + { + public bool Equals((TrieNode, TrieVisitContext, byte[]) x, (TrieNode, TrieVisitContext, byte[]) y) => + Equals(x.Item1, y.Item1) && Equals(x.Item2, y.Item2) && Bytes.EqualityComparer.Equals(x.Item3, y.Item3); + + public int GetHashCode((TrieNode, TrieVisitContext, byte[]) obj) => + HashCode.Combine(obj.Item1, obj.Item2, Bytes.EqualityComparer.GetHashCode(obj.Item3)); + } + } } } From 0e25bda11446ab7be7977782d3f827a9a7ed5a48 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Wed, 24 Jan 2024 02:05:05 +0100 Subject: [PATCH 06/16] missed one --- src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs b/src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs index 85ace68d993..e05894649c2 100644 --- a/src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs +++ b/src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs @@ -369,8 +369,6 @@ public void Leaf_with_contract_without_storage_and_empty_code_can_accept_visitor public void Leaf_with_contract_without_storage_and_with_code_can_accept_visitors() { TreeVisitorMock visitor = new(); - visitor.ShouldVisit(Arg.Any()).Returns(true); - TrieVisitContext context = new(); Account account = new(1, 100, Keccak.EmptyTreeHash, Keccak.Zero); AccountDecoder decoder = new(); From 43db963d6cefbad81a3df9df492ff96ef605ed9c Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Wed, 24 Jan 2024 08:32:33 +0100 Subject: [PATCH 07/16] fix ethereum tests --- src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs index 844ac274c1c..c002949c647 100644 --- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs +++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs @@ -406,7 +406,7 @@ private List RunAssertions(BlockchainTest test, Block headBlock, IWorldS foreach (KeyValuePair clearedStorage in clearedStorages) { - byte[] value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key)); + Span value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key)); if (!value.IsZero()) { differences.Add($"{acountAddress} storage[{clearedStorage.Key}] exp: 0x00, actual: {value.ToHexString(true)}"); @@ -415,7 +415,7 @@ private List RunAssertions(BlockchainTest test, Block headBlock, IWorldS foreach (KeyValuePair storageItem in accountState.Storage) { - byte[] value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key)) ?? new byte[0]; + Span value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key)); if (!Bytes.AreEqual(storageItem.Value, value)) { differences.Add($"{acountAddress} storage[{storageItem.Key}] exp: {storageItem.Value.ToHexString(true)}, actual: {value.ToHexString(true)}"); From 69c1ab8f84d6a08d2130a3ee0da16cdc11aa3501 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Wed, 24 Jan 2024 08:37:16 +0100 Subject: [PATCH 08/16] fix dependencies --- src/Nethermind/Nethermind.Core/Crypto/Keccak.cs | 9 ++++----- src/Nethermind/Nethermind.Core/Nethermind.Core.csproj | 5 ----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/Nethermind/Nethermind.Core/Crypto/Keccak.cs b/src/Nethermind/Nethermind.Core/Crypto/Keccak.cs index 318ae899c45..c8b3a6eedcc 100644 --- a/src/Nethermind/Nethermind.Core/Crypto/Keccak.cs +++ b/src/Nethermind/Nethermind.Core/Crypto/Keccak.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using Nethermind.Serialization.Rlp; namespace Nethermind.Core.Crypto { @@ -21,12 +20,12 @@ public static class ValueKeccak /// /// 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347 /// - public static readonly ValueHash256 OfAnEmptySequenceRlp = InternalCompute([Rlp.NullObjectByte]); + public static readonly ValueHash256 OfAnEmptySequenceRlp = InternalCompute([192]); /// /// 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421 /// - public static readonly ValueHash256 EmptyTreeHash = InternalCompute([Rlp.EmptyArrayByte]); + public static readonly ValueHash256 EmptyTreeHash = InternalCompute([128]); /// /// 0x0000000000000000000000000000000000000000000000000000000000000000 @@ -88,12 +87,12 @@ public static class Keccak /// /// 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347 /// - public static readonly Hash256 OfAnEmptySequenceRlp = new Hash256(ValueKeccak.InternalCompute([Rlp.NullObjectByte])); + public static readonly Hash256 OfAnEmptySequenceRlp = new Hash256(ValueKeccak.InternalCompute([192])); /// /// 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421 /// - public static Hash256 EmptyTreeHash = new Hash256(ValueKeccak.InternalCompute([Rlp.EmptyArrayByte])); + public static Hash256 EmptyTreeHash = new Hash256(ValueKeccak.InternalCompute([128])); /// /// 0x0000000000000000000000000000000000000000000000000000000000000000 diff --git a/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj b/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj index cd0cc16548b..6ddeabf9513 100644 --- a/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj +++ b/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj @@ -16,9 +16,4 @@ - - - ..\artifacts\bin\Nethermind.Evm.Test\debug\Nethermind.Serialization.Rlp.dll - - From eab6aac8cdf2775d9c52248367f959488f83b5ac Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Wed, 24 Jan 2024 09:14:28 +0100 Subject: [PATCH 09/16] more ReadOnlyMemory/Span --- .../ByteReadOnlyMemoryConverter.cs | 23 ++++++ .../Nethermind.Core/Extensions/Bytes.cs | 25 ++++--- .../NullableByteReadOnlyMemoryConverter.cs | 25 +++++++ src/Nethermind/Nethermind.Evm/EvmStack.cs | 4 +- .../Nethermind.Evm/IVirtualMachine.cs | 3 +- src/Nethermind/Nethermind.Evm/StatusCode.cs | 5 +- .../Nethermind.Evm/Tracing/ITxTracer.cs | 2 +- .../Nethermind.Evm/VirtualMachine.cs | 43 +++++------- .../Modules/Eth/EthRpcModule.cs | 8 +-- .../EthereumJsonSerializer.cs | 11 +-- .../CompactLogEntryDecoder.cs | 4 +- .../Nethermind.Serialization.Rlp/Rlp.cs | 4 +- .../Nethermind.Serialization.Rlp/RlpStream.cs | 4 +- .../ValueRlpStream.cs | 2 +- .../Proofs/AccountProofCollectorTests.cs | 70 +++++++++---------- .../Nethermind.State/IStateReader.cs | 2 +- .../Nethermind.State/Proofs/StorageProof.cs | 4 +- .../Nethermind.State/StateReader.cs | 4 +- 18 files changed, 142 insertions(+), 101 deletions(-) create mode 100644 src/Nethermind/Nethermind.Core/ByteReadOnlyMemoryConverter.cs create mode 100644 src/Nethermind/Nethermind.Core/NullableByteReadOnlyMemoryConverter.cs diff --git a/src/Nethermind/Nethermind.Core/ByteReadOnlyMemoryConverter.cs b/src/Nethermind/Nethermind.Core/ByteReadOnlyMemoryConverter.cs new file mode 100644 index 00000000000..d551fc02a93 --- /dev/null +++ b/src/Nethermind/Nethermind.Core/ByteReadOnlyMemoryConverter.cs @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Nethermind.Serialization.Json; + +public class ByteReadOnlyMemoryConverter : JsonConverter> +{ + public override ReadOnlyMemory Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) => + ByteArrayConverter.Convert(ref reader); + + public override void Write( + Utf8JsonWriter writer, + ReadOnlyMemory bytes, + JsonSerializerOptions options) => + ByteArrayConverter.Convert(writer, bytes.Span, skipLeadingZeros: false); +} diff --git a/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs b/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs index 1c19a6ede66..a18a3fc6416 100644 --- a/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs +++ b/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs @@ -27,8 +27,8 @@ public static unsafe partial class Bytes public static readonly IEqualityComparer NullableEqualityComparer = new NullableBytesEqualityComparer(); public static readonly ISpanEqualityComparer SpanEqualityComparer = new SpanBytesEqualityComparer(); public static readonly BytesComparer Comparer = new(); - public static readonly byte[] ZeroByte = [0]; - public static readonly byte[] OneByte = [1]; + public static readonly ReadOnlyMemory ZeroByte = new byte[] { 0 }; + public static readonly ReadOnlyMemory OneByte = new byte[] { 1 }; private class BytesEqualityComparer : EqualityComparer { @@ -200,26 +200,28 @@ public static int TrailingZerosCount(this byte[] bytes) return lastIndex < 0 ? bytes.Length : bytes.Length - lastIndex - 1; } - public static Span WithoutLeadingZeros(this byte[] bytes) + public static ReadOnlySpan WithoutLeadingZeros(this byte[] bytes) { return bytes.AsSpan().WithoutLeadingZeros(); } - public static Span WithoutLeadingZerosOrEmpty(this byte[] bytes) + public static ReadOnlySpan WithoutLeadingZerosOrEmpty(this byte[] bytes) { if (bytes is null || bytes.Length == 0) return Array.Empty(); return bytes.AsSpan().WithoutLeadingZeros(); } - public static Span WithoutLeadingZerosOrEmpty(this Span bytes) + public static ReadOnlySpan WithoutLeadingZerosOrEmpty(this Span bytes) => + ((ReadOnlySpan)bytes).WithoutLeadingZeros(); + + public static ReadOnlySpan WithoutLeadingZeros(this Span bytes) { - if (bytes.IsNullOrEmpty()) return Array.Empty(); - return bytes.WithoutLeadingZeros(); + return ((ReadOnlySpan)bytes).WithoutLeadingZeros(); } - public static Span WithoutLeadingZeros(this Span bytes) + public static ReadOnlySpan WithoutLeadingZeros(this ReadOnlySpan bytes) { - if (bytes.Length == 0) return ZeroByte; + if (bytes.Length == 0) return ZeroByte.Span; int nonZeroIndex = bytes.IndexOfAnyExcept((byte)0); // Keep one or it will be interpreted as null @@ -237,7 +239,10 @@ public static byte[] Concat(byte prefix, byte[] bytes) public static byte[] PadLeft(this byte[] bytes, int length, byte padding = 0) => bytes.Length == length ? bytes : bytes.AsSpan().PadLeft(length, padding); - public static byte[] PadLeft(this Span bytes, int length, byte padding = 0) + public static byte[] PadLeft(this Span bytes, int length, byte padding = 0) => + ((ReadOnlySpan)bytes).PadLeft(length, padding); + + public static byte[] PadLeft(this ReadOnlySpan bytes, int length, byte padding = 0) { if (bytes.Length == length) { diff --git a/src/Nethermind/Nethermind.Core/NullableByteReadOnlyMemoryConverter.cs b/src/Nethermind/Nethermind.Core/NullableByteReadOnlyMemoryConverter.cs new file mode 100644 index 00000000000..e49442928b4 --- /dev/null +++ b/src/Nethermind/Nethermind.Core/NullableByteReadOnlyMemoryConverter.cs @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Nethermind.Serialization.Json; + +public class NullableByteReadOnlyMemoryConverter : JsonConverter?> +{ + public override ReadOnlyMemory? Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) => + ByteArrayConverter.Convert(ref reader); + + public override void Write( + Utf8JsonWriter writer, + ReadOnlyMemory? bytes, + JsonSerializerOptions options) => + ByteArrayConverter.Convert(writer, bytes is null ? ReadOnlySpan.Empty : bytes.Value.Span, skipLeadingZeros: false); +} diff --git a/src/Nethermind/Nethermind.Evm/EvmStack.cs b/src/Nethermind/Nethermind.Evm/EvmStack.cs index 76fa8cc4066..122510d1f6c 100644 --- a/src/Nethermind/Nethermind.Evm/EvmStack.cs +++ b/src/Nethermind/Nethermind.Evm/EvmStack.cs @@ -106,7 +106,7 @@ public void PushByte(byte value) } } - private static ReadOnlySpan OneStackItem() => Bytes.OneByte; + private static ReadOnlySpan OneStackItem() => Bytes.OneByte.Span; public void PushOne() { @@ -121,7 +121,7 @@ public void PushOne() } } - private static ReadOnlySpan ZeroStackItem() => Bytes.ZeroByte; + private static ReadOnlySpan ZeroStackItem() => Bytes.ZeroByte.Span; public void PushZero() { diff --git a/src/Nethermind/Nethermind.Evm/IVirtualMachine.cs b/src/Nethermind/Nethermind.Evm/IVirtualMachine.cs index ffe5b0a613f..8fc865a0d82 100644 --- a/src/Nethermind/Nethermind.Evm/IVirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/IVirtualMachine.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; @@ -18,6 +19,6 @@ TransactionSubstate Run(EvmState state, IWorldState worldState, where TTracingActions : struct, IIsTracing; CodeInfo GetCachedCodeInfo(IWorldState worldState, Address codeSource, IReleaseSpec spec); - void InsertCode(byte[] code, Address codeOwner, IReleaseSpec spec); + void InsertCode(ReadOnlyMemory code, Address codeOwner, IReleaseSpec spec); } } diff --git a/src/Nethermind/Nethermind.Evm/StatusCode.cs b/src/Nethermind/Nethermind.Evm/StatusCode.cs index bfbc5d3e83b..67d23340f69 100644 --- a/src/Nethermind/Nethermind.Evm/StatusCode.cs +++ b/src/Nethermind/Nethermind.Evm/StatusCode.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using Nethermind.Core.Extensions; namespace Nethermind.Evm @@ -8,8 +9,8 @@ namespace Nethermind.Evm public static class StatusCode { public const byte Failure = 0; - public static readonly byte[] FailureBytes = Bytes.ZeroByte; + public static readonly ReadOnlyMemory FailureBytes = Bytes.ZeroByte; public const byte Success = 1; - public static readonly byte[] SuccessBytes = Bytes.OneByte; + public static readonly ReadOnlyMemory SuccessBytes = Bytes.OneByte; } } diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs index 92626270871..fe56eb78b85 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs @@ -349,7 +349,7 @@ void LoadOperationTransientStorage(Address storageCellAddress, UInt256 storageIn /// /// /// Depends on - void ReportActionRevert(long gasLeft, byte[] output) => ReportActionError(EvmExceptionType.Revert); + void ReportActionRevert(long gasLeft, ReadOnlyMemory output) => ReportActionError(EvmExceptionType.Revert); /// /// diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index ecb1bee59ac..d02c015ec4d 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -88,7 +88,7 @@ public VirtualMachine( public CodeInfo GetCachedCodeInfo(IWorldState worldState, Address codeSource, IReleaseSpec spec) => _evm.GetCachedCodeInfo(worldState, codeSource, spec); - public void InsertCode(byte[] code, Address codeOwner, IReleaseSpec spec) + public void InsertCode(ReadOnlyMemory code, Address codeOwner, IReleaseSpec spec) { _evm.InsertCode(code, codeOwner, spec); } @@ -177,7 +177,7 @@ public CallResult(byte[] output, bool? precompileSuccess, bool shouldRevert = fa } public EvmState? StateToExecute { get; } - public byte[] Output { get; } + public ReadOnlyMemory Output { get; } public EvmExceptionType ExceptionType { get; } public bool ShouldRevert { get; } public bool? PrecompileSuccess { get; } // TODO: check this behaviour as it seems it is required and previously that was not the case @@ -201,7 +201,7 @@ internal sealed class VirtualMachine : IVirtualMachine where TLogger : private IWorldState _state; private readonly Stack _stateStack = new(); private (Address Address, bool ShouldDelete) _parityTouchBugAccount = (Address.FromNumber(3), false); - private byte[] _returnDataBuffer = Array.Empty(); + private ReadOnlyMemory _returnDataBuffer = Array.Empty(); private ITxTracer _txTracer = NullTxTracer.Instance; public VirtualMachine( @@ -224,7 +224,7 @@ public TransactionSubstate Run(EvmState state, IWorldState worl IReleaseSpec spec = _specProvider.GetSpec(state.Env.TxExecutionContext.BlockExecutionContext.Header.Number, state.Env.TxExecutionContext.BlockExecutionContext.Header.Timestamp); EvmState currentState = state; - byte[] previousCallResult = null; + ReadOnlyMemory? previousCallResult = null; ZeroPaddedSpan previousCallOutput = ZeroPaddedSpan.Empty; UInt256 previousCallOutputDestination = UInt256.Zero; bool isTracing = _txTracer.IsTracing; @@ -391,7 +391,7 @@ public TransactionSubstate Run(EvmState state, IWorldState worl bool invalidCode = CodeDepositHandler.CodeIsInvalid(spec, callResult.Output); if (gasAvailableForCodeDeposit >= codeDepositGasCost && !invalidCode) { - var code = callResult.Output; + ReadOnlyMemory code = callResult.Output; InsertCode(code, callCodeOwner, spec); currentState.GasAvailable -= codeDepositGasCost; @@ -427,7 +427,7 @@ public TransactionSubstate Run(EvmState state, IWorldState worl { _returnDataBuffer = callResult.Output; previousCallResult = callResult.PrecompileSuccess.HasValue ? (callResult.PrecompileSuccess.Value ? StatusCode.SuccessBytes : StatusCode.FailureBytes) : StatusCode.SuccessBytes; - previousCallOutput = callResult.Output.AsSpan().SliceWithZeroPadding(0, Math.Min(callResult.Output.Length, (int)previousState.OutputLength)); + previousCallOutput = callResult.Output.Span.SliceWithZeroPadding(0, Math.Min(callResult.Output.Length, (int)previousState.OutputLength)); previousCallOutputDestination = (ulong)previousState.OutputDestination; if (previousState.IsPrecompile) { @@ -454,7 +454,7 @@ public TransactionSubstate Run(EvmState state, IWorldState worl worldState.Restore(previousState.Snapshot); _returnDataBuffer = callResult.Output; previousCallResult = StatusCode.FailureBytes; - previousCallOutput = callResult.Output.AsSpan().SliceWithZeroPadding(0, Math.Min(callResult.Output.Length, (int)previousState.OutputLength)); + previousCallOutput = callResult.Output.Span.SliceWithZeroPadding(0, Math.Min(callResult.Output.Length, (int)previousState.OutputLength)); previousCallOutputDestination = (ulong)previousState.OutputDestination; @@ -501,13 +501,13 @@ public TransactionSubstate Run(EvmState state, IWorldState worl } } - public void InsertCode(byte[] code, Address callCodeOwner, IReleaseSpec spec) + public void InsertCode(ReadOnlyMemory code, Address callCodeOwner, IReleaseSpec spec) { var codeInfo = new CodeInfo(code); // Start generating the JumpDestinationBitmap in background. ThreadPool.UnsafeQueueUserWorkItem(codeInfo, preferLocal: false); - Hash256 codeHash = code.Length == 0 ? Keccak.OfAnEmptyString : Keccak.Compute(code.AsSpan()); + Hash256 codeHash = code.Length == 0 ? Keccak.OfAnEmptyString : Keccak.Compute(code.Span); _state.InsertCode(callCodeOwner, codeHash, code, spec); CodeCache.Set(codeHash, codeInfo); } @@ -719,7 +719,7 @@ private CallResult ExecutePrecompile(EvmState state, IReleaseSpec spec) /// values at compile time. /// [SkipLocalsInit] - private CallResult ExecuteCall(EvmState vmState, byte[]? previousCallResult, ZeroPaddedSpan previousCallOutput, scoped in UInt256 previousCallOutputDestination, IReleaseSpec spec) + private CallResult ExecuteCall(EvmState vmState, ReadOnlyMemory? previousCallResult, ZeroPaddedSpan previousCallOutput, scoped in UInt256 previousCallOutputDestination, IReleaseSpec spec) where TTracingInstructions : struct, IIsTracing { ref readonly ExecutionEnvironment env = ref vmState.Env; @@ -755,7 +755,7 @@ private CallResult ExecuteCall(EvmState vmState, byte[]? p if (previousCallResult is not null) { - stack.PushBytes(previousCallResult); + stack.PushBytes(previousCallResult.Value.Span); if (typeof(TTracingInstructions) == typeof(IsTracing)) _txTracer.ReportOperationRemainingGas(vmState.GasAvailable); } @@ -1468,7 +1468,7 @@ private CallResult ExecuteCode bytes = stack.PopWord256(); + ReadOnlySpan bytes = stack.PopWord256(); bool newIsZero = bytes.IsZero(); - if (!newIsZero) - { - bytes = bytes.WithoutLeadingZeros(); - } - else - { - bytes = BytesZero; - } + bytes = !newIsZero ? bytes.WithoutLeadingZeros() : BytesZero; StorageCell storageCell = new(vmState.Env.ExecutingAccount, result); @@ -2750,10 +2743,10 @@ private EvmExceptionType InstructionSStore valueToStore = newIsZero ? BytesZero : bytes; - bytes = new byte[32]; // do not stackalloc here - storageCell.Index.ToBigEndian(bytes); - _txTracer.ReportStorageChange(bytes, valueToStore); + ReadOnlySpan valueToStore = newIsZero ? BytesZero.AsSpan() : bytes; + byte[] storageBytes = new byte[32]; // do not stackalloc here + storageCell.Index.ToBigEndian(storageBytes); + _txTracer.ReportStorageChange(storageBytes, valueToStore); } if (typeof(TTracingStorage) == typeof(IsTracing)) diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs index c68009a2e9d..20faf6b650e 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs @@ -176,12 +176,8 @@ public ResultWrapper eth_getStorageAt(Address address, UInt256 positionI } BlockHeader? header = searchResult.Object; - Span storage = _stateReader.GetStorage(header!.StateRoot!, address, positionIndex); - if (storage.IsEmpty) - { - return ResultWrapper.Success(Array.Empty()); - } - return ResultWrapper.Success(storage!.PadLeft(32)); + ReadOnlySpan storage = _stateReader.GetStorage(header!.StateRoot!, address, positionIndex); + return ResultWrapper.Success(storage.IsEmpty ? Array.Empty() : storage!.PadLeft(32)); } public Task> eth_getTransactionCount(Address address, BlockParameter blockParameter) diff --git a/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs b/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs index c4af68f59c5..c5f9005c7ac 100644 --- a/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs +++ b/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs @@ -19,14 +19,7 @@ public class EthereumJsonSerializer : IJsonSerializer public EthereumJsonSerializer(int? maxDepth = null) { - if (maxDepth.HasValue) - { - _jsonOptions = CreateOptions(indented: false, maxDepth.Value); - } - else - { - _jsonOptions = JsonOptions; - } + _jsonOptions = maxDepth.HasValue ? CreateOptions(indented: false, maxDepth.Value) : JsonOptions; } public T Deserialize(Stream stream) @@ -67,6 +60,8 @@ private static JsonSerializerOptions CreateOptions(bool indented, int maxDepth = new ULongConverter(), new IntConverter(), new ByteArrayConverter(), + new ByteReadOnlyMemoryConverter(), + new NullableByteReadOnlyMemoryConverter(), new NullableLongConverter(), new NullableULongConverter(), new NullableUInt256Converter(), diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/CompactLogEntryDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/CompactLogEntryDecoder.cs index 9d99a9ee474..65646dae530 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/CompactLogEntryDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/CompactLogEntryDecoder.cs @@ -123,7 +123,7 @@ public static void Encode(RlpStream rlpStream, LogEntry? item, RlpBehaviors rlpB rlpStream.Encode(item.Topics[i].Bytes.WithoutLeadingZerosOrEmpty()); } - Span withoutLeadingZero = item.Data.WithoutLeadingZerosOrEmpty(); + ReadOnlySpan withoutLeadingZero = item.Data.WithoutLeadingZerosOrEmpty(); int dataZeroPrefix = item.Data.Length - withoutLeadingZero.Length; rlpStream.Encode(dataZeroPrefix); rlpStream.Encode(withoutLeadingZero); @@ -152,7 +152,7 @@ private static (int Total, int Topics) GetContentLength(LogEntry? item) int topicsLength = GetTopicsLength(item); contentLength += Rlp.LengthOfSequence(topicsLength); - Span withoutLeadingZero = item.Data.WithoutLeadingZerosOrEmpty(); + ReadOnlySpan withoutLeadingZero = item.Data.WithoutLeadingZerosOrEmpty(); int dataZeroPrefix = item.Data.Length - withoutLeadingZero.Length; contentLength += Rlp.LengthOf(dataZeroPrefix); contentLength += Rlp.LengthOf(withoutLeadingZero); diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs index 50a6a763db2..43bba22b89e 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs @@ -337,7 +337,7 @@ public static int Encode(Span buffer, int position, ReadOnlySpan inp return position; } - public static Rlp Encode(Span input) + public static Rlp Encode(ReadOnlySpan input) { if (input.Length == 0) { @@ -1657,7 +1657,7 @@ public static int LengthOf(IReadOnlyList array) return LengthOfByteString(array.Count, array[0]); } - public static int LengthOf(Span array) + public static int LengthOf(ReadOnlySpan array) { if (array.Length == 0) { diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs b/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs index 63cc234bce4..2725d0fcf14 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs @@ -555,7 +555,7 @@ public void Encode(Memory? input) Encode(input.Value.Span); } - public void Encode(Span input) + public void Encode(ReadOnlySpan input) { if (input.IsEmpty) { @@ -1309,7 +1309,7 @@ public ReadOnlySpan DecodeByteArraySpan() int prefix = ReadByte(); if (prefix == 0) { - return Bytes.ZeroByte; + return Bytes.ZeroByte.Span; } if (prefix < 128) diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/ValueRlpStream.cs b/src/Nethermind/Nethermind.Serialization.Rlp/ValueRlpStream.cs index b286898d4b7..24fdb232f12 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/ValueRlpStream.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/ValueRlpStream.cs @@ -347,7 +347,7 @@ public ReadOnlySpan DecodeByteArraySpan() int prefix = ReadByte(); if (prefix == 0) { - return Bytes.ZeroByte; + return Bytes.ZeroByte.Span; } if (prefix < 128) diff --git a/src/Nethermind/Nethermind.State.Test/Proofs/AccountProofCollectorTests.cs b/src/Nethermind/Nethermind.State.Test/Proofs/AccountProofCollectorTests.cs index f0b67a02798..dc27bc86144 100644 --- a/src/Nethermind/Nethermind.State.Test/Proofs/AccountProofCollectorTests.cs +++ b/src/Nethermind/Nethermind.State.Test/Proofs/AccountProofCollectorTests.cs @@ -39,9 +39,9 @@ public void Non_existing_account_is_valid() Assert.That(proof.CodeHash, Is.EqualTo(ValueKeccak.OfAnEmptyString)); Assert.That(proof.StorageRoot, Is.EqualTo(ValueKeccak.EmptyTreeHash)); Assert.That(proof.Balance, Is.EqualTo(UInt256.Zero)); - Assert.That(proof.StorageProofs[0].Value, Is.EqualTo(new byte[] { 0 })); - Assert.That(proof.StorageProofs[1].Value, Is.EqualTo(new byte[] { 0 })); - Assert.That(proof.StorageProofs[2].Value, Is.EqualTo(new byte[] { 0 })); + Assert.That(proof.StorageProofs?[0].Value?.ToArray(), Is.EqualTo(new byte[] { 0 })); + Assert.That(proof.StorageProofs?[1].Value?.ToArray(), Is.EqualTo(new byte[] { 0 })); + Assert.That(proof.StorageProofs?[2].Value?.ToArray(), Is.EqualTo(new byte[] { 0 })); } [Test] @@ -63,9 +63,9 @@ public void Non_existing_account_is_valid_on_non_empty_tree_with_branch_without_ Assert.That(proof.CodeHash, Is.EqualTo(Keccak.OfAnEmptyString)); Assert.That(proof.StorageRoot, Is.EqualTo(Keccak.EmptyTreeHash)); Assert.That(proof.Balance, Is.EqualTo(UInt256.Zero)); - Assert.That(proof.StorageProofs[0].Value, Is.EqualTo(new byte[] { 0 })); - Assert.That(proof.StorageProofs[1].Value, Is.EqualTo(new byte[] { 0 })); - Assert.That(proof.StorageProofs[2].Value, Is.EqualTo(new byte[] { 0 })); + Assert.That(proof.StorageProofs?[0].Value?.ToArray(), Is.EqualTo(new byte[] { 0 })); + Assert.That(proof.StorageProofs?[1].Value?.ToArray(), Is.EqualTo(new byte[] { 0 })); + Assert.That(proof.StorageProofs?[2].Value?.ToArray(), Is.EqualTo(new byte[] { 0 })); } [Test] @@ -85,9 +85,9 @@ public void Non_existing_account_is_valid_even_when_leaf_is_the_last_part_of_the Assert.That(proof.CodeHash, Is.EqualTo(Keccak.OfAnEmptyString)); Assert.That(proof.StorageRoot, Is.EqualTo(Keccak.EmptyTreeHash)); Assert.That(proof.Balance, Is.EqualTo(UInt256.Zero)); - Assert.That(proof.StorageProofs[0].Value, Is.EqualTo(new byte[] { 0 })); - Assert.That(proof.StorageProofs[1].Value, Is.EqualTo(new byte[] { 0 })); - Assert.That(proof.StorageProofs[2].Value, Is.EqualTo(new byte[] { 0 })); + Assert.That(proof.StorageProofs?[0].Value?.ToArray(), Is.EqualTo(new byte[] { 0 })); + Assert.That(proof.StorageProofs?[1].Value?.ToArray(), Is.EqualTo(new byte[] { 0 })); + Assert.That(proof.StorageProofs?[2].Value?.ToArray(), Is.EqualTo(new byte[] { 0 })); } [Test] @@ -289,8 +289,8 @@ public void Storage_proofs_have_values_set() AccountProofCollector accountProofCollector = new(TestItem.AddressA, new[] { Bytes.FromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), Bytes.FromHexString("0x0000000000000000000000000000000000000000000000000000000000000001") }); tree.Accept(accountProofCollector, tree.RootHash); AccountProof proof = accountProofCollector.BuildResult(); - Assert.That(proof.StorageProofs[0].Value.ToHexString(true), Is.EqualTo("0xab12000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[1].Value.ToHexString(true), Is.EqualTo("0xab34000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[0].Value?.Span.ToHexString(true), Is.EqualTo("0xab12000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs[1].Value?.Span.ToHexString(true), Is.EqualTo("0xab34000000000000000000000000000000000000000000000000000000000000000000000000000000")); } [Test] @@ -348,9 +348,9 @@ public void Storage_proofs_have_values_set_complex_setup() AccountProofCollector accountProofCollector = new(TestItem.AddressA, new byte[][] { a, b, c }); tree.Accept(accountProofCollector, tree.RootHash); AccountProof proof = accountProofCollector.BuildResult(); - Assert.That(proof.StorageProofs[0].Value.ToHexString(true), Is.EqualTo("0xab12000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[1].Value.ToHexString(true), Is.EqualTo("0xab34000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[2].Value.ToHexString(true), Is.EqualTo("0xab56000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[0].Value?.Span.ToHexString(true), Is.EqualTo("0xab12000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[1].Value?.Span.ToHexString(true), Is.EqualTo("0xab34000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[2].Value?.Span.ToHexString(true), Is.EqualTo("0xab56000000000000000000000000000000000000000000000000000000000000000000000000000000")); } [Test] @@ -387,11 +387,11 @@ public void Storage_proofs_have_values_set_complex_2_setup() AccountProofCollector accountProofCollector = new(TestItem.AddressA, new byte[][] { a, b, c, d, e }); tree.Accept(accountProofCollector, tree.RootHash); AccountProof proof = accountProofCollector.BuildResult(); - Assert.That(proof.StorageProofs[0].Value.ToHexString(true), Is.EqualTo("0xab12000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[1].Value.ToHexString(true), Is.EqualTo("0xab34000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[2].Value.ToHexString(true), Is.EqualTo("0xab56000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[3].Value.ToHexString(true), Is.EqualTo("0xab78000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[4].Value.ToHexString(true), Is.EqualTo("0xab9a000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[0].Value?.Span.ToHexString(true), Is.EqualTo("0xab12000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[1].Value?.Span.ToHexString(true), Is.EqualTo("0xab34000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[2].Value?.Span.ToHexString(true), Is.EqualTo("0xab56000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[3].Value?.Span.ToHexString(true), Is.EqualTo("0xab78000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[4].Value?.Span.ToHexString(true), Is.EqualTo("0xab9a000000000000000000000000000000000000000000000000000000000000000000000000000000")); } [Test] @@ -428,11 +428,11 @@ public void Storage_proofs_have_values_set_complex_3_setup() AccountProofCollector accountProofCollector = new(TestItem.AddressA, new byte[][] { a, b, c, d, e }); tree.Accept(accountProofCollector, tree.RootHash); AccountProof proof = accountProofCollector.BuildResult(); - Assert.That(proof.StorageProofs[0].Value.ToHexString(true), Is.EqualTo("0xab12000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[1].Value.ToHexString(true), Is.EqualTo("0xab34000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[2].Value.ToHexString(true), Is.EqualTo("0xab56000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[3].Value.ToHexString(true), Is.EqualTo("0xab78000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[4].Value.ToHexString(true), Is.EqualTo("0xab9a000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[0].Value?.Span.ToHexString(true), Is.EqualTo("0xab12000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[1].Value?.Span.ToHexString(true), Is.EqualTo("0xab34000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[2].Value?.Span.ToHexString(true), Is.EqualTo("0xab56000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[3].Value?.Span.ToHexString(true), Is.EqualTo("0xab78000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[4].Value?.Span.ToHexString(true), Is.EqualTo("0xab9a000000000000000000000000000000000000000000000000000000000000000000000000000000")); } [Test] @@ -467,14 +467,14 @@ public void Storage_proofs_when_values_are_missing_setup() AccountProofCollector accountProofCollector = new(TestItem.AddressA, new byte[][] { a, b, c, d, e }); tree.Accept(accountProofCollector, tree.RootHash); AccountProof proof = accountProofCollector.BuildResult(); - Assert.That(proof.StorageProofs[0].Value?.ToHexString(true) ?? "0x", Is.EqualTo("0xab12000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[1].Value?.ToHexString(true) ?? "0x", Is.EqualTo("0x00")); - Assert.That(proof.StorageProofs[2].Value?.ToHexString(true) ?? "0x", Is.EqualTo("0xab56000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[3].Value?.ToHexString(true) ?? "0x", Is.EqualTo("0x00")); - Assert.That(proof.StorageProofs[4].Value?.ToHexString(true) ?? "0x", Is.EqualTo("0xab9a000000000000000000000000000000000000000000000000000000000000000000000000000000")); - - proof.StorageProofs[1].Proof.Should().HaveCount(3); - proof.StorageProofs[3].Proof.Should().HaveCount(2); + Assert.That(proof.StorageProofs?[0].Value?.Span.ToHexString(true) ?? "0x", Is.EqualTo("0xab12000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[1].Value?.Span.ToHexString(true) ?? "0x", Is.EqualTo("0x00")); + Assert.That(proof.StorageProofs?[2].Value?.Span.ToHexString(true) ?? "0x", Is.EqualTo("0xab56000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[3].Value?.Span.ToHexString(true) ?? "0x", Is.EqualTo("0x00")); + Assert.That(proof.StorageProofs?[4].Value?.Span.ToHexString(true) ?? "0x", Is.EqualTo("0xab9a000000000000000000000000000000000000000000000000000000000000000000000000000000")); + + proof.StorageProofs?[1].Proof.Should().HaveCount(3); + proof.StorageProofs?[3].Proof.Should().HaveCount(2); } [Test] @@ -535,9 +535,9 @@ public void Storage_proofs_have_values_set_selective_setup() AccountProofCollector accountProofCollector = new(TestItem.AddressA, new byte[][] { a, c, e }); tree.Accept(accountProofCollector, tree.RootHash); AccountProof proof = accountProofCollector.BuildResult(); - Assert.That(proof.StorageProofs[0].Value.ToHexString(true), Is.EqualTo("0xab12000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[1].Value.ToHexString(true), Is.EqualTo("0xab56000000000000000000000000000000000000000000000000000000000000000000000000000000")); - Assert.That(proof.StorageProofs[2].Value.ToHexString(true), Is.EqualTo("0xab9a000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[0].Value?.Span.ToHexString(true), Is.EqualTo("0xab12000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[1].Value?.Span.ToHexString(true), Is.EqualTo("0xab56000000000000000000000000000000000000000000000000000000000000000000000000000000")); + Assert.That(proof.StorageProofs?[2].Value?.Span.ToHexString(true), Is.EqualTo("0xab9a000000000000000000000000000000000000000000000000000000000000000000000000000000")); } private class AddressWithStorage diff --git a/src/Nethermind/Nethermind.State/IStateReader.cs b/src/Nethermind/Nethermind.State/IStateReader.cs index 990b035a003..a8a31f937c2 100644 --- a/src/Nethermind/Nethermind.State/IStateReader.cs +++ b/src/Nethermind/Nethermind.State/IStateReader.cs @@ -13,7 +13,7 @@ public interface IStateReader { Account? GetAccount(Hash256 stateRoot, Address address); - Span GetStorage(Hash256 stateRoot, Address address, in UInt256 index); + ReadOnlySpan GetStorage(Hash256 stateRoot, Address address, in UInt256 index); byte[]? GetCode(Hash256 codeHash); diff --git a/src/Nethermind/Nethermind.State/Proofs/StorageProof.cs b/src/Nethermind/Nethermind.State/Proofs/StorageProof.cs index 62b18eff0bb..66592d4176a 100644 --- a/src/Nethermind/Nethermind.State/Proofs/StorageProof.cs +++ b/src/Nethermind/Nethermind.State/Proofs/StorageProof.cs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; + namespace Nethermind.State.Proofs { /// @@ -10,6 +12,6 @@ public class StorageProof { public byte[]? Key { get; set; } public byte[][]? Proof { get; set; } - public byte[]? Value { get; set; } + public ReadOnlyMemory? Value { get; set; } } } diff --git a/src/Nethermind/Nethermind.State/StateReader.cs b/src/Nethermind/Nethermind.State/StateReader.cs index f5744f841de..995c772bbf5 100644 --- a/src/Nethermind/Nethermind.State/StateReader.cs +++ b/src/Nethermind/Nethermind.State/StateReader.cs @@ -34,7 +34,7 @@ public StateReader(ITrieStore? trieStore, IKeyValueStore? codeDb, ILogManager? l return GetState(stateRoot, address); } - public Span GetStorage(Hash256 stateRoot, Address address, in UInt256 index) + public ReadOnlySpan GetStorage(Hash256 stateRoot, Address address, in UInt256 index) { Account? account = GetAccount(stateRoot, address); if (account is null) return null; @@ -42,7 +42,7 @@ public Span GetStorage(Hash256 stateRoot, Address address, in UInt256 inde Hash256 storageRoot = account.StorageRoot; if (storageRoot == Keccak.EmptyTreeHash) { - return Bytes.ZeroByte; + return Bytes.ZeroByte.Span; } Metrics.StorageTreeReads++; From 4cc6c14bd8b72abfdb0972c41f59fda9ce5215ec Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Wed, 24 Jan 2024 09:19:28 +0100 Subject: [PATCH 10/16] fix tests --- .../Nethermind.Trie.Test/TrieTests.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Nethermind/Nethermind.Trie.Test/TrieTests.cs b/src/Nethermind/Nethermind.Trie.Test/TrieTests.cs index 8e97d737f7b..02c48ef68a4 100644 --- a/src/Nethermind/Nethermind.Trie.Test/TrieTests.cs +++ b/src/Nethermind/Nethermind.Trie.Test/TrieTests.cs @@ -119,7 +119,7 @@ public void Single_leaf_delete_same_block() memDb.Keys.Should().HaveCount(0); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).ToArray().Should().BeNull(); + checkTree.Get(_keyA).ToArray().Should().BeEmpty(); } [Test] @@ -138,7 +138,7 @@ public void Single_leaf_delete_next_block() memDb.Keys.Should().HaveCount(1); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).ToArray().Should().BeNull(); + checkTree.Get(_keyA).ToArray().Should().BeEmpty(); } [Test] @@ -171,8 +171,8 @@ public void Single_leaf_and_keep_for_multiple_dispatches_then_delete() memDb.Keys.Should().HaveCount(2); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).ToArray().Should().BeNull(); - checkTree.Get(_keyB).ToArray().Should().BeNull(); + checkTree.Get(_keyA).ToArray().Should().BeEmpty(); + checkTree.Get(_keyB).ToArray().Should().BeEmpty(); } [Test] @@ -225,9 +225,9 @@ public void Branch_with_branch_and_leaf_then_deleted() // leaf (root) memDb.Keys.Should().HaveCount(6); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).ToArray().Should().BeNull(); - checkTree.Get(_keyB).ToArray().Should().BeNull(); - checkTree.Get(_keyC).ToArray().Should().BeNull(); + checkTree.Get(_keyA).ToArray().Should().BeEmpty(); + checkTree.Get(_keyB).ToArray().Should().BeEmpty(); + checkTree.Get(_keyC).ToArray().Should().BeEmpty(); } public void Test_add_many(int i) @@ -292,7 +292,7 @@ public void Test_try_delete_and_read_missing_nodes(int i) for (int j = 0; j < i; j++) { Hash256 key = TestItem.Keccaks[j + 100]; - checkTree.Get(key.Bytes).ToArray().Should().BeNull(); + checkTree.Get(key.Bytes).ToArray().Should().BeEmpty(); } } @@ -393,7 +393,7 @@ public void Test_add_and_delete_many_same_block(int i) for (int j = 0; j < i; j++) { Hash256 key = TestItem.Keccaks[j]; - checkTree.Get(key.Bytes).ToArray().Should().BeNull($@"{i} {j}"); + checkTree.Get(key.Bytes).ToArray().Should().BeEmpty($"{i} {j}"); } } @@ -425,7 +425,7 @@ public void Test_add_and_delete_many_next_block(int i) for (int j = 0; j < i; j++) { Hash256 key = TestItem.Keccaks[j]; - checkTree.Get(key.Bytes).ToArray().Should().BeNull($@"{i} {j}"); + checkTree.Get(key.Bytes).ToArray().Should().BeEmpty($"{i} {j}"); } } @@ -487,7 +487,7 @@ public void Two_branches_exactly_same_leaf_then_one_removed() // leaf (root) memDb.Keys.Should().HaveCount(6); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); - checkTree.Get(_keyA).ToArray().Should().BeNull(); + checkTree.Get(_keyA).ToArray().Should().BeEmpty(); checkTree.Get(_keyB).ToArray().Should().BeEquivalentTo(_longLeaf1); checkTree.Get(_keyC).ToArray().Should().BeEquivalentTo(_longLeaf1); checkTree.Get(_keyD).ToArray().Should().BeEquivalentTo(_longLeaf1); @@ -651,7 +651,7 @@ L L - - - - - - - - - - - - - - */ PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); checkTree.Get(key1).ToArray().Should().BeEquivalentTo(_longLeaf1); checkTree.Get(key2).ToArray().Should().BeEquivalentTo(_longLeaf1); - checkTree.Get(key3).ToArray().Should().BeNull(); + checkTree.Get(key3).ToArray().Should().BeEmpty(); } [Test] From e5c8d6a0e5e3841b1c5ee27a730d5f8aca07b81a Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Wed, 24 Jan 2024 09:29:01 +0100 Subject: [PATCH 11/16] try increase test resilience --- src/Nethermind/Nethermind.Network.Test/PeerManagerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Network.Test/PeerManagerTests.cs b/src/Nethermind/Nethermind.Network.Test/PeerManagerTests.cs index 4dda0b92184..b0a6c56e6fb 100644 --- a/src/Nethermind/Nethermind.Network.Test/PeerManagerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/PeerManagerTests.cs @@ -457,7 +457,7 @@ public async Task Will_fill_up_over_and_over_again_on_disconnects_and_when_ids_k Assert.That( () => ctx.PeerManager.CandidatePeers.All(p => p.OutSession is null), - Is.True.After(1000, 10)); + Is.True.After(2000, 10)); } [Test] From 7a09616498bec3a5193baa29289208d871cd186c Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Wed, 24 Jan 2024 10:11:42 +0100 Subject: [PATCH 12/16] increase more delays --- .../ParallelSync/SyncDispatcherTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/SyncDispatcherTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/SyncDispatcherTests.cs index 1a66ea46787..9669e00a290 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/SyncDispatcherTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/SyncDispatcherTests.cs @@ -287,7 +287,7 @@ public async Task Test_release_before_processing_complete(bool isMultiSync, int syncFeed.Activate(); await Task.Delay(100); - Assert.That(() => syncFeed.HighestRequested, Is.EqualTo(expectedHighestRequest).After(2000, 100)); + Assert.That(() => syncFeed.HighestRequested, Is.EqualTo(expectedHighestRequest).After(4000, 100)); syncFeed.UnlockResponse(); } } From da4909b797984894a013c9591674c570b5ff5c8d Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Thu, 25 Jan 2024 12:09:06 +0100 Subject: [PATCH 13/16] Move PatriciaTree.Get to ReadOnlySpan --- src/Nethermind/Nethermind.Evm/EvmStack.cs | 2 +- .../Tracing/GethStyle/JavaScript/Db.cs | 2 +- src/Nethermind/Nethermind.Evm/VirtualMachine.cs | 15 ++++++--------- .../ByteArrayExtensions.cs | 5 +++++ src/Nethermind/Nethermind.State/IWorldState.cs | 4 ++-- .../PartialStorageProviderBase.cs | 4 ++-- .../Nethermind.State/PersistentStorageProvider.cs | 4 ++-- src/Nethermind/Nethermind.State/StateTree.cs | 4 ++-- src/Nethermind/Nethermind.State/StorageTree.cs | 4 ++-- .../Nethermind.State/TransientStorageProvider.cs | 2 +- src/Nethermind/Nethermind.State/WorldState.cs | 4 ++-- .../LesSync/CanonicalHashTrie.cs | 2 +- .../Trie/HealingStateTree.cs | 2 +- .../Trie/HealingStorageTree.cs | 2 +- src/Nethermind/Nethermind.Trie/PatriciaTree.cs | 2 +- 15 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/Nethermind/Nethermind.Evm/EvmStack.cs b/src/Nethermind/Nethermind.Evm/EvmStack.cs index 122510d1f6c..70faa665fac 100644 --- a/src/Nethermind/Nethermind.Evm/EvmStack.cs +++ b/src/Nethermind/Nethermind.Evm/EvmStack.cs @@ -39,7 +39,7 @@ public EvmStack(scoped in Span bytes, scoped in int head, ITxTracer txTrac private readonly ITxTracer _tracer; - public void PushBytes(scoped in ReadOnlySpan value) + public void PushBytes(scoped ReadOnlySpan value) { if (typeof(TTracing) == typeof(IsTracing)) _tracer.ReportStackPush(value); diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/JavaScript/Db.cs b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/JavaScript/Db.cs index 83c778930fb..c38c2d5cd56 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/JavaScript/Db.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/JavaScript/Db.cs @@ -33,7 +33,7 @@ public ITypedArray getState(object address, object hash) byte[] array = ArrayPool.Shared.Rent(32); try { - Span bytes = WorldState.Get(new StorageCell(address.ToAddress(), hash.GetHash())); + ReadOnlySpan bytes = WorldState.Get(new StorageCell(address.ToAddress(), hash.GetHash())); if (bytes.Length < array.Length) { Array.Clear(array); diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index d02c015ec4d..a4d0a332464 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -1660,10 +1660,8 @@ private CallResult ExecuteCode value = _state.Get(in storageCell); - Span valueBytes = MemoryMarshal.CreateSpan(ref MemoryMarshal.AsRef(value), value.Length); // TODO: how to do it? - stack.PushBytes(valueBytes); - + ReadOnlySpan value = _state.Get(in storageCell); + stack.PushBytes(value); if (typeof(TTracingStorage) == typeof(IsTracing)) { _txTracer.LoadOperationStorage(storageCell.Address, result, value); @@ -2019,9 +2017,8 @@ private CallResult ExecuteCode value = _state.GetTransientState(in storageCell); - Span valueBytes = MemoryMarshal.CreateSpan(ref MemoryMarshal.AsRef(value), value.Length); // TODO: how to do it? - stack.PushBytes(valueBytes); + ReadOnlySpan value = _state.GetTransientState(in storageCell); + stack.PushBytes(value); if (typeof(TTracingStorage) == typeof(IsTracing)) { @@ -2061,7 +2058,7 @@ private CallResult ExecuteCode currentValue = _state.GetTransientState(in storageCell); + ReadOnlySpan currentValue = _state.GetTransientState(in storageCell); _txTracer.SetOperationTransientStorage(storageCell.Address, result, bytes, currentValue); } @@ -2645,7 +2642,7 @@ private EvmExceptionType InstructionSStore currentValue = _state.Get(in storageCell); + ReadOnlySpan currentValue = _state.Get(in storageCell); // Console.WriteLine($"current: {currentValue.ToHexString()} newValue {newValue.ToHexString()}"); bool currentIsZero = currentValue.IsZero(); diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/ByteArrayExtensions.cs b/src/Nethermind/Nethermind.Serialization.Rlp/ByteArrayExtensions.cs index 5dbbe5671cf..bb157ca7dee 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/ByteArrayExtensions.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/ByteArrayExtensions.cs @@ -34,6 +34,11 @@ public static Rlp.ValueDecoderContext AsRlpValueContext(this byte[]? bytes) } public static Rlp.ValueDecoderContext AsRlpValueContext(this Span span) + { + return ((ReadOnlySpan)span).AsRlpValueContext(); + } + + public static Rlp.ValueDecoderContext AsRlpValueContext(this ReadOnlySpan span) { return span.IsEmpty ? new Rlp.ValueDecoderContext(Array.Empty()) : new Rlp.ValueDecoderContext(span); } diff --git a/src/Nethermind/Nethermind.State/IWorldState.cs b/src/Nethermind/Nethermind.State/IWorldState.cs index ddcaf3fa279..0cd9f5d2cf2 100644 --- a/src/Nethermind/Nethermind.State/IWorldState.cs +++ b/src/Nethermind/Nethermind.State/IWorldState.cs @@ -27,7 +27,7 @@ public interface IWorldState : IJournal, IReadOnlyStateProvider /// /// Storage location /// Value at cell - Span Get(in StorageCell storageCell); + ReadOnlySpan Get(in StorageCell storageCell); /// /// Set the provided value to persistent storage at the specified storage cell @@ -41,7 +41,7 @@ public interface IWorldState : IJournal, IReadOnlyStateProvider /// /// Storage location /// Value at cell - Span GetTransientState(in StorageCell storageCell); + ReadOnlySpan GetTransientState(in StorageCell storageCell); /// /// Set the provided value to transient storage at the specified storage cell diff --git a/src/Nethermind/Nethermind.State/PartialStorageProviderBase.cs b/src/Nethermind/Nethermind.State/PartialStorageProviderBase.cs index 77eff0d27aa..7195ed5e58d 100644 --- a/src/Nethermind/Nethermind.State/PartialStorageProviderBase.cs +++ b/src/Nethermind/Nethermind.State/PartialStorageProviderBase.cs @@ -41,7 +41,7 @@ protected PartialStorageProviderBase(ILogManager? logManager) /// /// Storage location /// Value at cell - public Span Get(in StorageCell storageCell) + public ReadOnlySpan Get(in StorageCell storageCell) { return GetCurrentValue(storageCell); } @@ -235,7 +235,7 @@ protected bool TryGetCachedValue(in StorageCell storageCell, out byte[]? bytes) /// /// Storage location /// Value at location - protected abstract Span GetCurrentValue(in StorageCell storageCell); + protected abstract ReadOnlySpan GetCurrentValue(in StorageCell storageCell); /// /// Update the storage cell with provided value diff --git a/src/Nethermind/Nethermind.State/PersistentStorageProvider.cs b/src/Nethermind/Nethermind.State/PersistentStorageProvider.cs index c0cdceaad00..b265fe1993f 100644 --- a/src/Nethermind/Nethermind.State/PersistentStorageProvider.cs +++ b/src/Nethermind/Nethermind.State/PersistentStorageProvider.cs @@ -60,7 +60,7 @@ public override void Reset() /// /// Storage location /// Value at location - protected override Span GetCurrentValue(in StorageCell storageCell) => + protected override ReadOnlySpan GetCurrentValue(in StorageCell storageCell) => TryGetCachedValue(storageCell, out byte[]? bytes) ? bytes! : LoadFromTree(storageCell); /// @@ -234,7 +234,7 @@ private StorageTree GetOrCreateStorage(Address address) return value; } - private Span LoadFromTree(in StorageCell storageCell) + private ReadOnlySpan LoadFromTree(in StorageCell storageCell) { StorageTree tree = GetOrCreateStorage(storageCell.Address); diff --git a/src/Nethermind/Nethermind.State/StateTree.cs b/src/Nethermind/Nethermind.State/StateTree.cs index 49a63f8c6f3..6c8c8819ac0 100644 --- a/src/Nethermind/Nethermind.State/StateTree.cs +++ b/src/Nethermind/Nethermind.State/StateTree.cs @@ -37,14 +37,14 @@ public StateTree(ITrieStore? store, ILogManager? logManager) [DebuggerStepThrough] public Account? Get(Address address, Hash256? rootHash = null) { - Span bytes = Get(ValueKeccak.Compute(address.Bytes).BytesAsSpan, rootHash); + ReadOnlySpan bytes = Get(ValueKeccak.Compute(address.Bytes).BytesAsSpan, rootHash); return bytes.IsEmpty ? null : _decoder.Decode(bytes); } [DebuggerStepThrough] internal Account? Get(Hash256 keccak) // for testing { - Span bytes = Get(keccak.Bytes); + ReadOnlySpan bytes = Get(keccak.Bytes); return bytes.IsEmpty ? null : _decoder.Decode(bytes); } diff --git a/src/Nethermind/Nethermind.State/StorageTree.cs b/src/Nethermind/Nethermind.State/StorageTree.cs index a0139b47268..d5b2719c9ad 100644 --- a/src/Nethermind/Nethermind.State/StorageTree.cs +++ b/src/Nethermind/Nethermind.State/StorageTree.cs @@ -69,9 +69,9 @@ public byte[] Get(in UInt256 index, Hash256? storageRoot = null) return Get(key, storageRoot).ToArray(); } - public override Span Get(ReadOnlySpan rawKey, Hash256? rootHash = null) + public override ReadOnlySpan Get(ReadOnlySpan rawKey, Hash256? rootHash = null) { - Span value = base.Get(rawKey, rootHash); + ReadOnlySpan value = base.Get(rawKey, rootHash); if (value.IsEmpty) { diff --git a/src/Nethermind/Nethermind.State/TransientStorageProvider.cs b/src/Nethermind/Nethermind.State/TransientStorageProvider.cs index 7f0820fc626..3e2177fdf33 100644 --- a/src/Nethermind/Nethermind.State/TransientStorageProvider.cs +++ b/src/Nethermind/Nethermind.State/TransientStorageProvider.cs @@ -21,7 +21,7 @@ public TransientStorageProvider(ILogManager? logManager) /// /// Storage location /// Value at cell - protected override Span GetCurrentValue(in StorageCell storageCell) => + protected override ReadOnlySpan GetCurrentValue(in StorageCell storageCell) => TryGetCachedValue(storageCell, out byte[]? bytes) ? bytes! : _zeroValue; } } diff --git a/src/Nethermind/Nethermind.State/WorldState.cs b/src/Nethermind/Nethermind.State/WorldState.cs index 7c612e4997d..fd5caa81851 100644 --- a/src/Nethermind/Nethermind.State/WorldState.cs +++ b/src/Nethermind/Nethermind.State/WorldState.cs @@ -66,7 +66,7 @@ public byte[] GetOriginal(in StorageCell storageCell) { return _persistentStorageProvider.GetOriginal(storageCell); } - public Span Get(in StorageCell storageCell) + public ReadOnlySpan Get(in StorageCell storageCell) { return _persistentStorageProvider.Get(storageCell); } @@ -74,7 +74,7 @@ public void Set(in StorageCell storageCell, byte[] newValue) { _persistentStorageProvider.Set(storageCell, newValue); } - public Span GetTransientState(in StorageCell storageCell) + public ReadOnlySpan GetTransientState(in StorageCell storageCell) { return _transientStorageProvider.Get(storageCell); } diff --git a/src/Nethermind/Nethermind.Synchronization/LesSync/CanonicalHashTrie.cs b/src/Nethermind/Nethermind.Synchronization/LesSync/CanonicalHashTrie.cs index 9c1fecfbd49..73374859419 100644 --- a/src/Nethermind/Nethermind.Synchronization/LesSync/CanonicalHashTrie.cs +++ b/src/Nethermind/Nethermind.Synchronization/LesSync/CanonicalHashTrie.cs @@ -102,7 +102,7 @@ public void Set(BlockHeader header) public (Hash256?, UInt256) Get(Span key) { - Span val = base.Get(key); + ReadOnlySpan val = base.Get(key); if (val.IsEmpty) { throw new InvalidDataException("Missing CHT data"); diff --git a/src/Nethermind/Nethermind.Synchronization/Trie/HealingStateTree.cs b/src/Nethermind/Nethermind.Synchronization/Trie/HealingStateTree.cs index 75f11e95d65..32cdee612d5 100644 --- a/src/Nethermind/Nethermind.Synchronization/Trie/HealingStateTree.cs +++ b/src/Nethermind/Nethermind.Synchronization/Trie/HealingStateTree.cs @@ -27,7 +27,7 @@ public void InitializeNetwork(ITrieNodeRecovery recovery) _recovery = recovery; } - public override Span Get(ReadOnlySpan rawKey, Hash256? rootHash = null) + public override ReadOnlySpan Get(ReadOnlySpan rawKey, Hash256? rootHash = null) { try { diff --git a/src/Nethermind/Nethermind.Synchronization/Trie/HealingStorageTree.cs b/src/Nethermind/Nethermind.Synchronization/Trie/HealingStorageTree.cs index 6288d16f009..63fee9d2581 100644 --- a/src/Nethermind/Nethermind.Synchronization/Trie/HealingStorageTree.cs +++ b/src/Nethermind/Nethermind.Synchronization/Trie/HealingStorageTree.cs @@ -26,7 +26,7 @@ public HealingStorageTree(ITrieStore? trieStore, Hash256 rootHash, ILogManager? _recovery = recovery; } - public override Span Get(ReadOnlySpan rawKey, Hash256? rootHash = null) + public override ReadOnlySpan Get(ReadOnlySpan rawKey, Hash256? rootHash = null) { try { diff --git a/src/Nethermind/Nethermind.Trie/PatriciaTree.cs b/src/Nethermind/Nethermind.Trie/PatriciaTree.cs index c46239591ad..b760f159d39 100644 --- a/src/Nethermind/Nethermind.Trie/PatriciaTree.cs +++ b/src/Nethermind/Nethermind.Trie/PatriciaTree.cs @@ -355,7 +355,7 @@ private void SetRootHash(Hash256? value, bool resetObjects) [SkipLocalsInit] [DebuggerStepThrough] - public virtual Span Get(ReadOnlySpan rawKey, Hash256? rootHash = null) + public virtual ReadOnlySpan Get(ReadOnlySpan rawKey, Hash256? rootHash = null) { try { From 90addd4cc9859f9ea2fea35ae1b80c04c70a38a9 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Thu, 25 Jan 2024 13:41:41 +0100 Subject: [PATCH 14/16] fix --- src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs index c002949c647..fe7fd623b4c 100644 --- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs +++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs @@ -406,7 +406,7 @@ private List RunAssertions(BlockchainTest test, Block headBlock, IWorldS foreach (KeyValuePair clearedStorage in clearedStorages) { - Span value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key)); + ReadOnlySpan value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key)); if (!value.IsZero()) { differences.Add($"{acountAddress} storage[{clearedStorage.Key}] exp: 0x00, actual: {value.ToHexString(true)}"); @@ -415,7 +415,7 @@ private List RunAssertions(BlockchainTest test, Block headBlock, IWorldS foreach (KeyValuePair storageItem in accountState.Storage) { - Span value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key)); + ReadOnlySpan value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key)); if (!Bytes.AreEqual(storageItem.Value, value)) { differences.Add($"{acountAddress} storage[{storageItem.Key}] exp: {storageItem.Value.ToHexString(true)}, actual: {value.ToHexString(true)}"); From 09f2442c241e8e549eee48d342c437bcdf2361db Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Thu, 25 Jan 2024 23:02:49 +0100 Subject: [PATCH 15/16] fix --- src/Nethermind/Nethermind.State/StateTree.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.State/StateTree.cs b/src/Nethermind/Nethermind.State/StateTree.cs index a5ad3a1958e..f81e58c4e92 100644 --- a/src/Nethermind/Nethermind.State/StateTree.cs +++ b/src/Nethermind/Nethermind.State/StateTree.cs @@ -44,7 +44,7 @@ public StateTree(ITrieStore? store, ILogManager? logManager) [DebuggerStepThrough] public AccountStruct? GetStruct(Address address, Hash256? rootHash = null) { - Span bytes = Get(ValueKeccak.Compute(address.Bytes).BytesAsSpan, rootHash); + ReadOnlySpan bytes = Get(ValueKeccak.Compute(address.Bytes).BytesAsSpan, rootHash); Rlp.ValueDecoderContext valueDecoderContext = new Rlp.ValueDecoderContext(bytes); return bytes.IsEmpty ? null : _decoder.DecodeStruct(ref valueDecoderContext); } From ad58087ff0c74bf1838243b884b3de384d3e07e0 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Fri, 26 Jan 2024 15:24:43 +0100 Subject: [PATCH 16/16] add readonly to AccountStruct --- src/Nethermind/Nethermind.Core/Account.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Core/Account.cs b/src/Nethermind/Nethermind.Core/Account.cs index 92df94240c9..144b088caa9 100644 --- a/src/Nethermind/Nethermind.Core/Account.cs +++ b/src/Nethermind/Nethermind.Core/Account.cs @@ -104,7 +104,7 @@ public Account WithChangedCodeHash(Hash256 newCodeHash) public AccountStruct ToStruct() => new(Nonce, Balance, StorageRoot, CodeHash); } - public struct AccountStruct + public readonly struct AccountStruct { private readonly ValueHash256 _codeHash = Keccak.OfAnEmptyString.ValueHash256; private readonly ValueHash256 _storageRoot = Keccak.EmptyTreeHash.ValueHash256;