diff --git a/src/Nethermind/Nethermind.Blockchain.Test/CachedCodeInfoRepositoryTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/CachedCodeInfoRepositoryTests.cs index 14d605000172..b933980d7e6b 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/CachedCodeInfoRepositoryTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/CachedCodeInfoRepositoryTests.cs @@ -36,7 +36,7 @@ public void Precompile_WithCachingEnabled_IsWrappedInCachedPrecompile() TestPrecompile cachingPrecompile = new(supportsCaching: true); Address precompileAddress = Address.FromNumber(100); - FrozenDictionary precompiles = new Dictionary + FrozenDictionary precompiles = new Dictionary { [precompileAddress] = new(cachingPrecompile) }.ToFrozenDictionary(); @@ -51,7 +51,7 @@ public void Precompile_WithCachingEnabled_IsWrappedInCachedPrecompile() // Act CachedCodeInfoRepository repository = new(precompileProvider, baseRepository, cache); - ICodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); + CodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); // Assert codeInfo.Should().NotBeNull(); @@ -66,7 +66,7 @@ public void Precompile_WithCachingDisabled_IsNotWrapped() TestPrecompile nonCachingPrecompile = new(supportsCaching: false); Address precompileAddress = Address.FromNumber(100); - FrozenDictionary precompiles = new Dictionary + FrozenDictionary precompiles = new Dictionary { [precompileAddress] = new(nonCachingPrecompile) }.ToFrozenDictionary(); @@ -81,7 +81,7 @@ public void Precompile_WithCachingDisabled_IsNotWrapped() // Act CachedCodeInfoRepository repository = new(precompileProvider, baseRepository, cache); - ICodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); + CodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); // Assert codeInfo.Should().NotBeNull(); @@ -92,7 +92,7 @@ public void Precompile_WithCachingDisabled_IsNotWrapped() public void IdentityPrecompile_IsNotWrapped_WhenCacheEnabled() { // Arrange - FrozenDictionary precompiles = new Dictionary + FrozenDictionary precompiles = new Dictionary { [IdentityPrecompile.Address] = new(IdentityPrecompile.Instance) }.ToFrozenDictionary(); @@ -107,7 +107,7 @@ public void IdentityPrecompile_IsNotWrapped_WhenCacheEnabled() // Act CachedCodeInfoRepository repository = new(precompileProvider, baseRepository, cache); - ICodeInfo codeInfo = repository.GetCachedCodeInfo(IdentityPrecompile.Address, false, spec, out _); + CodeInfo codeInfo = repository.GetCachedCodeInfo(IdentityPrecompile.Address, false, spec, out _); // Assert codeInfo.Should().NotBeNull(); @@ -122,7 +122,7 @@ public void CachedPrecompile_CachesResults_ForCachingEnabledPrecompile() TestPrecompile cachingPrecompile = new(supportsCaching: true, onRun: () => runCount++); Address precompileAddress = Address.FromNumber(100); - FrozenDictionary precompiles = new Dictionary + FrozenDictionary precompiles = new Dictionary { [precompileAddress] = new(cachingPrecompile) }.ToFrozenDictionary(); @@ -136,7 +136,7 @@ public void CachedPrecompile_CachesResults_ForCachingEnabledPrecompile() IReleaseSpec spec = CreateSpecWithPrecompile(precompileAddress); CachedCodeInfoRepository repository = new(precompileProvider, baseRepository, cache); - ICodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); + CodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); byte[] input = [1, 2, 3]; @@ -157,7 +157,7 @@ public void NonCachingPrecompile_DoesNotCacheResults() TestPrecompile nonCachingPrecompile = new(supportsCaching: false, onRun: () => runCount++); Address precompileAddress = Address.FromNumber(100); - FrozenDictionary precompiles = new Dictionary + FrozenDictionary precompiles = new Dictionary { [precompileAddress] = new(nonCachingPrecompile) }.ToFrozenDictionary(); @@ -171,7 +171,7 @@ public void NonCachingPrecompile_DoesNotCacheResults() IReleaseSpec spec = CreateSpecWithPrecompile(precompileAddress); CachedCodeInfoRepository repository = new(precompileProvider, baseRepository, cache); - ICodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); + CodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); byte[] input = [1, 2, 3]; @@ -191,7 +191,7 @@ public void NullCache_DoesNotWrapAnyPrecompiles() TestPrecompile cachingPrecompile = new(supportsCaching: true); Address precompileAddress = Address.FromNumber(100); - FrozenDictionary precompiles = new Dictionary + FrozenDictionary precompiles = new Dictionary { [precompileAddress] = new(cachingPrecompile) }.ToFrozenDictionary(); @@ -205,7 +205,7 @@ public void NullCache_DoesNotWrapAnyPrecompiles() // Act - pass null cache CachedCodeInfoRepository repository = new(precompileProvider, baseRepository, null); - ICodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); + CodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); // Assert - precompile should not be wrapped codeInfo.Should().NotBeNull(); @@ -216,7 +216,7 @@ public void NullCache_DoesNotWrapAnyPrecompiles() public void Sha256Precompile_IsWrapped_WhenCacheEnabled() { // Arrange - Sha256Precompile has SupportsCaching = true (default) - FrozenDictionary precompiles = new Dictionary + FrozenDictionary precompiles = new Dictionary { [Sha256Precompile.Address] = new(Sha256Precompile.Instance) }.ToFrozenDictionary(); @@ -231,7 +231,7 @@ public void Sha256Precompile_IsWrapped_WhenCacheEnabled() // Act CachedCodeInfoRepository repository = new(precompileProvider, baseRepository, cache); - ICodeInfo codeInfo = repository.GetCachedCodeInfo(Sha256Precompile.Address, false, spec, out _); + CodeInfo codeInfo = repository.GetCachedCodeInfo(Sha256Precompile.Address, false, spec, out _); // Assert - Sha256Precompile should be wrapped (unlike IdentityPrecompile) codeInfo.Should().NotBeNull(); @@ -243,7 +243,7 @@ public void Sha256Precompile_IsWrapped_WhenCacheEnabled() public void MixedPrecompiles_OnlyCachingEnabledAreWrapped() { // Arrange - mix of caching and non-caching precompiles - FrozenDictionary precompiles = new Dictionary + FrozenDictionary precompiles = new Dictionary { [Sha256Precompile.Address] = new(Sha256Precompile.Instance), // SupportsCaching = true [IdentityPrecompile.Address] = new(IdentityPrecompile.Instance) // SupportsCaching = false @@ -264,8 +264,8 @@ public void MixedPrecompiles_OnlyCachingEnabledAreWrapped() // Act CachedCodeInfoRepository repository = new(precompileProvider, baseRepository, cache); - ICodeInfo sha256CodeInfo = repository.GetCachedCodeInfo(Sha256Precompile.Address, false, spec, out _); - ICodeInfo identityCodeInfo = repository.GetCachedCodeInfo(IdentityPrecompile.Address, false, spec, out _); + CodeInfo sha256CodeInfo = repository.GetCachedCodeInfo(Sha256Precompile.Address, false, spec, out _); + CodeInfo identityCodeInfo = repository.GetCachedCodeInfo(IdentityPrecompile.Address, false, spec, out _); // Assert - Sha256 wrapped, Identity not wrapped sha256CodeInfo.Precompile.Should().NotBeSameAs(Sha256Precompile.Instance); @@ -282,7 +282,7 @@ public void CachedPrecompile_DifferentInputs_CreateSeparateCacheEntries() TestPrecompile cachingPrecompile = new(supportsCaching: true, onRun: () => runCount++); Address precompileAddress = Address.FromNumber(100); - FrozenDictionary precompiles = new Dictionary + FrozenDictionary precompiles = new Dictionary { [precompileAddress] = new(cachingPrecompile) }.ToFrozenDictionary(); @@ -296,7 +296,7 @@ public void CachedPrecompile_DifferentInputs_CreateSeparateCacheEntries() IReleaseSpec spec = CreateSpecWithPrecompile(precompileAddress); CachedCodeInfoRepository repository = new(precompileProvider, baseRepository, cache); - ICodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); + CodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); byte[] input1 = [1, 2, 3]; byte[] input2 = [4, 5, 6]; @@ -321,7 +321,7 @@ public void CachedPrecompile_ReturnsCachedResult_OnCacheHit() TestPrecompile cachingPrecompile = new(supportsCaching: true, onRun: () => runCount++, fixedOutput: expectedOutput); Address precompileAddress = Address.FromNumber(100); - FrozenDictionary precompiles = new Dictionary + FrozenDictionary precompiles = new Dictionary { [precompileAddress] = new(cachingPrecompile) }.ToFrozenDictionary(); @@ -335,7 +335,7 @@ public void CachedPrecompile_ReturnsCachedResult_OnCacheHit() IReleaseSpec spec = CreateSpecWithPrecompile(precompileAddress); CachedCodeInfoRepository repository = new(precompileProvider, baseRepository, cache); - ICodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); + CodeInfo codeInfo = repository.GetCachedCodeInfo(precompileAddress, false, spec, out _); byte[] input = [1, 2, 3]; @@ -355,7 +355,7 @@ public void CachedPrecompile_ReturnsCachedResult_OnCacheHit() public void Sha256Precompile_CachesResults_WithRealComputation() { // Arrange - FrozenDictionary precompiles = new Dictionary + FrozenDictionary precompiles = new Dictionary { [Sha256Precompile.Address] = new(Sha256Precompile.Instance) }.ToFrozenDictionary(); @@ -369,7 +369,7 @@ public void Sha256Precompile_CachesResults_WithRealComputation() IReleaseSpec spec = CreateSpecWithPrecompile(Sha256Precompile.Address); CachedCodeInfoRepository repository = new(precompileProvider, baseRepository, cache); - ICodeInfo codeInfo = repository.GetCachedCodeInfo(Sha256Precompile.Address, false, spec, out _); + CodeInfo codeInfo = repository.GetCachedCodeInfo(Sha256Precompile.Address, false, spec, out _); byte[] input = [1, 2, 3, 4, 5]; @@ -388,7 +388,7 @@ public void Sha256Precompile_CachesResults_WithRealComputation() public void IdentityPrecompile_DoesNotCache_WithRealComputation() { // Arrange - FrozenDictionary precompiles = new Dictionary + FrozenDictionary precompiles = new Dictionary { [IdentityPrecompile.Address] = new(IdentityPrecompile.Instance) }.ToFrozenDictionary(); @@ -402,7 +402,7 @@ public void IdentityPrecompile_DoesNotCache_WithRealComputation() IReleaseSpec spec = CreateSpecWithPrecompile(IdentityPrecompile.Address); CachedCodeInfoRepository repository = new(precompileProvider, baseRepository, cache); - ICodeInfo codeInfo = repository.GetCachedCodeInfo(IdentityPrecompile.Address, false, spec, out _); + CodeInfo codeInfo = repository.GetCachedCodeInfo(IdentityPrecompile.Address, false, spec, out _); byte[] input = [1, 2, 3, 4, 5]; diff --git a/src/Nethermind/Nethermind.Blockchain/CachedCodeInfoRepository.cs b/src/Nethermind/Nethermind.Blockchain/CachedCodeInfoRepository.cs index c8ca251cb403..cdbd1857d4fb 100644 --- a/src/Nethermind/Nethermind.Blockchain/CachedCodeInfoRepository.cs +++ b/src/Nethermind/Nethermind.Blockchain/CachedCodeInfoRepository.cs @@ -21,11 +21,11 @@ public class CachedCodeInfoRepository( ICodeInfoRepository baseCodeInfoRepository, ConcurrentDictionary>? precompileCache) : ICodeInfoRepository { - private readonly FrozenDictionary _cachedPrecompile = precompileCache is null + private readonly FrozenDictionary _cachedPrecompile = precompileCache is null ? precompileProvider.GetPrecompiles() : precompileProvider.GetPrecompiles().ToFrozenDictionary(kvp => kvp.Key, kvp => CreateCachedPrecompile(kvp, precompileCache)); - public ICodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IReleaseSpec vmSpec, + public CodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IReleaseSpec vmSpec, out Address? delegationAddress) { if (vmSpec.IsPrecompile(codeSource) && _cachedPrecompile.TryGetValue(codeSource, out var cachedCodeInfo)) @@ -57,15 +57,15 @@ public bool TryGetDelegation(Address address, IReleaseSpec spec, return baseCodeInfoRepository.TryGetDelegation(address, spec, out delegatedAddress); } - private static PrecompileInfo CreateCachedPrecompile( - in KeyValuePair originalPrecompile, + private static CodeInfo CreateCachedPrecompile( + in KeyValuePair originalPrecompile, ConcurrentDictionary> cache) { IPrecompile precompile = originalPrecompile.Value.Precompile!; return !precompile.SupportsCaching ? originalPrecompile.Value - : new PrecompileInfo(new CachedPrecompile(originalPrecompile.Key.Value, precompile, cache)); + : new CodeInfo(new CachedPrecompile(originalPrecompile.Key.Value, precompile, cache)); } private class CachedPrecompile( diff --git a/src/Nethermind/Nethermind.Blockchain/EthereumPrecompileProvider.cs b/src/Nethermind/Nethermind.Blockchain/EthereumPrecompileProvider.cs index d793c9a65ba3..03fa5cff876d 100644 --- a/src/Nethermind/Nethermind.Blockchain/EthereumPrecompileProvider.cs +++ b/src/Nethermind/Nethermind.Blockchain/EthereumPrecompileProvider.cs @@ -13,9 +13,9 @@ namespace Nethermind.Blockchain; public class EthereumPrecompileProvider() : IPrecompileProvider { - private static FrozenDictionary Precompiles + private static FrozenDictionary Precompiles { - get => new Dictionary + get => new Dictionary { [EcRecoverPrecompile.Address] = new(EcRecoverPrecompile.Instance), [Sha256Precompile.Address] = new(Sha256Precompile.Instance), @@ -45,7 +45,7 @@ private static FrozenDictionary Precompiles }.ToFrozenDictionary(); } - public FrozenDictionary GetPrecompiles() + public FrozenDictionary GetPrecompiles() { return Precompiles; } diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/GethStyle/Custom/JavaScript/GethLikeJavaScriptTxTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/GethStyle/Custom/JavaScript/GethLikeJavaScriptTxTracer.cs index 296e39acbb4f..2460334a9b60 100644 --- a/src/Nethermind/Nethermind.Blockchain/Tracing/GethStyle/Custom/JavaScript/GethLikeJavaScriptTxTracer.cs +++ b/src/Nethermind/Nethermind.Blockchain/Tracing/GethStyle/Custom/JavaScript/GethLikeJavaScriptTxTracer.cs @@ -11,6 +11,7 @@ using Nethermind.Evm; using Nethermind.Evm.Tracing; using Nethermind.Evm.TransactionProcessing; +using Nethermind.Evm.CodeAnalysis; namespace Nethermind.Blockchain.Tracing.GethStyle.Custom.JavaScript; @@ -108,7 +109,7 @@ public override void ReportAction(long gas, UInt256 value, Address from, Address public override void StartOperation(int pc, Instruction opcode, long gas, in ExecutionEnvironment env, int codeSection = 0, int functionDepth = 0) { - _log.pc = pc + env.CodeInfo.PcOffset(); + _log.pc = pc + (env.CodeInfo is EofCodeInfo eof ? eof.PcOffset() : 0); _log.op = new Log.Opcode(opcode); _log.gas = gas; _log.depth = env.GetGethTraceDepth(); diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/ParityStyle/ParityLikeTxTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/ParityStyle/ParityLikeTxTracer.cs index 43d4ec399cfe..cc1b104b0a85 100644 --- a/src/Nethermind/Nethermind.Blockchain/Tracing/ParityStyle/ParityLikeTxTracer.cs +++ b/src/Nethermind/Nethermind.Blockchain/Tracing/ParityStyle/ParityLikeTxTracer.cs @@ -9,6 +9,7 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Evm; +using Nethermind.Evm.CodeAnalysis; using Nethermind.Evm.Tracing; using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; @@ -236,7 +237,7 @@ public override void StartOperation(int pc, Instruction opcode, long gas, in Exe { ParityVmOperationTrace operationTrace = new(); _gasAlreadySetForCurrentOp = false; - operationTrace.Pc = pc + env.CodeInfo.PcOffset(); + operationTrace.Pc = pc + (env.CodeInfo is EofCodeInfo eof ? eof.PcOffset() : 0); operationTrace.Cost = gas; // skip codeSection // skip functionDepth diff --git a/src/Nethermind/Nethermind.Evm.Test/CodeInfoRepositoryTests.cs b/src/Nethermind/Nethermind.Evm.Test/CodeInfoRepositoryTests.cs index 9865e3441676..b8da26cbc008 100644 --- a/src/Nethermind/Nethermind.Evm.Test/CodeInfoRepositoryTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/CodeInfoRepositoryTests.cs @@ -144,7 +144,7 @@ public void GetCachedCodeInfo_CodeTryGetDelegation_ReturnsCodeOfDelegation(byte[ stateProvider.InsertCode(delegationAddress, delegationCode, _releaseSpec); EthereumCodeInfoRepository sut = new(stateProvider); - ICodeInfo result = sut.GetCachedCodeInfo(TestItem.AddressA, _releaseSpec); + CodeInfo result = sut.GetCachedCodeInfo(TestItem.AddressA, _releaseSpec); result.CodeSpan.ToArray().Should().BeEquivalentTo(delegationCode); } diff --git a/src/Nethermind/Nethermind.Evm/CallResult.cs b/src/Nethermind/Nethermind.Evm/CallResult.cs index 08d88379284f..d23ac7ab54e3 100644 --- a/src/Nethermind/Nethermind.Evm/CallResult.cs +++ b/src/Nethermind/Nethermind.Evm/CallResult.cs @@ -44,7 +44,7 @@ public CallResult(ReadOnlyMemory output, bool? precompileSuccess, int from FromVersion = fromVersion; } - public CallResult(ICodeInfo? container, ReadOnlyMemory output, bool? precompileSuccess, int fromVersion, bool shouldRevert = false, EvmExceptionType exceptionType = EvmExceptionType.None) + public CallResult(CodeInfo? container, ReadOnlyMemory output, bool? precompileSuccess, int fromVersion, bool shouldRevert = false, EvmExceptionType exceptionType = EvmExceptionType.None) { StateToExecute = null; Output = (container, output); @@ -64,7 +64,7 @@ private CallResult(EvmExceptionType exceptionType) } public VmState? StateToExecute { get; } - public (ICodeInfo Container, ReadOnlyMemory Bytes) Output { get; } + public (CodeInfo Container, ReadOnlyMemory Bytes) Output { get; } public EvmExceptionType ExceptionType { get; } public bool ShouldRevert { get; } public bool? PrecompileSuccess { get; } diff --git a/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs b/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs index 4e2320bd3ff6..1e2274477b5d 100644 --- a/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs +++ b/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs @@ -3,35 +3,93 @@ using System; using System.Threading; +using Nethermind.Core.Extensions; +using Nethermind.Evm.Precompiles; namespace Nethermind.Evm.CodeAnalysis; -public sealed class CodeInfo(ReadOnlyMemory code) : ICodeInfo, IThreadPoolWorkItem +public class CodeInfo : IThreadPoolWorkItem, IEquatable { - private static readonly JumpDestinationAnalyzer _emptyAnalyzer = new(Array.Empty()); - public static CodeInfo Empty { get; } = new(ReadOnlyMemory.Empty); - public ReadOnlyMemory Code { get; } = code; - ReadOnlySpan ICodeInfo.CodeSpan => Code.Span; + public static CodeInfo Empty { get; } = new(); + // Empty code sentinel + private static readonly JumpDestinationAnalyzer? _emptyAnalyzer = new(Empty, skipAnalysis: true); - private readonly JumpDestinationAnalyzer _analyzer = code.Length == 0 ? _emptyAnalyzer : new JumpDestinationAnalyzer(code); + // Empty + private CodeInfo() + { + _analyzer = null; + } - public bool IsEmpty => ReferenceEquals(_analyzer, _emptyAnalyzer); + // Eof + protected CodeInfo(int version, ReadOnlyMemory code) + { + Version = version; + Code = code; + _analyzer = null; + } - public bool ValidateJump(int destination) + // Regular contract + public CodeInfo(ReadOnlyMemory code) { - return _analyzer.ValidateJump(destination); + Code = code; + _analyzer = code.Length == 0 ? _emptyAnalyzer : new JumpDestinationAnalyzer(this); } - void IThreadPoolWorkItem.Execute() + // Precompile + public CodeInfo(IPrecompile? precompile) { - _analyzer.Execute(); + Precompile = precompile; + _analyzer = null; } + public ReadOnlyMemory Code { get; } + public ReadOnlySpan CodeSpan => Code.Span; + + public IPrecompile? Precompile { get; } + + private readonly JumpDestinationAnalyzer _analyzer; + + public bool IsEmpty => ReferenceEquals(_analyzer, _emptyAnalyzer); + public bool IsPrecompile => Precompile is not null; + + public bool ValidateJump(int destination) + => _analyzer?.ValidateJump(destination) ?? false; + + /// + /// Gets the version of the code format. + /// The default implementation returns 0, representing a legacy code format or non-EOF code. + /// + public int Version { get; } = 0; + + void IThreadPoolWorkItem.Execute() + => _analyzer?.Execute(); + public void AnalyzeInBackgroundIfRequired() { - if (!ReferenceEquals(_analyzer, _emptyAnalyzer) && _analyzer.RequiresAnalysis) + if (!ReferenceEquals(_analyzer, _emptyAnalyzer) && (_analyzer?.RequiresAnalysis ?? false)) { ThreadPool.UnsafeQueueUserWorkItem(this, preferLocal: false); } } + + public override bool Equals(object? obj) + => Equals(obj as CodeInfo); + + public override int GetHashCode() + { + if (IsPrecompile) + return Precompile?.GetType().GetHashCode() ?? 0; + return CodeSpan.FastHash(); + } + + public bool Equals(CodeInfo? other) + { + if (other is null) + return false; + if (ReferenceEquals(this, other)) + return true; + if (IsPrecompile || other.IsPrecompile) + return Precompile?.GetType() == other.Precompile?.GetType(); + return CodeSpan.SequenceEqual(other.CodeSpan); + } } diff --git a/src/Nethermind/Nethermind.Evm/CodeAnalysis/JumpDestinationAnalyzer.cs b/src/Nethermind/Nethermind.Evm/CodeAnalysis/JumpDestinationAnalyzer.cs index 2ceca978a1ba..7923f62aeafc 100644 --- a/src/Nethermind/Nethermind.Evm/CodeAnalysis/JumpDestinationAnalyzer.cs +++ b/src/Nethermind/Nethermind.Evm/CodeAnalysis/JumpDestinationAnalyzer.cs @@ -16,7 +16,7 @@ namespace Nethermind.Evm.CodeAnalysis; -public sealed class JumpDestinationAnalyzer(ReadOnlyMemory code) +public sealed class JumpDestinationAnalyzer(CodeInfo codeInfo, bool skipAnalysis = false) { private const int PUSH1 = (int)Instruction.PUSH1; private const int PUSHx = PUSH1 - 1; @@ -24,10 +24,10 @@ public sealed class JumpDestinationAnalyzer(ReadOnlyMemory code) private const int BitShiftPerInt64 = 6; private static readonly long[]? _emptyJumpDestinationBitmap = new long[1]; - private long[]? _jumpDestinationBitmap = code.Length == 0 ? _emptyJumpDestinationBitmap : null; + private long[]? _jumpDestinationBitmap = (codeInfo.Code.Length == 0 || skipAnalysis) ? _emptyJumpDestinationBitmap : null; private object? _analysisComplete; - private ReadOnlyMemory MachineCode { get; } = code; + public ReadOnlyMemory MachineCode => codeInfo.Code; public bool ValidateJump(int destination) { diff --git a/src/Nethermind/Nethermind.Evm/CodeInfoFactory.cs b/src/Nethermind/Nethermind.Evm/CodeInfoFactory.cs index 43fd8a86b8b2..91ff0753e0e1 100644 --- a/src/Nethermind/Nethermind.Evm/CodeInfoFactory.cs +++ b/src/Nethermind/Nethermind.Evm/CodeInfoFactory.cs @@ -10,7 +10,7 @@ namespace Nethermind.Evm.CodeAnalysis; public static class CodeInfoFactory { - public static ICodeInfo CreateCodeInfo(ReadOnlyMemory code, IReleaseSpec spec, ValidationStrategy validationRules = ValidationStrategy.ExtractHeader) + public static CodeInfo CreateCodeInfo(ReadOnlyMemory code, IReleaseSpec spec, ValidationStrategy validationRules = ValidationStrategy.ExtractHeader) { if (spec.IsEofEnabled && code.Span.StartsWith(EofValidator.MAGIC) @@ -23,7 +23,7 @@ public static ICodeInfo CreateCodeInfo(ReadOnlyMemory code, IReleaseSpec s return codeInfo; } - public static bool CreateInitCodeInfo(ReadOnlyMemory data, IReleaseSpec spec, [NotNullWhen(true)] out ICodeInfo? codeInfo, out ReadOnlyMemory extraCallData) + public static bool CreateInitCodeInfo(ReadOnlyMemory data, IReleaseSpec spec, [NotNullWhen(true)] out CodeInfo? codeInfo, out ReadOnlyMemory extraCallData) { extraCallData = default; if (spec.IsEofEnabled && data.Span.StartsWith(EofValidator.MAGIC)) diff --git a/src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs b/src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs index 959ed46ff4c3..1fb55fdaf67f 100644 --- a/src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs +++ b/src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs @@ -19,7 +19,7 @@ namespace Nethermind.Evm; public class CodeInfoRepository : ICodeInfoRepository { private static readonly CodeLruCache _codeCache = new(); - private readonly FrozenDictionary _localPrecompiles; + private readonly FrozenDictionary _localPrecompiles; private readonly IWorldState _worldState; public CodeInfoRepository(IWorldState worldState, IPrecompileProvider precompileProvider) @@ -28,7 +28,7 @@ public CodeInfoRepository(IWorldState worldState, IPrecompileProvider precompile _worldState = worldState; } - public ICodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IReleaseSpec vmSpec, out Address? delegationAddress) + public CodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IReleaseSpec vmSpec, out Address? delegationAddress) { delegationAddress = null; if (vmSpec.IsPrecompile(codeSource)) // _localPrecompiles have to have all precompiles @@ -36,7 +36,7 @@ public ICodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IR return _localPrecompiles[codeSource]; } - ICodeInfo cachedCodeInfo = InternalGetCachedCode(_worldState, codeSource, vmSpec); + CodeInfo cachedCodeInfo = InternalGetCachedCode(_worldState, codeSource, vmSpec); if (!cachedCodeInfo.IsEmpty && ICodeInfoRepository.TryGetDelegatedAddress(cachedCodeInfo.CodeSpan, out delegationAddress)) { @@ -47,21 +47,21 @@ public ICodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IR return cachedCodeInfo; } - private ICodeInfo InternalGetCachedCode(Address codeSource, IReleaseSpec vmSpec) + private CodeInfo InternalGetCachedCode(Address codeSource, IReleaseSpec vmSpec) { ref readonly ValueHash256 codeHash = ref _worldState.GetCodeHash(codeSource); return InternalGetCachedCode(_worldState, in codeHash, vmSpec); } - private static ICodeInfo InternalGetCachedCode(IReadOnlyStateProvider worldState, Address codeSource, IReleaseSpec vmSpec) + private static CodeInfo InternalGetCachedCode(IReadOnlyStateProvider worldState, Address codeSource, IReleaseSpec vmSpec) { ValueHash256 codeHash = worldState.GetCodeHash(codeSource); return InternalGetCachedCode(worldState, in codeHash, vmSpec); } - private static ICodeInfo InternalGetCachedCode(IReadOnlyStateProvider worldState, in ValueHash256 codeHash, IReleaseSpec vmSpec) + private static CodeInfo InternalGetCachedCode(IReadOnlyStateProvider worldState, in ValueHash256 codeHash, IReleaseSpec vmSpec) { - ICodeInfo? cachedCodeInfo = null; + CodeInfo? cachedCodeInfo = null; if (codeHash == Keccak.OfAnEmptyString.ValueHash256) { cachedCodeInfo = CodeInfo.Empty; @@ -101,7 +101,7 @@ public void InsertCode(ReadOnlyMemory code, Address codeOwner, IReleaseSpe if (_worldState.InsertCode(codeOwner, in codeHash, code, spec) && _codeCache.Get(in codeHash) is null) { - ICodeInfo codeInfo = CodeInfoFactory.CreateCodeInfo(code, spec, ValidationStrategy.ExtractHeader); + CodeInfo codeInfo = CodeInfoFactory.CreateCodeInfo(code, spec, ValidationStrategy.ExtractHeader); _codeCache.Set(in codeHash, codeInfo); } } @@ -138,7 +138,7 @@ public ValueHash256 GetExecutableCodeHash(Address address, IReleaseSpec spec) return Keccak.OfAnEmptyString.ValueHash256; } - ICodeInfo codeInfo = InternalGetCachedCode(_worldState, address, spec); + CodeInfo codeInfo = InternalGetCachedCode(_worldState, address, spec); return codeInfo.IsEmpty ? Keccak.OfAnEmptyString.ValueHash256 : codeHash; @@ -154,33 +154,33 @@ private sealed class CodeLruCache { private const int CacheCount = 16; private const int CacheMax = CacheCount - 1; - private readonly ClockCache[] _caches; + private readonly ClockCache[] _caches; public CodeLruCache() { - _caches = new ClockCache[CacheCount]; + _caches = new ClockCache[CacheCount]; for (int i = 0; i < _caches.Length; i++) { // Cache per nibble to reduce contention as TxPool is very parallel - _caches[i] = new ClockCache(MemoryAllowance.CodeCacheSize / CacheCount); + _caches[i] = new ClockCache(MemoryAllowance.CodeCacheSize / CacheCount); } } - public ICodeInfo? Get(in ValueHash256 codeHash) + public CodeInfo? Get(in ValueHash256 codeHash) { - ClockCache cache = _caches[GetCacheIndex(codeHash)]; + ClockCache cache = _caches[GetCacheIndex(codeHash)]; return cache.Get(codeHash); } - public bool Set(in ValueHash256 codeHash, ICodeInfo codeInfo) + public bool Set(in ValueHash256 codeHash, CodeInfo codeInfo) { - ClockCache cache = _caches[GetCacheIndex(codeHash)]; + ClockCache cache = _caches[GetCacheIndex(codeHash)]; return cache.Set(codeHash, codeInfo); } private static int GetCacheIndex(in ValueHash256 codeHash) => codeHash.Bytes[^1] & CacheMax; - public bool TryGet(in ValueHash256 codeHash, [NotNullWhen(true)] out ICodeInfo? codeInfo) + public bool TryGet(in ValueHash256 codeHash, [NotNullWhen(true)] out CodeInfo? codeInfo) { codeInfo = Get(in codeHash); return codeInfo is not null; diff --git a/src/Nethermind/Nethermind.Evm/EvmObjectFormat/EofCodeInfo.cs b/src/Nethermind/Nethermind.Evm/EvmObjectFormat/EofCodeInfo.cs index 140a3034b36d..82e5a8ee5b95 100644 --- a/src/Nethermind/Nethermind.Evm/EvmObjectFormat/EofCodeInfo.cs +++ b/src/Nethermind/Nethermind.Evm/EvmObjectFormat/EofCodeInfo.cs @@ -6,17 +6,18 @@ namespace Nethermind.Evm.CodeAnalysis; -public sealed class EofCodeInfo(in EofContainer container) : ICodeInfo +public sealed class EofCodeInfo : CodeInfo { - public EofContainer EofContainer { get; private set; } = container; - public ReadOnlyMemory Code => EofContainer.Container; - public int Version => EofContainer.Header.Version; - public bool IsEmpty => EofContainer.IsEmpty; + public EofCodeInfo(in EofContainer container) : base(container.Header.Version, container.Container) + { + EofContainer = container; + } + + public EofContainer EofContainer { get; private set; } public ReadOnlyMemory TypeSection => EofContainer.TypeSection; public ReadOnlyMemory CodeSection => EofContainer.CodeSection; public ReadOnlyMemory DataSection => EofContainer.DataSection; public ReadOnlyMemory ContainerSection => EofContainer.ContainerSection; - ReadOnlySpan ICodeInfo.CodeSpan => CodeSection.Span; public SectionHeader CodeSectionOffset(int sectionId) => EofContainer.Header.CodeSections[sectionId]; public SectionHeader? ContainerSectionOffset(int sectionId) => EofContainer.Header.ContainerSections.Value[sectionId]; diff --git a/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs b/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs index 0f396d82bd47..ff60de7b2723 100644 --- a/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs +++ b/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs @@ -22,7 +22,7 @@ public sealed class ExecutionEnvironment : IDisposable /// /// Parsed bytecode for the current call. /// - public ICodeInfo CodeInfo { get; private set; } = null!; + public CodeInfo CodeInfo { get; private set; } = null!; /// /// Currently executing account (in DELEGATECALL this will be equal to caller). @@ -65,7 +65,7 @@ private ExecutionEnvironment() { } /// Rents an ExecutionEnvironment from the pool and initializes it with the provided values. /// public static ExecutionEnvironment Rent( - ICodeInfo codeInfo, + CodeInfo codeInfo, Address executingAccount, Address caller, Address? codeSource, diff --git a/src/Nethermind/Nethermind.Evm/ICodeInfo.cs b/src/Nethermind/Nethermind.Evm/ICodeInfo.cs deleted file mode 100644 index 07156260530e..000000000000 --- a/src/Nethermind/Nethermind.Evm/ICodeInfo.cs +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System; -using Nethermind.Evm.Precompiles; - -namespace Nethermind.Evm.CodeAnalysis; - -/// -/// Represents common code information for EVM execution. -/// Implementations include , (EVM Object Format), -/// and for precompiled contracts. -/// -public interface ICodeInfo -{ - /// - /// Gets the version of the code format. - /// The default implementation returns 0, representing a legacy code format or non-EOF code. - /// - int Version => 0; - - /// - /// Indicates whether the code is empty or not. - /// - bool IsEmpty { get; } - - /// - /// Gets the raw machine code as a segment. - /// This is the primary code section from which the EVM executes instructions. - /// - ReadOnlyMemory Code { get; } - - /// - /// Indicates whether this code represents a precompiled contract. - /// By default, this returns false. - /// - bool IsPrecompile => false; - IPrecompile? Precompile => null; - - /// - /// Gets the code section. - /// By default, this returns the same contents as . - /// - ReadOnlyMemory CodeSection => Code; - ReadOnlySpan CodeSpan { get; } - - /// - /// Gets the data section, which is reserved for additional data segments in EOF. - /// By default, this returns an empty memory segment. - /// - ReadOnlyMemory DataSection => Memory.Empty; - - /// - /// Computes the offset to be added to the program counter when executing instructions. - /// By default, this returns 0, meaning no offset is applied. - /// - /// The program counter offset for this code format. - int PcOffset() => 0; - - /// - /// Validates whether a jump destination is permissible according to this code format. - /// By default, this returns false. - /// - /// The instruction index to validate. - /// true if the jump is valid; otherwise, false. - bool ValidateJump(int destination) => false; -} diff --git a/src/Nethermind/Nethermind.Evm/ICodeInfoRepository.cs b/src/Nethermind/Nethermind.Evm/ICodeInfoRepository.cs index 17e568d007e0..20cedaa8233d 100644 --- a/src/Nethermind/Nethermind.Evm/ICodeInfoRepository.cs +++ b/src/Nethermind/Nethermind.Evm/ICodeInfoRepository.cs @@ -11,7 +11,7 @@ namespace Nethermind.Evm; public interface ICodeInfoRepository { - ICodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IReleaseSpec vmSpec, out Address? delegationAddress); + CodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IReleaseSpec vmSpec, out Address? delegationAddress); ValueHash256 GetExecutableCodeHash(Address address, IReleaseSpec spec); void InsertCode(ReadOnlyMemory code, Address codeOwner, IReleaseSpec spec); void SetDelegation(Address codeSource, Address authority, IReleaseSpec spec); @@ -37,8 +37,8 @@ static bool TryGetDelegatedAddress(ReadOnlySpan code, [NotNullWhen(true)] public static class CodeInfoRepositoryExtensions { - public static ICodeInfo GetCachedCodeInfo(this ICodeInfoRepository codeInfoRepository, Address codeSource, IReleaseSpec vmSpec) + public static CodeInfo GetCachedCodeInfo(this ICodeInfoRepository codeInfoRepository, Address codeSource, IReleaseSpec vmSpec) => codeInfoRepository.GetCachedCodeInfo(codeSource, vmSpec, out _); - public static ICodeInfo GetCachedCodeInfo(this ICodeInfoRepository codeInfoRepository, Address codeSource, IReleaseSpec vmSpec, out Address? delegationAddress) + public static CodeInfo GetCachedCodeInfo(this ICodeInfoRepository codeInfoRepository, Address codeSource, IReleaseSpec vmSpec, out Address? delegationAddress) => codeInfoRepository.GetCachedCodeInfo(codeSource, true, vmSpec, out delegationAddress); } diff --git a/src/Nethermind/Nethermind.Evm/IOverridableCodeInfoRepository.cs b/src/Nethermind/Nethermind.Evm/IOverridableCodeInfoRepository.cs index 6cee9b50c462..5b9dd5dd3697 100644 --- a/src/Nethermind/Nethermind.Evm/IOverridableCodeInfoRepository.cs +++ b/src/Nethermind/Nethermind.Evm/IOverridableCodeInfoRepository.cs @@ -9,7 +9,7 @@ namespace Nethermind.Evm; public interface IOverridableCodeInfoRepository : ICodeInfoRepository { - void SetCodeOverride(IReleaseSpec vmSpec, Address key, ICodeInfo value); + void SetCodeOverride(IReleaseSpec vmSpec, Address key, CodeInfo value); void MovePrecompile(IReleaseSpec vmSpec, Address precompileAddr, Address targetAddr); void ResetOverrides(); void ResetPrecompileOverrides(); diff --git a/src/Nethermind/Nethermind.Evm/IPrecompileProvider.cs b/src/Nethermind/Nethermind.Evm/IPrecompileProvider.cs index d6654879331d..6e17d2e8c3d3 100644 --- a/src/Nethermind/Nethermind.Evm/IPrecompileProvider.cs +++ b/src/Nethermind/Nethermind.Evm/IPrecompileProvider.cs @@ -9,5 +9,5 @@ namespace Nethermind.Evm; public interface IPrecompileProvider { - public FrozenDictionary GetPrecompiles(); + public FrozenDictionary GetPrecompiles(); } diff --git a/src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Call.cs b/src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Call.cs index e802d92416fe..2728f87e21b2 100644 --- a/src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Call.cs +++ b/src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Call.cs @@ -177,7 +177,7 @@ public static EvmExceptionType InstructionCall( if (!TGasPolicy.UpdateMemoryCost(ref gas, in a, result, vm.VmState)) goto OutOfGas; - ICodeInfo codeInfo = vm.CodeInfoRepository + CodeInfo codeInfo = vm.CodeInfoRepository .GetCachedCodeInfo(address, followDelegation: false, spec, out _); // Get the external code from the repository. diff --git a/src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Create.cs b/src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Create.cs index 66f79084b2cb..d433f76793e7 100644 --- a/src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Create.cs +++ b/src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Create.cs @@ -200,7 +200,7 @@ public static EvmExceptionType InstructionCreate(Vir where TGasPolicy : struct, IGasPolicy where TTracingInst : struct, IFlag { - ICodeInfo codeInfo = vm.VmState.Env.CodeInfo; // Ensure the instruction is only valid for non-legacy (EOF) code. - if (codeInfo.Version == 0) + if (vm.VmState.Env.CodeInfo is not EofCodeInfo codeInfo) goto BadInstruction; // Deduct gas required for data loading. @@ -193,8 +192,7 @@ public static EvmExceptionType InstructionDataLoadN(Vi where TGasPolicy : struct, IGasPolicy where TTracingInst : struct, IFlag { - ICodeInfo codeInfo = vm.VmState.Env.CodeInfo; - if (codeInfo.Version == 0) + if (vm.VmState.Env.CodeInfo is not EofCodeInfo codeInfo) goto BadInstruction; if (!TGasPolicy.UpdateGas(ref gas, GasCostOf.DataLoadN)) @@ -225,8 +223,7 @@ public static EvmExceptionType InstructionDataSize(Vir where TGasPolicy : struct, IGasPolicy where TTracingInst : struct, IFlag { - ICodeInfo codeInfo = vm.VmState.Env.CodeInfo; - if (codeInfo.Version == 0) + if (vm.VmState.Env.CodeInfo is not EofCodeInfo codeInfo) goto BadInstruction; if (!TGasPolicy.UpdateGas(ref gas, GasCostOf.DataSize)) @@ -251,8 +248,7 @@ public static EvmExceptionType InstructionDataCopy(Vir where TGasPolicy : struct, IGasPolicy where TTracingInst : struct, IFlag { - ICodeInfo codeInfo = vm.VmState.Env.CodeInfo; - if (codeInfo.Version == 0) + if (vm.VmState.Env.CodeInfo is not EofCodeInfo codeInfo) goto BadInstruction; // Pop destination memory offset, data section offset, and size. @@ -303,8 +299,7 @@ public static EvmExceptionType InstructionDataCopy(Vir public static EvmExceptionType InstructionRelativeJump(VirtualMachine vm, ref EvmStack stack, ref TGasPolicy gas, ref int programCounter) where TGasPolicy : struct, IGasPolicy { - ICodeInfo codeInfo = vm.VmState.Env.CodeInfo; - if (codeInfo.Version == 0) + if (vm.VmState.Env.CodeInfo is not EofCodeInfo codeInfo) goto BadInstruction; if (!TGasPolicy.UpdateGas(ref gas, GasCostOf.RJump)) @@ -330,8 +325,7 @@ public static EvmExceptionType InstructionRelativeJump(VirtualMachin public static EvmExceptionType InstructionRelativeJumpIf(VirtualMachine vm, ref EvmStack stack, ref TGasPolicy gas, ref int programCounter) where TGasPolicy : struct, IGasPolicy { - ICodeInfo codeInfo = vm.VmState.Env.CodeInfo; - if (codeInfo.Version == 0) + if (vm.VmState.Env.CodeInfo is not EofCodeInfo codeInfo) goto BadInstruction; if (!TGasPolicy.UpdateGas(ref gas, GasCostOf.RJumpi)) @@ -365,8 +359,7 @@ public static EvmExceptionType InstructionRelativeJumpIf(VirtualMach public static EvmExceptionType InstructionJumpTable(VirtualMachine vm, ref EvmStack stack, ref TGasPolicy gas, ref int programCounter) where TGasPolicy : struct, IGasPolicy { - ICodeInfo codeInfo = vm.VmState.Env.CodeInfo; - if (codeInfo.Version == 0) + if (vm.VmState.Env.CodeInfo is not EofCodeInfo codeInfo) goto BadInstruction; if (!TGasPolicy.UpdateGas(ref gas, GasCostOf.RJumpv)) @@ -406,7 +399,7 @@ public static EvmExceptionType InstructionJumpTable(VirtualMachine(VirtualMachine vm, ref EvmStack stack, ref TGasPolicy gas, ref int programCounter) where TGasPolicy : struct, IGasPolicy { - ICodeInfo iCodeInfo = vm.VmState.Env.CodeInfo; + CodeInfo iCodeInfo = vm.VmState.Env.CodeInfo; if (iCodeInfo.Version == 0) goto BadInstruction; @@ -462,7 +455,7 @@ public static EvmExceptionType InstructionCallFunction(VirtualMachin public static EvmExceptionType InstructionReturnFunction(VirtualMachine vm, ref EvmStack stack, ref TGasPolicy gas, ref int programCounter) where TGasPolicy : struct, IGasPolicy { - ICodeInfo codeInfo = vm.VmState.Env.CodeInfo; + CodeInfo codeInfo = vm.VmState.Env.CodeInfo; if (codeInfo.Version == 0) goto BadInstruction; @@ -490,7 +483,7 @@ public static EvmExceptionType InstructionReturnFunction(VirtualMach public static EvmExceptionType InstructionJumpFunction(VirtualMachine vm, ref EvmStack stack, ref TGasPolicy gas, ref int programCounter) where TGasPolicy : struct, IGasPolicy { - ICodeInfo iCodeInfo = vm.VmState.Env.CodeInfo; + CodeInfo iCodeInfo = vm.VmState.Env.CodeInfo; if (iCodeInfo.Version == 0) goto BadInstruction; @@ -530,8 +523,7 @@ public static EvmExceptionType InstructionDupN(Virtual where TGasPolicy : struct, IGasPolicy where TTracingInst : struct, IFlag { - ICodeInfo codeInfo = vm.VmState.Env.CodeInfo; - if (codeInfo.Version == 0) + if (vm.VmState.Env.CodeInfo is not EofCodeInfo codeInfo) goto BadInstruction; if (!TGasPolicy.UpdateGas(ref gas, GasCostOf.Dupn)) @@ -561,8 +553,7 @@ public static EvmExceptionType InstructionSwapN(Virtua where TGasPolicy : struct, IGasPolicy where TTracingInst : struct, IFlag { - ICodeInfo codeInfo = vm.VmState.Env.CodeInfo; - if (codeInfo.Version == 0) + if (vm.VmState.Env.CodeInfo is not EofCodeInfo codeInfo) goto BadInstruction; if (!TGasPolicy.UpdateGas(ref gas, GasCostOf.Swapn)) @@ -591,8 +582,7 @@ public static EvmExceptionType InstructionExchange(Vir where TGasPolicy : struct, IGasPolicy where TTracingInst : struct, IFlag { - ICodeInfo codeInfo = vm.VmState.Env.CodeInfo; - if (codeInfo.Version == 0) + if (vm.VmState.Env.CodeInfo is not EofCodeInfo codeInfo) goto BadInstruction; if (!TGasPolicy.UpdateGas(ref gas, GasCostOf.Swapn)) @@ -742,7 +732,7 @@ public static EvmExceptionType InstructionEofCreate(Vi state.SubtractFromBalance(env.ExecutingAccount, value, spec); // Create new code info for the init code. - ICodeInfo codeInfo = CodeInfoFactory.CreateCodeInfo(initContainer, spec, ValidationStrategy.ExtractHeader); + CodeInfo codeInfo = CodeInfoFactory.CreateCodeInfo(initContainer, spec, ValidationStrategy.ExtractHeader); // 8. Prepare the callData from the caller’s memory slice. if (!vm.VmState.Memory.TryLoad(dataOffset, dataSize, out ReadOnlyMemory callData)) @@ -843,7 +833,7 @@ public static EvmExceptionType InstructionReturnDataLoad Code => Array.Empty(); - ReadOnlySpan ICodeInfo.CodeSpan => Code.Span; - public IPrecompile? Precompile { get; } = precompile; - - public bool IsPrecompile => true; - public bool IsEmpty => false; -} diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index e927b73bf0ec..2ae5c1892b50 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -614,7 +614,7 @@ private TransactionResult BuildExecutionEnvironment( { Address recipient = tx.GetRecipient(tx.IsContractCreation ? WorldState.GetNonce(tx.SenderAddress!) : 0); if (recipient is null) ThrowInvalidDataException("Recipient has not been resolved properly before tx execution"); - ICodeInfo? codeInfo; + CodeInfo? codeInfo; ReadOnlyMemory inputData = tx.IsMessageCall ? tx.Data : default; if (tx.IsContractCreation) { diff --git a/src/Nethermind/Nethermind.Evm/TransactionSubstate.cs b/src/Nethermind/Nethermind.Evm/TransactionSubstate.cs index f335e854c52e..624ac196f00a 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionSubstate.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionSubstate.cs @@ -52,7 +52,7 @@ public readonly ref struct TransactionSubstate public string? Error { get; } public string? SubstateError { get; } public EvmExceptionType EvmExceptionType { get; } - public (ICodeInfo DeployCode, ReadOnlyMemory Bytes) Output { get; } + public (CodeInfo DeployCode, ReadOnlyMemory Bytes) Output { get; } public bool ShouldRevert { get; } public long Refund { get; } public IToArrayCollection Logs => _logs ?? _emptyLogs; @@ -80,7 +80,7 @@ private TransactionSubstate(string errorCode) ShouldRevert = true; } - public TransactionSubstate((ICodeInfo eofDeployCode, ReadOnlyMemory bytes) output, + public TransactionSubstate((CodeInfo eofDeployCode, ReadOnlyMemory bytes) output, long refund, IHashSetEnumerableCollection
destroyList, IToArrayCollection logs, diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index 45611c2385ef..5a1e2773ae57 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -1215,7 +1215,7 @@ protected virtual unsafe CallResult RunByteCode( SectionIndex = VmState.FunctionIndex; // Retrieve the code information and create a read-only span of instructions. - ICodeInfo codeInfo = VmState.Env.CodeInfo; + CodeInfo codeInfo = VmState.Env.CodeInfo; ReadOnlySpan codeSection = GetInstructions(codeInfo); // Initialize the exception type to "None". @@ -1330,16 +1330,16 @@ protected virtual unsafe CallResult RunByteCode( debugger?.TryWait(ref _currentState, ref programCounter, ref gas, ref stack.Head); #endif // Process the return data based on its runtime type. - if (ReturnData is VmState state) + if (ReturnData is byte[] data) { - return new CallResult(state); + // Fall back to returning a CallResult with a byte array as the return data. + return new CallResult(null, data, null, codeInfo.Version); } - else if (ReturnData is EofCodeInfo eofCodeInfo) + else if (ReturnData is VmState state) { - return new CallResult(eofCodeInfo, ReturnDataBuffer, null, codeInfo.Version); + return new CallResult(state); } - // Fall back to returning a CallResult with a byte array as the return data. - return new CallResult(null, (byte[])ReturnData, null, codeInfo.Version); + return ReturnEof(codeInfo); Revert: // Return a CallResult indicating a revert. @@ -1355,7 +1355,7 @@ protected virtual unsafe CallResult RunByteCode( // Converts the code section bytes into a read-only span of instructions. // Lightest weight conversion as mostly just helpful when debugging to see what the opcodes are. - static ReadOnlySpan GetInstructions(ICodeInfo codeInfo) + static ReadOnlySpan GetInstructions(CodeInfo codeInfo) { ReadOnlySpan codeBytes = codeInfo.CodeSpan; return MemoryMarshal.CreateReadOnlySpan( @@ -1363,6 +1363,10 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(codeBytes)), codeBytes.Length); } + [MethodImpl(MethodImplOptions.NoInlining)] + CallResult ReturnEof(CodeInfo codeInfo) + => new(ReturnData as EofCodeInfo, ReturnDataBuffer, null, codeInfo.Version); + [DoesNotReturn] static void ThrowOperationCanceledException() => throw new OperationCanceledException("Cancellation Requested"); } diff --git a/src/Nethermind/Nethermind.State/OverridableEnv/OverridableCodeInfoRepository.cs b/src/Nethermind/Nethermind.State/OverridableEnv/OverridableCodeInfoRepository.cs index d8ac3c455f1d..7b1a1da5dd5a 100644 --- a/src/Nethermind/Nethermind.State/OverridableEnv/OverridableCodeInfoRepository.cs +++ b/src/Nethermind/Nethermind.State/OverridableEnv/OverridableCodeInfoRepository.cs @@ -15,10 +15,10 @@ namespace Nethermind.State.OverridableEnv; public class OverridableCodeInfoRepository(ICodeInfoRepository codeInfoRepository, IWorldState worldState) : IOverridableCodeInfoRepository { - private readonly Dictionary _codeOverrides = new(); - private readonly Dictionary _precompileOverrides = new(); + private readonly Dictionary _codeOverrides = new(); + private readonly Dictionary _precompileOverrides = new(); - public ICodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IReleaseSpec vmSpec, out Address? delegationAddress) + public CodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IReleaseSpec vmSpec, out Address? delegationAddress) { delegationAddress = null; if (_precompileOverrides.TryGetValue(codeSource, out var precompile)) return precompile.codeInfo; @@ -41,9 +41,9 @@ public void InsertCode(ReadOnlyMemory code, Address codeOwner, IReleaseSpe public void SetCodeOverride( IReleaseSpec vmSpec, Address key, - ICodeInfo value) + CodeInfo value) { - _codeOverrides[key] = (value, ValueKeccak.Compute(value.CodeSpan)); + _codeOverrides[key] = (value, ValueKeccak.Compute(value.Code.Span)); } public void MovePrecompile(IReleaseSpec vmSpec, Address precompileAddr, Address targetAddr) diff --git a/src/Nethermind/Nethermind.Test.Runner/StateTestTxTracer.cs b/src/Nethermind/Nethermind.Test.Runner/StateTestTxTracer.cs index f332f113489c..bc89ff38ecff 100644 --- a/src/Nethermind/Nethermind.Test.Runner/StateTestTxTracer.cs +++ b/src/Nethermind/Nethermind.Test.Runner/StateTestTxTracer.cs @@ -10,6 +10,7 @@ using Nethermind.Evm; using Nethermind.Evm.Tracing; using Nethermind.Evm.TransactionProcessing; +using Nethermind.Evm.CodeAnalysis; namespace Nethermind.Test.Runner; @@ -54,7 +55,7 @@ public void StartOperation(int pc, Instruction opcode, long gas, in ExecutionEnv { _gasAlreadySetForCurrentOp = false; _traceEntry = new StateTestTxTraceEntry(); - _traceEntry.Pc = pc + env.CodeInfo.PcOffset(); + _traceEntry.Pc = pc + (env.CodeInfo is EofCodeInfo eofCodeInfo ? eofCodeInfo.PcOffset() : 0); _traceEntry.Section = codeSection; _traceEntry.Operation = (byte)opcode; _traceEntry.OperationName = opcode.GetName();