diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.cs index b9b1e0947dd..026dfdb5063 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.cs @@ -22,8 +22,7 @@ using Nethermind.JsonRpc.Data; using Nethermind.JsonRpc.Test.Modules; using Nethermind.Logging; - -using Newtonsoft.Json.Linq; +using Nethermind.State; using NUnit.Framework; namespace Nethermind.AccountAbstraction.Test; diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationTracerTests.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationTracerTests.cs index e6246baf185..4e546819c4b 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationTracerTests.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationTracerTests.cs @@ -11,6 +11,7 @@ using Nethermind.Evm.Test; using Nethermind.Logging; using Nethermind.Specs; +using Nethermind.State; using NUnit.Framework; namespace Nethermind.AccountAbstraction.Test diff --git a/src/Nethermind/Nethermind.Evm.Test/CodeAnalysis/CodeInfoTests.cs b/src/Nethermind/Nethermind.Evm.Test/CodeAnalysis/CodeInfoTests.cs index cf2c6e68472..a76c67e2eb6 100644 --- a/src/Nethermind/Nethermind.Evm.Test/CodeAnalysis/CodeInfoTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/CodeAnalysis/CodeInfoTests.cs @@ -3,6 +3,8 @@ using System.Linq; using System.Reflection; +using System.Runtime.Intrinsics; + using FluentAssertions; using Nethermind.Evm.CodeAnalysis; using NUnit.Framework; @@ -165,5 +167,80 @@ public void Push1Jumpdest_Over10k() codeInfo.ValidateJump(10, false).Should().BeFalse(); codeInfo.ValidateJump(11, false).Should().BeFalse(); // 0x5b but not JUMPDEST but data } + + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + [TestCase(4)] + [TestCase(5)] + [TestCase(6)] + [TestCase(7)] + [TestCase(8)] + [TestCase(9)] + [TestCase(10)] + [TestCase(11)] + [TestCase(12)] + [TestCase(13)] + [TestCase(14)] + [TestCase(15)] + [TestCase(16)] + [TestCase(17)] + [TestCase(18)] + [TestCase(19)] + [TestCase(20)] + [TestCase(21)] + [TestCase(22)] + [TestCase(23)] + [TestCase(24)] + [TestCase(25)] + [TestCase(26)] + [TestCase(27)] + [TestCase(28)] + [TestCase(29)] + [TestCase(30)] + [TestCase(31)] + [TestCase(32)] + public void PushNJumpdest_Over10k(int n) + { + byte[] code = new byte[10_001]; + + // One vector (aligned), half vector to unalign + int i; + for (i = 0; i < Vector256.Count * 2 + Vector128.Count; i++) + { + code[i] = (byte)0x5b; + } + for (; i < Vector256.Count * 3; i++) + { + // + } + var triggerPushes = false; + for (; i < code.Length; i++) + { + if (i % (n + 1) == 0) + { + triggerPushes = true; + } + if (triggerPushes) + { + code[i] = i % (n + 1) == 0 ? (byte)(0x60 + n - 1) : (byte)0x5b; + } + } + + CodeInfo codeInfo = new(code); + + for (i = 0; i < Vector256.Count * 2 + Vector128.Count; i++) + { + codeInfo.ValidateJump(i, false).Should().BeTrue(); + } + for (; i < Vector256.Count * 3; i++) + { + codeInfo.ValidateJump(i, false).Should().BeFalse(); + } + for (; i < code.Length; i++) + { + codeInfo.ValidateJump(i, false).Should().BeFalse(); // Are 0x5b but not JUMPDEST but data + } + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs index ca30797a92f..3ec2002df2b 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs @@ -7,6 +7,7 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Specs; +using Nethermind.State; using Nethermind.Core.Test.Builders; using Nethermind.Evm.Tracing.GethStyle; using Nethermind.Trie; diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs index c9ed0fa5c82..ae825118bac 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs @@ -11,6 +11,7 @@ using Nethermind.Evm.Precompiles; using Nethermind.Specs.Forks; using Nethermind.Specs.Test; +using Nethermind.State; using NUnit.Framework; namespace Nethermind.Evm.Test diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs index f908d1638a2..7e21148f754 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs @@ -3,6 +3,7 @@ using Nethermind.Core.Extensions; using Nethermind.Specs; +using Nethermind.State; using Nethermind.Core.Test.Builders; using NUnit.Framework; using System.Diagnostics; diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1884Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1884Tests.cs index aed97068526..9e9f11bded1 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1884Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1884Tests.cs @@ -5,6 +5,7 @@ using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Specs; +using Nethermind.State; using Nethermind.Core.Test.Builders; using Nethermind.Int256; using NUnit.Framework; diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs index 377a40460f1..946bafcb754 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs @@ -3,6 +3,7 @@ using Nethermind.Core.Extensions; using Nethermind.Specs; +using Nethermind.State; using Nethermind.Core.Test.Builders; using NUnit.Framework; using Nethermind.Core; diff --git a/src/Nethermind/Nethermind.Evm.Test/StorageAndSelfDestructTests.cs b/src/Nethermind/Nethermind.Evm.Test/StorageAndSelfDestructTests.cs index 842bbc2f2b8..9477089d2db 100644 --- a/src/Nethermind/Nethermind.Evm.Test/StorageAndSelfDestructTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/StorageAndSelfDestructTests.cs @@ -11,6 +11,7 @@ using Nethermind.Logging; using Nethermind.Specs; using Nethermind.Specs.Forks; +using Nethermind.State; using NUnit.Framework; namespace Nethermind.Evm.Test diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeJavaScriptTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeJavaScriptTracerTests.cs index 45009fe185e..0b935557f3d 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeJavaScriptTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeJavaScriptTracerTests.cs @@ -12,9 +12,9 @@ using Nethermind.Core.Test.Builders; using Nethermind.Evm.Tracing.GethStyle.JavaScript; using Nethermind.Int256; -using Nethermind.JsonRpc.Modules.DebugModule; using Nethermind.Serialization.Json; using Nethermind.Specs.Forks; +using Nethermind.State; namespace Nethermind.Evm.Test.Tracing; diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeTxMemoryTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeTxMemoryTracerTests.cs index 09d19f396a7..ae5ceab5c4b 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeTxMemoryTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeTxMemoryTracerTests.cs @@ -6,6 +6,7 @@ using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Evm.Tracing.GethStyle; +using Nethermind.State; using NUnit.Framework; namespace Nethermind.Evm.Test.Tracing; diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs index 8867edb930b..dabc8b9ae63 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs @@ -11,6 +11,7 @@ using Nethermind.Int256; using Nethermind.Evm.Precompiles; using Nethermind.Evm.Tracing.ParityStyle; +using Nethermind.State; using NUnit.Framework; namespace Nethermind.Evm.Test.Tracing diff --git a/src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs b/src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs index 4554f5a319c..99441287fa9 100644 --- a/src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs @@ -4,6 +4,7 @@ using Nethermind.Core; using Nethermind.Core.Extensions; using Nethermind.Specs; +using Nethermind.State; using Nethermind.Core.Test.Builders; using NUnit.Framework; diff --git a/src/Nethermind/Nethermind.Evm/ByteArrayExtensions.cs b/src/Nethermind/Nethermind.Evm/ByteArrayExtensions.cs index ec6368ac113..57159706c74 100644 --- a/src/Nethermind/Nethermind.Evm/ByteArrayExtensions.cs +++ b/src/Nethermind/Nethermind.Evm/ByteArrayExtensions.cs @@ -34,25 +34,18 @@ private static ZeroPaddedSpan SliceWithZeroPadding(this ReadOnlySpan span, return new ZeroPaddedSpan(span.Slice(startIndex, copiedLength), length - copiedLength, padDirection); } - public static ZeroPaddedSpan SliceWithZeroPadding(this Span span, scoped in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right) - { - if (startIndex >= span.Length || startIndex > int.MaxValue) - { - return new ZeroPaddedSpan(default, length, PadDirection.Right); - } - - return SliceWithZeroPadding(span, (int)startIndex, length, padDirection); - } - - public static ZeroPaddedSpan SliceWithZeroPadding(this ReadOnlyMemory bytes, scoped in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right) - { - if (startIndex >= bytes.Length || startIndex > int.MaxValue) - { - return new ZeroPaddedSpan(default, length, PadDirection.Right); - } - - return SliceWithZeroPadding(bytes.Span, (int)startIndex, length, padDirection); - } + public static ZeroPaddedSpan SliceWithZeroPadding(this Span span, scoped in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right) => startIndex >= span.Length || startIndex > int.MaxValue + ? new ZeroPaddedSpan(default, length, PadDirection.Right) + : SliceWithZeroPadding(span, (int)startIndex, length, padDirection); + + public static ZeroPaddedSpan SliceWithZeroPadding(this ReadOnlySpan span, scoped in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right) => startIndex >= span.Length || startIndex > int.MaxValue + ? new ZeroPaddedSpan(default, length, PadDirection.Right) + : SliceWithZeroPadding(span, (int)startIndex, length, padDirection); + + public static ZeroPaddedSpan SliceWithZeroPadding(this ReadOnlyMemory bytes, scoped in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right) => + startIndex >= bytes.Length || startIndex > int.MaxValue + ? new ZeroPaddedSpan(default, length, PadDirection.Right) + : SliceWithZeroPadding(bytes.Span, (int)startIndex, length, padDirection); public static ZeroPaddedSpan SliceWithZeroPadding(this byte[] bytes, scoped in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right) => bytes.AsSpan().SliceWithZeroPadding(startIndex, length, padDirection); diff --git a/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs b/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs index 73d517ad78d..6d167abac09 100644 --- a/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs +++ b/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs @@ -2,21 +2,30 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Runtime.CompilerServices; +using System.Threading; using Nethermind.Evm.Precompiles; namespace Nethermind.Evm.CodeAnalysis { - public class CodeInfo + public class CodeInfo : IThreadPoolWorkItem { - public byte[] MachineCode { get; set; } + public ReadOnlyMemory MachineCode { get; } public IPrecompile? Precompile { get; set; } - private JumpDestinationAnalyzer? _analyzer; + private readonly JumpDestinationAnalyzer _analyzer; + private static readonly JumpDestinationAnalyzer _emptyAnalyzer = new(Array.Empty()); + public static CodeInfo Empty { get; } = new CodeInfo(Array.Empty()); public CodeInfo(byte[] code) { MachineCode = code; + _analyzer = code.Length == 0 ? _emptyAnalyzer : new JumpDestinationAnalyzer(code); + } + + public CodeInfo(ReadOnlyMemory code) + { + MachineCode = code; + _analyzer = code.Length == 0 ? _emptyAnalyzer : new JumpDestinationAnalyzer(code); } public bool IsPrecompile => Precompile is not null; @@ -25,24 +34,17 @@ public CodeInfo(IPrecompile precompile) { Precompile = precompile; MachineCode = Array.Empty(); + _analyzer = _emptyAnalyzer; } public bool ValidateJump(int destination, bool isSubroutine) { - JumpDestinationAnalyzer analyzer = _analyzer; - analyzer ??= CreateAnalyzer(); - - return analyzer.ValidateJump(destination, isSubroutine); + return _analyzer.ValidateJump(destination, isSubroutine); } - /// - /// Do sampling to choose an algo when the code is big enough. - /// When the code size is small we can use the default analyzer. - /// - [MethodImpl(MethodImplOptions.NoInlining)] - private JumpDestinationAnalyzer CreateAnalyzer() + void IThreadPoolWorkItem.Execute() { - return _analyzer = new JumpDestinationAnalyzer(MachineCode); + _analyzer.Execute(); } } } diff --git a/src/Nethermind/Nethermind.Evm/CodeAnalysis/JumpDestinationAnalyzer.cs b/src/Nethermind/Nethermind.Evm/CodeAnalysis/JumpDestinationAnalyzer.cs index 8451a422ac4..8e944c18101 100644 --- a/src/Nethermind/Nethermind.Evm/CodeAnalysis/JumpDestinationAnalyzer.cs +++ b/src/Nethermind/Nethermind.Evm/CodeAnalysis/JumpDestinationAnalyzer.cs @@ -4,54 +4,38 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Threading; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; namespace Nethermind.Evm.CodeAnalysis { - public sealed class JumpDestinationAnalyzer : IThreadPoolWorkItem + public sealed class JumpDestinationAnalyzer(ReadOnlyMemory code) { private const int PUSH1 = 0x60; - private const int PUSH32 = 0x7f; + private const int PUSHx = PUSH1 - 1; private const int JUMPDEST = 0x5b; private const int BEGINSUB = 0x5c; - private const int BitShiftPerInt32 = 5; + private const int BitShiftPerInt64 = 6; - private int[]? _jumpDestBitmap; - public byte[] MachineCode { get; set; } + private static readonly long[]? _emptyJumpDestinationBitmap = new long[1]; + private long[]? _jumpDestinationBitmap = code.Length == 0 ? _emptyJumpDestinationBitmap : null; - public JumpDestinationAnalyzer(byte[] code) - { - // Store the code refence as the JumpDest analysis is lazy - // and not performed until first jump. - MachineCode = code; - - // Start generating the JumpDestinationBitmap in background. - ThreadPool.UnsafeQueueUserWorkItem(this, preferLocal: false); - } + private ReadOnlyMemory MachineCode { get; } = code; public bool ValidateJump(int destination, bool isSubroutine) { - // Take array ref to local so Jit knows its size won't change in the method. - byte[] machineCode = MachineCode; - _jumpDestBitmap ??= CreateJumpDestinationBitmap(machineCode); + ReadOnlySpan machineCode = MachineCode.Span; + _jumpDestinationBitmap ??= CreateJumpDestinationBitmap(machineCode); var result = false; // Cast to uint to change negative numbers to very int high numbers // Then do length check, this both reduces check by 1 and eliminates the bounds - // check from accessing the array. - if ((uint)destination < (uint)machineCode.Length && - IsJumpDestination(_jumpDestBitmap, destination)) + // check from accessing the span. + if ((uint)destination < (uint)machineCode.Length && IsJumpDestination(_jumpDestinationBitmap, destination)) { // Store byte to int, as less expensive operations at word size int codeByte = machineCode[destination]; - if (isSubroutine) - { - result = codeByte == BEGINSUB; - } - else - { - result = codeByte == JUMPDEST; - } + result = isSubroutine ? codeByte == BEGINSUB : codeByte == JUMPDEST; } return result; @@ -59,13 +43,13 @@ public bool ValidateJump(int destination, bool isSubroutine) /// /// Used for conversion between different representations of bit array. - /// Returns (n + (32 - 1)) / 32, rearranged to avoid arithmetic overflow. + /// Returns (n + (64 - 1)) / 64, rearranged to avoid arithmetic overflow. /// For example, in the bit to int case, the straightforward calc would - /// be (n + 31) / 32, but that would cause overflow. So instead it's - /// rearranged to ((n - 1) / 32) + 1. + /// be (n + 63) / 64, but that would cause overflow. So instead it's + /// rearranged to ((n - 1) / 64) + 1. /// Due to sign extension, we don't need to special case for n == 0, if we use - /// bitwise operations (since ((n - 1) >> 5) + 1 = 0). - /// This doesn't hold true for ((n - 1) / 32) + 1, which equals 1. + /// bitwise operations (since ((n - 1) >> 6) + 1 = 0). + /// This doesn't hold true for ((n - 1) / 64) + 1, which equals 1. /// /// Usage: /// GetInt32ArrayLengthFromBitLength(77): returns how many ints must be @@ -73,79 +57,128 @@ public bool ValidateJump(int destination, bool isSubroutine) /// /// /// how many ints are required to store n bytes - private static int GetInt32ArrayLengthFromBitLength(int n) - { - return (int)((uint)(n - 1 + (1 << BitShiftPerInt32)) >> BitShiftPerInt32); - } + private static int GetInt64ArrayLengthFromBitLength(int n) => + (n - 1 + (1 << BitShiftPerInt64)) >>> BitShiftPerInt64; /// /// Collects data locations in code. /// An unset bit means the byte is an opcode, a set bit means it's data. /// - private static int[] CreateJumpDestinationBitmap(byte[] code) + private static long[] CreateJumpDestinationBitmap(ReadOnlySpan code) { - int[] jumpDestBitmap = new int[GetInt32ArrayLengthFromBitLength(code.Length)]; - - int pc = 0; + long[] jumpDestinationBitmap = new long[GetInt64ArrayLengthFromBitLength(code.Length)]; + int programCounter = 0; + // We accumulate each array segment to a register and then flush to memory when we move to next. + long currentFlags = 0; while (true) { - // Since we are using a non-standard for loop here; - // changing to while(true) plus below if check elides - // the bounds check from the following code array access. - if ((uint)pc >= (uint)code.Length) break; + // Set default programCounter increment to 1 for default case when don't vectorize or read a PUSH. + int move = 1; + // We use Sse rather than Avx or Avx-512 as is optimization for stretch of code without PUSHes. + // As the vector size increases the chance of there being a PUSH increases which will disable this optimization. + if (Sse2.IsSupported && + // Check not going to read passed end of code. + programCounter <= code.Length - Vector128.Count && + // Are we on an short stride, one quarter of the long flags? + (programCounter & 15) == 0) + { + Vector128 data = Unsafe.As>(ref Unsafe.AddByteOffset(ref MemoryMarshal.GetReference(code), programCounter)); + // Pushes are 0x60 to 0x7f; converting to signed bytes any instruction higher than PUSH32 + // becomes negative so we can just do a single greater than test to see if any present. + Vector128 compare = Sse2.CompareGreaterThan(data, Vector128.Create((sbyte)PUSHx)); + if (compare == default) + { + // Check the bytes for any JUMPDESTs. + Vector128 dest = Sse2.CompareEqual(data, Vector128.Create((sbyte)JUMPDEST)); + // Check the bytes for any BEGINSUBs. + Vector128 sub = Sse2.CompareEqual(data, Vector128.Create((sbyte)BEGINSUB)); + // Merge the two results. + Vector128 combined = Sse2.Or(dest, sub); + // Extract the checks as a set of int flags. + int flags = Sse2.MoveMask(combined); + // Shift up flags by depending which side of long we are on, and merge to current set. + currentFlags |= (long)flags << (programCounter & (32 + 16)); + // Forward programCounter by Vector128 stride. + move = Vector128.Count; + goto Next; + } + } + + // Grab the instruction from the code; zero length code + // doesn't enter this method and we check at end of loop if + // hit the last element and should exit, so skip bounds check + // access here. + int op = Unsafe.Add(ref MemoryMarshal.GetReference(code), programCounter); - // Grab the instruction from the code. - int op = code[pc]; + if ((uint)op - JUMPDEST <= BEGINSUB - JUMPDEST) + { + // Accumulate Jump Destinations to register, shift will wrap and single bit + // so can shift by the whole programCounter. + currentFlags |= 1L << programCounter; + } + else if ((sbyte)op > PUSHx) + { + // Fast forward programCounter by the amount of data the push + // represents as don't need to analyse data for Jump Destinations. + move = op - PUSH1 + 2; + } - if (op >= PUSH1 && op <= PUSH32) + Next: + int nextCounter = programCounter + move; + // Check if read last item of code; we want to write this out also even if not + // at a boundary and then we will return the results. + bool exit = nextCounter >= code.Length; + // Does the move mean we are moving to new segment of the long array? + // If we take the current index in flags, and add the move, are we at + // a new long segment, i.e. a larger than 64 position move. + if ((programCounter & 63) + move >= 64 || exit) { - // Skip forward amount of data the push represents - // don't need to analyse data for JumpDests - pc += op - PUSH1 + 1; + // If so write out the flags (if any are set) + if (currentFlags != 0) + { + // Moving to next array element (or finishing) assign to array. + MarkJumpDestinations(jumpDestinationBitmap, programCounter, currentFlags); + // Clear the flags in preparation for the next array segment. + currentFlags = 0; + } } - else if (op == JUMPDEST || op == BEGINSUB) + + if (exit) { - // Exact type will be checked again by ValidateJump - MarkAsJumpDestination(jumpDestBitmap, pc); + // End of code. + break; } - // Next instruction - pc++; + // Move to next instruction. + programCounter = nextCounter; } - return jumpDestBitmap; + return jumpDestinationBitmap; } /// /// Checks if the position is in a code segment. /// - private static bool IsJumpDestination(int[] bitvec, int pos) + private static bool IsJumpDestination(long[] bitvec, int pos) { - int vecIndex = pos >> BitShiftPerInt32; - // Check if in bounds, Jit will add slightly more expensive exception throwing check if we don't + int vecIndex = pos >> BitShiftPerInt64; + // Check if in bounds, Jit will add slightly more expensive exception throwing check if we don't. if ((uint)vecIndex >= (uint)bitvec.Length) return false; - return (bitvec[vecIndex] & (1 << pos)) != 0; + return (bitvec[vecIndex] & (1L << pos)) != 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void MarkAsJumpDestination(int[] bitvec, int pos) + private static void MarkJumpDestinations(long[] jumpDestinationBitmap, int pos, long flags) { - int vecIndex = pos >> BitShiftPerInt32; - Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bitvec), vecIndex) - |= 1 << pos; + uint offset = (uint)pos >> BitShiftPerInt64; + Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(jumpDestinationBitmap), offset) |= flags; } - void IThreadPoolWorkItem.Execute() + public void Execute() { - if (_jumpDestBitmap is null) - { - var jumpDestBitmap = CreateJumpDestinationBitmap(MachineCode); - // Atomically assign if still null. Aren't really any thread safety issues here, - // as will be same result. Just keep first one we created; as Evm will have started - // using it if already created and let this one be Gen0 GC'd. - Interlocked.CompareExchange(ref _jumpDestBitmap, jumpDestBitmap, null); - } + // This is to support background thread preparation of the bitmap. + _jumpDestinationBitmap ??= CreateJumpDestinationBitmap(MachineCode.Span); } } } diff --git a/src/Nethermind/Nethermind.Evm/EvmStack.cs b/src/Nethermind/Nethermind.Evm/EvmStack.cs index b59af410489..0256eda50e2 100644 --- a/src/Nethermind/Nethermind.Evm/EvmStack.cs +++ b/src/Nethermind/Nethermind.Evm/EvmStack.cs @@ -333,7 +333,7 @@ public byte PopByte() return _bytes[Head * WordSize + WordSize - sizeof(byte)]; } - public void PushLeftPaddedBytes(Span value, int paddingLength) + public void PushLeftPaddedBytes(ReadOnlySpan value, int paddingLength) { if (typeof(TTracing) == typeof(IsTracing)) _tracer.ReportStackPush(value); diff --git a/src/Nethermind/Nethermind.Evm/IVirtualMachine.cs b/src/Nethermind/Nethermind.Evm/IVirtualMachine.cs index 2a8188828b3..ffe5b0a613f 100644 --- a/src/Nethermind/Nethermind.Evm/IVirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/IVirtualMachine.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core; +using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Evm.CodeAnalysis; using Nethermind.Evm.Tracing; @@ -17,5 +18,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); } } diff --git a/src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs index a3ddb2a9ca1..52c917694e5 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs @@ -89,7 +89,7 @@ public static AlwaysCancelTxTracer Instance public void ReportActionEnd(long gas, Address deploymentAddress, ReadOnlyMemory deployedCode) => throw new OperationCanceledException(ErrorMessage); public void ReportBlockHash(Hash256 blockHash) => throw new OperationCanceledException(ErrorMessage); - public void ReportByteCode(byte[] byteCode) => throw new OperationCanceledException(ErrorMessage); + public void ReportByteCode(ReadOnlyMemory byteCode) => throw new OperationCanceledException(ErrorMessage); public void ReportGasUpdateForVmTrace(long refund, long gasAvailable) => throw new OperationCanceledException(ErrorMessage); public void ReportRefund(long refund) => throw new OperationCanceledException(ErrorMessage); public void ReportExtraGasPressure(long extraGasPressure) => throw new OperationCanceledException(ErrorMessage); diff --git a/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs index c43469bd91c..9ade3798ea3 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs @@ -157,7 +157,7 @@ public void ReportActionRevert(long gasLeft, byte[] output) => public void ReportActionEnd(long gas, Address deploymentAddress, ReadOnlyMemory deployedCode) => _currentTxTracer.ReportActionEnd(gas, deploymentAddress, deployedCode); - public void ReportByteCode(byte[] byteCode) => + public void ReportByteCode(ReadOnlyMemory byteCode) => _currentTxTracer.ReportByteCode(byteCode); public void ReportGasUpdateForVmTrace(long refund, long gasAvailable) => diff --git a/src/Nethermind/Nethermind.Evm/Tracing/CancellationTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/CancellationTxTracer.cs index 31759e88649..af2fed7b7c2 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/CancellationTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/CancellationTxTracer.cs @@ -384,7 +384,7 @@ public void ReportBlockHash(Hash256 blockHash) } } - public void ReportByteCode(byte[] byteCode) + public void ReportByteCode(ReadOnlyMemory byteCode) { _token.ThrowIfCancellationRequested(); if (_innerTracer.IsTracingCode) diff --git a/src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs index c4ad9abfd32..c6b8277a6b6 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs @@ -413,7 +413,7 @@ public void ReportBlockHash(Hash256 blockHash) } } - public void ReportByteCode(byte[] byteCode) + public void ReportByteCode(ReadOnlyMemory byteCode) { for (int index = 0; index < _txTracers.Count; index++) { diff --git a/src/Nethermind/Nethermind.Evm/Tracing/Debugger/DebugTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/Debugger/DebugTracer.cs index 5014ff4808c..02cf430b759 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/Debugger/DebugTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/Debugger/DebugTracer.cs @@ -239,7 +239,7 @@ public void ReportActionEnd(long gas, Address deploymentAddress, ReadOnlyMemory< public void ReportBlockHash(Hash256 blockHash) => InnerTracer.ReportBlockHash(blockHash); - public void ReportByteCode(byte[] byteCode) + public void ReportByteCode(ReadOnlyMemory byteCode) => InnerTracer.ReportByteCode(byteCode); public void ReportGasUpdateForVmTrace(long refund, long gasAvailable) diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs index ca99d17265e..26057c97f89 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs @@ -375,11 +375,11 @@ void LoadOperationTransientStorage(Address storageCellAddress, UInt256 storageIn void ReportBlockHash(Hash256 blockHash); /// - /// + /// /// /// /// Depends on - void ReportByteCode(byte[] byteCode); + void ReportByteCode(ReadOnlyMemory byteCode); /// /// Special case for VM trace in Parity but we consider removing support for it diff --git a/src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs index ee1c0bb456a..0daaf63efc1 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs @@ -93,7 +93,7 @@ public override void ReportActionEnd(long gas, Address deploymentAddress, ReadOn => ThrowInvalidOperationException(); public override void ReportBlockHash(Hash256 blockHash) => ThrowInvalidOperationException(); - public override void ReportByteCode(byte[] byteCode) + public override void ReportByteCode(ReadOnlyMemory byteCode) => ThrowInvalidOperationException(); public override void ReportGasUpdateForVmTrace(long refund, long gasAvailable) diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs index 908a90527d8..3bddd02d4d5 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs @@ -468,9 +468,10 @@ public override void ReportActionEnd(long gas, Address deploymentAddress, ReadOn PopAction(); } - public override void ReportByteCode(byte[] byteCode) + public override void ReportByteCode(ReadOnlyMemory byteCode) { - _currentVmTrace.VmTrace.Code = byteCode; + // TODO: use memory pool? + _currentVmTrace.VmTrace.Code = byteCode.ToArray(); } public override void ReportGasUpdateForVmTrace(long refund, long gasAvailable) diff --git a/src/Nethermind/Nethermind.Evm/Tracing/TxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/TxTracer.cs index 14343567c4c..1b196a33507 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/TxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/TxTracer.cs @@ -66,7 +66,7 @@ public virtual void ReportActionEnd(long gas, ReadOnlyMemory output) { } public virtual void ReportActionError(EvmExceptionType evmExceptionType) { } public virtual void ReportActionEnd(long gas, Address deploymentAddress, ReadOnlyMemory deployedCode) { } public virtual void ReportBlockHash(Hash256 blockHash) { } - public virtual void ReportByteCode(byte[] byteCode) { } + public virtual void ReportByteCode(ReadOnlyMemory byteCode) { } public virtual void ReportGasUpdateForVmTrace(long refund, long gasAvailable) { } public virtual void ReportRefund(long refund) { } public virtual void ReportExtraGasPressure(long extraGasPressure) { } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index 90d039ff7eb..8dcbb876024 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -5,6 +5,8 @@ using System.IO; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading; + using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; @@ -552,7 +554,9 @@ protected virtual bool ExecuteEvmCall( if (unspentGas >= codeDepositGasCost) { - WorldState.InsertCode(env.ExecutingAccount, substate.Output, spec); + var code = substate.Output.ToArray(); + VirtualMachine.InsertCode(code, env.ExecutingAccount, spec); + unspentGas -= codeDepositGasCost; } } diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index d388f58a775..5e01871d832 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -32,6 +32,8 @@ namespace Nethermind.Evm; using System.Linq; +using System.Threading; + using Int256; public class VirtualMachine : IVirtualMachine @@ -59,6 +61,11 @@ 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) + { + _evm.InsertCode(code, codeOwner, spec); + } + public TransactionSubstate Run(EvmState state, IWorldState worldState, ITxTracer txTracer) where TTracingActions : struct, IIsTracing => _evm.Run(state, worldState, txTracer); @@ -126,8 +133,7 @@ public interface IIsTracing { } public readonly struct IsTracing : IIsTracing { } } -internal sealed class VirtualMachine : IVirtualMachine - where TLogger : struct, IIsTracing +internal sealed class VirtualMachine : IVirtualMachine where TLogger : struct, IIsTracing { private readonly UInt256 P255Int = (UInt256)System.Numerics.BigInteger.Pow(2, 255); private UInt256 P255 => P255Int; @@ -354,7 +360,9 @@ public TransactionSubstate Run(EvmState state, IWorldState worl bool invalidCode = CodeDepositHandler.CodeIsInvalid(spec, callResult.Output); if (gasAvailableForCodeDeposit >= codeDepositGasCost && !invalidCode) { - _state.InsertCode(callCodeOwner, callResult.Output, spec); + var code = callResult.Output; + InsertCode(code, callCodeOwner, spec); + currentState.GasAvailable -= codeDepositGasCost; if (typeof(TTracingActions) == typeof(IsTracing)) @@ -462,6 +470,17 @@ public TransactionSubstate Run(EvmState state, IWorldState worl } } + public void InsertCode(byte[] 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()); + _state.InsertCode(callCodeOwner, codeHash, code, spec); + _codeCache.Set(codeHash, codeInfo); + } + private void RevertParityTouchBugAccount(IReleaseSpec spec) { if (_parityTouchBugAccount.ShouldDelete) @@ -487,8 +506,14 @@ public CodeInfo GetCachedCodeInfo(IWorldState worldState, Address codeSource, IR return _precompiles[codeSource]; } + CodeInfo cachedCodeInfo = null; Hash256 codeHash = worldState.GetCodeHash(codeSource); - CodeInfo cachedCodeInfo = _codeCache.Get(codeHash); + if (ReferenceEquals(codeHash, Keccak.OfAnEmptyString)) + { + cachedCodeInfo = CodeInfo.Empty; + } + + cachedCodeInfo ??= _codeCache.Get(codeHash); if (cachedCodeInfo is null) { byte[] code = worldState.GetCode(codeHash); @@ -774,7 +799,7 @@ private CallResult ExecuteCode code = env.CodeInfo.MachineCode.AsSpan(); + ReadOnlySpan code = env.CodeInfo.MachineCode.Span; EvmExceptionType exceptionType = EvmExceptionType.None; bool isRevert = false; #if DEBUG @@ -1400,7 +1425,7 @@ private CallResult ExecuteCode externalCode = GetCachedCodeInfo(_worldState, address, spec).MachineCode; slice = externalCode.SliceWithZeroPadding(b, (int)result); vmState.Memory.Save(in a, in slice); if (typeof(TTracingInstructions) == typeof(IsTracing)) @@ -2170,8 +2195,8 @@ private CallResult ExecuteCode(Address address, ref EvmStack stack, IReleaseSpec spec) where TTracingInstructions : struct, IIsTracing { - byte[] accountCode = GetCachedCodeInfo(_worldState, address, spec).MachineCode; - UInt256 result = (UInt256)accountCode.Length; + int codeLength = GetCachedCodeInfo(_worldState, address, spec).MachineCode.Span.Length; + UInt256 result = (UInt256)codeLength; stack.PushUInt256(in result); } @@ -2463,7 +2488,7 @@ private EvmExceptionType InstructionSelfDestruct(EvmState vmState, ref return (EvmExceptionType.None, null); } - Span initCode = vmState.Memory.LoadSpan(in memoryPositionOfInitCode, initCodeLength); + ReadOnlyMemory initCode = vmState.Memory.Load(in memoryPositionOfInitCode, initCodeLength); UInt256 balance = _state.GetBalance(env.ExecutingAccount); if (value > balance) @@ -2490,7 +2515,7 @@ private EvmExceptionType InstructionSelfDestruct(EvmState vmState, ref Address contractAddress = instruction == Instruction.CREATE ? ContractAddress.From(env.ExecutingAccount, _state.GetNonce(env.ExecutingAccount)) - : ContractAddress.From(env.ExecutingAccount, salt, initCode); + : ContractAddress.From(env.ExecutingAccount, salt, initCode.Span); if (spec.UseHotAndColdStorage) { @@ -2524,14 +2549,10 @@ private EvmExceptionType InstructionSelfDestruct(EvmState vmState, ref _state.SubtractFromBalance(env.ExecutingAccount, value, spec); - ValueHash256 codeHash = ValueKeccak.Compute(initCode); - // Prefer code from code cache (e.g. if create from a factory contract or copypasta) - if (!_codeCache.TryGet(codeHash, out CodeInfo codeInfo)) - { - codeInfo = new(initCode.ToArray()); - // Prime the code cache as likely to be used by more txs - _codeCache.Set(codeHash, codeInfo); - } + // Do not add the initCode to the cache as it is + // pointing to data in this tx and will become invalid + // for another tx as returned to pool. + CodeInfo codeInfo = new(initCode); ExecutionEnvironment callEnv = new ( diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs index c0448532a2f..95154d4d1a6 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs @@ -14,6 +14,7 @@ using Nethermind.Specs; using Nethermind.Specs.Forks; using Nethermind.Specs.Test; +using Nethermind.State; using Newtonsoft.Json.Linq; using NUnit.Framework; diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs index ceb8024cbbb..73791ea3169 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs @@ -12,6 +12,7 @@ using Nethermind.Specs; using Nethermind.Specs.Forks; using Nethermind.Specs.Test; +using Nethermind.State; using NUnit.Framework; namespace Nethermind.JsonRpc.Test.Modules.Eth; diff --git a/src/Nethermind/Nethermind.State/IWorldState.cs b/src/Nethermind/Nethermind.State/IWorldState.cs index 98c85d14503..b25ef558f67 100644 --- a/src/Nethermind/Nethermind.State/IWorldState.cs +++ b/src/Nethermind/Nethermind.State/IWorldState.cs @@ -83,7 +83,7 @@ public interface IWorldState : IJournal, IReadOnlyStateProvider void CreateAccount(Address address, in UInt256 balance, in UInt256 nonce = default); void CreateAccountIfNotExists(Address address, in UInt256 balance, in UInt256 nonce = default); - void InsertCode(Address address, ReadOnlyMemory code, IReleaseSpec spec, bool isGenesis = false); + void InsertCode(Address address, Hash256 codeHash, ReadOnlyMemory code, IReleaseSpec spec, bool isGenesis = false); void AddToBalance(Address address, in UInt256 balanceChange, IReleaseSpec spec); diff --git a/src/Nethermind/Nethermind.State/IWorldStateExtensions.cs b/src/Nethermind/Nethermind.State/IWorldStateExtensions.cs index 468763e770b..b5e7dc0a99f 100644 --- a/src/Nethermind/Nethermind.State/IWorldStateExtensions.cs +++ b/src/Nethermind/Nethermind.State/IWorldStateExtensions.cs @@ -3,7 +3,9 @@ using System; using Nethermind.Core; +using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; +using Nethermind.Core.Specs; using Nethermind.Logging; using Nethermind.Trie; @@ -14,11 +16,13 @@ public static class WorldStateExtensions public static byte[] GetCode(this IWorldState stateProvider, Address address) { Account account = stateProvider.GetAccount(address); - if (!account.HasCode) - { - return Array.Empty(); - } - return stateProvider.GetCode(account.CodeHash); + return !account.HasCode ? Array.Empty() : stateProvider.GetCode(account.CodeHash); + } + + public static void InsertCode(this IWorldState worldState, Address address, ReadOnlyMemory code, IReleaseSpec spec, bool isGenesis = false) + { + Hash256 codeHash = code.Length == 0 ? Keccak.OfAnEmptyString : Keccak.Compute(code.Span); + worldState.InsertCode(address, codeHash, code, spec, isGenesis); } public static string DumpState(this IWorldState stateProvider) diff --git a/src/Nethermind/Nethermind.State/StateProvider.cs b/src/Nethermind/Nethermind.State/StateProvider.cs index ea04bc1dbc1..5fd453c0ed9 100644 --- a/src/Nethermind/Nethermind.State/StateProvider.cs +++ b/src/Nethermind/Nethermind.State/StateProvider.cs @@ -146,10 +146,9 @@ public UInt256 GetBalance(Address address) return account?.Balance ?? UInt256.Zero; } - public void InsertCode(Address address, ReadOnlyMemory code, IReleaseSpec spec, bool isGenesis = false) + public void InsertCode(Address address, Hash256 codeHash, ReadOnlyMemory code, IReleaseSpec spec, bool isGenesis = false) { _needsStateRootUpdate = true; - Hash256 codeHash = code.Length == 0 ? Keccak.OfAnEmptyString : Keccak.Compute(code.Span); // Don't reinsert if already inserted. This can be the case when the same // code is used by multiple deployments. Either from factory contracts (e.g. LPs) diff --git a/src/Nethermind/Nethermind.State/WorldState.cs b/src/Nethermind/Nethermind.State/WorldState.cs index aaeaf4bab1d..4d93ab22831 100644 --- a/src/Nethermind/Nethermind.State/WorldState.cs +++ b/src/Nethermind/Nethermind.State/WorldState.cs @@ -106,10 +106,12 @@ public void CreateAccount(Address address, in UInt256 balance, in UInt256 nonce { _stateProvider.CreateAccount(address, balance, nonce); } - public void InsertCode(Address address, ReadOnlyMemory code, IReleaseSpec spec, bool isGenesis = false) + + public void InsertCode(Address address, Hash256 codeHash, ReadOnlyMemory code, IReleaseSpec spec, bool isGenesis = false) { - _stateProvider.InsertCode(address, code, spec, isGenesis); + _stateProvider.InsertCode(address, codeHash, code, spec, isGenesis); } + public void AddToBalance(Address address, in UInt256 balanceChange, IReleaseSpec spec) { _stateProvider.AddToBalance(address, balanceChange, spec); diff --git a/src/Nethermind/Nethermind.Test.Runner/StateTestTxTracer.cs b/src/Nethermind/Nethermind.Test.Runner/StateTestTxTracer.cs index 322ea016b81..31707568258 100644 --- a/src/Nethermind/Nethermind.Test.Runner/StateTestTxTracer.cs +++ b/src/Nethermind/Nethermind.Test.Runner/StateTestTxTracer.cs @@ -220,7 +220,7 @@ public void ReportBlockHash(Hash256 blockHash) throw new NotImplementedException(); } - public void ReportByteCode(byte[] byteCode) + public void ReportByteCode(ReadOnlyMemory byteCode) { throw new NotSupportedException(); }