Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix remaining EOF validation issues #7556

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Nethermind/Ethereum.Test.Base/EofTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
// SPDX-License-Identifier: LGPL-3.0-only

using Ethereum.Test.Base.Interfaces;
using System.Collections.Generic;
using System.Numerics;
using Nethermind.Evm.EvmObjectFormat;

namespace Ethereum.Test.Base;
public class Result
Expand All @@ -16,6 +15,7 @@ public class Result
public class VectorTest
{
public byte[] Code { get; set; }
public ValidationStrategy ContainerKind { get; set; }
}

public class EofTest : IEthereumTest
Expand Down
3 changes: 2 additions & 1 deletion src/Nethermind/Ethereum.Test.Base/EofTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ protected bool RunTest(EofTest test, ITxTracer txTracer)

var vector = test.Vector;
var code = vector.Code;
var strategy = vector.ContainerKind;
var fork = test.Result.Fork switch
{
"Prague" => Nethermind.Specs.Forks.Prague.Instance,
Expand All @@ -68,7 +69,7 @@ protected bool RunTest(EofTest test, ITxTracer txTracer)
_ => throw new NotSupportedException($"Fork {test.Result.Fork} is not supported")
};

bool result = CodeDepositHandler.IsValidWithEofRules(fork, code, 1);
bool result = CodeDepositHandler.IsValidWithEofRules(fork, code, 1, strategy);
return result;
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
using Nethermind.Crypto;
using Nethermind.Evm.EvmObjectFormat;
using Nethermind.Int256;
using Nethermind.Serialization.Json;
using Nethermind.Serialization.Rlp;
Expand Down Expand Up @@ -309,6 +310,11 @@ public static IEnumerable<EofTest> ConvertToEofTests(string json)
VectorTestJson vectorJson = pair.Value;
VectorTest vector = new();
vector.Code = Bytes.FromHexString(vectorJson.Code);
vector.ContainerKind =
("INITCODE".Equals(vectorJson.ContainerKind)
? ValidationStrategy.ValidateInitcodeMode
: ValidationStrategy.ValidateRuntimeMode)
| ValidationStrategy.ValidateFullBody;

foreach (var result in vectorJson.Results)
{
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Ethereum.Test.Base/VectorTestJson.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ namespace Ethereum.Test.Base;
public class VectorTestJson
{
public string Code { get; set; }
public string ContainerKind { get; set; }
public Dictionary<string, TestResultJson> Results { get; set; }
}
33 changes: 24 additions & 9 deletions src/Nethermind/Nethermind.Evm/EvmObjectFormat/Handlers/EofV1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -440,11 +440,7 @@ private bool ValidateContainer(EofContainer eofContainer, ValidationStrategy val

if (validationStrategy.HasFlag(ValidationStrategy.Validate))
{
// Clear the Initcode flag for subcontainer
ValidationStrategy subContainerValidation = validationStrategy & ~ValidationStrategy.ValidateInitcodeMode;
// Set the Runtime flag for subcontainer
subContainerValidation |= ValidationStrategy.ValidateRuntimeMode;
containers.Enqueue((new EofContainer(subsection, header.Value), subContainerValidation));
containers.Enqueue((new EofContainer(subsection, header.Value), worklet.Strategy));
}
}
else
Expand Down Expand Up @@ -637,6 +633,7 @@ private bool ValidateInstructions(EofContainer eofContainer, int sectionId, Vali

ReadOnlySpan<byte> currentTypeSection = eofContainer.TypeSections[sectionId].Span;
var isCurrentSectionNonReturning = currentTypeSection[OUTPUTS_OFFSET] == 0x80;
bool hasRequiredSectionExit = isCurrentSectionNonReturning;

int position;
Instruction opcode = Instruction.STOP;
Expand Down Expand Up @@ -710,7 +707,7 @@ private bool ValidateInstructions(EofContainer eofContainer, int sectionId, Vali
return false;
}

containersWorklist.Enqueue(runtimeContainerId + 1, ValidationStrategy.ValidateRuntimeMode);
containersWorklist.Enqueue(runtimeContainerId + 1, ValidationStrategy.ValidateRuntimeMode | ValidationStrategy.ValidateFullBody);

BitmapHelper.HandleNumbits(EofValidator.ONE_BYTE_LENGTH, invalidJumpDestinations, ref nextPosition);
}
Expand All @@ -736,6 +733,7 @@ private bool ValidateInstructions(EofContainer eofContainer, int sectionId, Vali
}
else if (opcode is Instruction.JUMPF)
{
hasRequiredSectionExit = true;
if (nextPosition + EofValidator.TWO_BYTE_LENGTH > code.Length)
{
if (Logger.IsTrace) Logger.Trace($"EOF: Eof{VERSION}, {Instruction.JUMPF} Argument underflow");
Expand All @@ -762,6 +760,12 @@ private bool ValidateInstructions(EofContainer eofContainer, int sectionId, Vali
return false;
}

if (isCurrentSectionNonReturning && !isTargetSectionNonReturning)
{
if (Logger.IsTrace) Logger.Trace($"EOF: Eof{VERSION}, {Instruction.JUMPF} from non-returning must target non-returning");
return false;
}

sectionsWorklist.Enqueue(targetSectionId, strategy);
BitmapHelper.HandleNumbits(EofValidator.TWO_BYTE_LENGTH, invalidJumpDestinations, ref nextPosition);
}
Expand Down Expand Up @@ -839,10 +843,15 @@ private bool ValidateInstructions(EofContainer eofContainer, int sectionId, Vali
sectionsWorklist.Enqueue(targetSectionId, strategy);
BitmapHelper.HandleNumbits(EofValidator.TWO_BYTE_LENGTH, invalidJumpDestinations, ref nextPosition);
}
else if (opcode is Instruction.RETF && isCurrentSectionNonReturning)
else if (opcode is Instruction.RETF)
{
if (Logger.IsTrace) Logger.Trace($"EOF: Eof{VERSION}, non returning sections are not allowed to use opcode {Instruction.RETF}");
return false;
hasRequiredSectionExit = true;
if (isCurrentSectionNonReturning)
{
if (Logger.IsTrace)
Logger.Trace($"EOF: Eof{VERSION}, non returning sections are not allowed to use opcode {Instruction.RETF}");
return false;
}
}
else if (opcode is Instruction.DATALOADN)
{
Expand Down Expand Up @@ -913,6 +922,12 @@ private bool ValidateInstructions(EofContainer eofContainer, int sectionId, Vali
return false;
}

if (!hasRequiredSectionExit)
{
if (Logger.IsTrace) Logger.Trace($"EOF: Eof{VERSION}, Code section {sectionId} is returning and does not have a RETF or JUMPF");
return false;
}

var result = BitmapHelper.CheckCollision(invalidJumpDestinations, jumpDestinations);
if (result)
{
Expand Down