Skip to content

Commit

Permalink
Reduce exceptions in Evm (#5727)
Browse files Browse the repository at this point in the history
* Reduce exceptions in Evm

* Less expensive call

* Couple others

* Still throw exception for precompile

* Feedback

* Add to DebugTracer

* StateTestTxTracer

* Use consts
  • Loading branch information
benaadams authored May 26, 2023
1 parent b997407 commit 8ab99ff
Show file tree
Hide file tree
Showing 22 changed files with 54 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public UserOperationTxTracer(
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => true;
public bool IsTracingFees => false;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs,
Keccak? stateRoot = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class TestAllTracerWithOutput : ITxTracer
public bool IsTracingBlockHash => true;
public bool IsTracingAccess { get; set; } = true;
public bool IsTracingFees => true;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public byte[] ReturnValue { get; set; }

Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm/Tracing/AccessTxTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class AccessTxTracer : ITxTracer
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => true;
public bool IsTracingFees => false;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public AccessTxTracer(params Address[] addressesToOptimize)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public static AlwaysCancelTxTracer Instance
public bool IsTracingBlockHash => true;
public bool IsTracingAccess => true;
public bool IsTracingFees => true;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Keccak stateRoot = null) => throw new OperationCanceledException(ErrorMessage);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class BlockReceiptsTracer : IBlockTracer, ITxTracer, IJournal<int>, ITxTr
public bool IsTracingBlockHash => _currentTxTracer.IsTracingBlockHash;
public bool IsTracingAccess => _currentTxTracer.IsTracingAccess;
public bool IsTracingFees => _currentTxTracer.IsTracingFees;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

private IBlockTracer _otherTracer = NullBlockTracer.Instance;

Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm/Tracing/CallOutputTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class CallOutputTracer : ITxTracer
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => false;
public bool IsTracingFees => false;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public byte[] ReturnValue { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class CancellationTxTracer : ITxTracer, ITxTracerWrapper
private readonly bool _isTracingBlockHash;
private readonly bool _isTracingBlockAccess;
private readonly bool _isTracingFees;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public ITxTracer InnerTracer => _innerTracer;

Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public CompositeTxTracer(IList<ITxTracer> txTracers)
public bool IsTracingBlockHash { get; }
public bool IsTracingAccess { get; }
public bool IsTracingFees { get; }
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public void ReportBalanceChange(Address address, UInt256? before, UInt256? after)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public DebugTracer(ITxTracer tracer)
public bool IsTracingState => ((IStateTracer)InnerTracer).IsTracingState;

public bool IsTracingStorage => ((IStorageTracer)InnerTracer).IsTracingStorage;

public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

internal Dictionary<(int depth, int pc), Func<EvmState, bool>> _breakPoints = new();
public bool IsBreakpoitnSet(int depth, int programCounter)
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm/Tracing/EstimateGasTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public EstimateGasTracer()
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => false;
public bool IsTracingFees => false;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public byte[] ReturnValue { get; set; }

Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm/Tracing/FeesTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class FeesTracer : IBlockTracer, ITxTracer
public bool IsTracingStorage => false;
public bool IsTracingReceipt => false;
public bool IsTracingFees => true;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public UInt256 Fees { get; private set; } = UInt256.Zero;
public UInt256 BurntFees { get; private set; } = UInt256.Zero;
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public OutOfGasTracer()
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => false;
public bool IsTracingFees => false;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public bool OutOfGas { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,17 @@ public GethLikeTxTracer(GethTraceOptions options)
bool IStateTracer.IsTracingState => false;
bool IStorageTracer.IsTracingStorage => false;
public bool IsTracingReceipt => true;
bool ITxTracer.IsTracingActions => false;
public bool IsTracingActions => false;
public bool IsTracingOpLevelStorage { get; }
public bool IsTracingMemory { get; }
bool ITxTracer.IsTracingInstructions => true;
public bool IsTracingInstructions => true;
public bool IsTracingRefunds => false;
public bool IsTracingCode => false;
public bool IsTracingStack { get; }
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => false;
public bool IsTracingFees => false;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Keccak? stateRoot = null)
{
Expand Down
2 changes: 2 additions & 0 deletions src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ public interface ITxTracer : IWorldStateTracer
/// </remarks>
bool IsTracingFees { get; }

bool IsTracing { get; }

/// <summary>
/// Transaction completed successfully
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ private NullTxTracer() { }
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => false;
public bool IsTracingFees => false;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Keccak? stateRoot = null)
=> throw new InvalidOperationException(ErrorMessage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public ParityLikeTxTracer(Block block, Transaction? tx, ParityTraceTypes parityT
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => false;
public bool IsTracingFees => false;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

private static string GetCallType(ExecutionType executionType)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public ProofTxTracer(bool treatSystemAccountDifferently)
public bool IsTracingState => true;
public bool IsTracingStorage => true;
public bool IsTracingFees => false;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;

public void ReportActionEnd(long gas, Address deploymentAddress, ReadOnlyMemory<byte> deployedCode)
{
Expand Down
30 changes: 19 additions & 11 deletions src/Nethermind/Nethermind.Evm/TransactionSubstate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Numerics;
using Nethermind.Core;
using Nethermind.Core.Extensions;
using Nethermind.Int256;

namespace Nethermind.Evm
{
Expand All @@ -26,45 +27,52 @@ public TransactionSubstate(EvmExceptionType exceptionType, bool isTracerConnecte
ShouldRevert = false;
}

public TransactionSubstate(
public unsafe TransactionSubstate(
ReadOnlyMemory<byte> output,
long refund,
IReadOnlyCollection<Address> destroyList,
IReadOnlyCollection<LogEntry> logs,
bool shouldRevert,
bool isTracerConnected)
{
const int revertPrefix = 4;

Output = output;
Refund = refund;
DestroyList = destroyList;
Logs = logs;
ShouldRevert = shouldRevert;
if (ShouldRevert)
{
// TODO: is this invoked even if there is no tracer? why would we construct error messages then?
Error = Revert;
if (isTracerConnected)
{
if (Output.Length > 0)
{
try
{
BigInteger start = Output.Span.Slice(4, 32).ToUnsignedBigInteger();
BigInteger length = Output.Slice((int)start + 4, 32).Span.ToUnsignedBigInteger();
Error = string.Concat("Reverted ",
Output.Slice((int)start + 32 + 4, (int)length).ToArray().ToHexString(true));
}
catch (Exception)
ReadOnlySpan<byte> span = Output.Span;
if (span.Length >= sizeof(UInt256) * 2 + revertPrefix)
{
try
{
Error = string.Concat("Reverted ", Output.ToArray().ToHexString(true));
int start = (int)(new UInt256(span.Slice(revertPrefix, sizeof(UInt256)), isBigEndian: true));
if (start + revertPrefix + sizeof(UInt256) <= span.Length)
{
int length = (int)new UInt256(span.Slice(start + revertPrefix, sizeof(UInt256)), isBigEndian: true);
if (checked(start + revertPrefix + sizeof(UInt256) + length) <= span.Length)
{
Error = string.Concat("Reverted ",
span.Slice(start + sizeof(UInt256) + revertPrefix, length).ToHexString(true));
return;
}
}
}
catch
{
// ignore
}
}

Error = string.Concat("Reverted ", span.ToHexString(true));
}
}
}
Expand Down
27 changes: 7 additions & 20 deletions src/Nethermind/Nethermind.Evm/VirtualMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public TransactionSubstate Run(EvmState state, IWorldState worldState, ITxTracer

if (currentState.IsTopLevel)
{
return new TransactionSubstate(callResult.ExceptionType, _txTracer != NullTxTracer.Instance);
return new TransactionSubstate(callResult.ExceptionType, _txTracer.IsTracing);
}

previousCallResult = StatusCode.FailureBytes;
Expand Down Expand Up @@ -231,7 +231,7 @@ public TransactionSubstate Run(EvmState state, IWorldState worldState, ITxTracer
(IReadOnlyCollection<Address>)currentState.DestroyList,
(IReadOnlyCollection<LogEntry>)currentState.Logs,
callResult.ShouldRevert,
_txTracer != NullTxTracer.Instance);
isTracerConnected: _txTracer.IsTracing);
}

Address callCodeOwner = currentState.Env.ExecutingAccount;
Expand Down Expand Up @@ -348,7 +348,7 @@ public TransactionSubstate Run(EvmState state, IWorldState worldState, ITxTracer

if (currentState.IsTopLevel)
{
return new TransactionSubstate(ex is OverflowException ? EvmExceptionType.Other : (ex as EvmException).ExceptionType, _txTracer != NullTxTracer.Instance);
return new TransactionSubstate(ex is OverflowException ? EvmExceptionType.Other : (ex as EvmException).ExceptionType, _txTracer.IsTracing);
}

previousCallResult = StatusCode.FailureBytes;
Expand Down Expand Up @@ -564,14 +564,7 @@ private CallResult ExecutePrecompile(EvmState state, IReleaseSpec spec)
_parityTouchBugAccount.ShouldDelete = true;
}

//if(!UpdateGas(dataGasCost, ref gasAvailable)) return CallResult.Exception;
if (!UpdateGas(baseGasCost, ref gasAvailable))
{
Metrics.EvmExceptions++;
throw new OutOfGasException();
}

if (!UpdateGas(dataGasCost, ref gasAvailable))
if (!UpdateGas(checked(baseGasCost + dataGasCost), ref gasAvailable))
{
Metrics.EvmExceptions++;
throw new OutOfGasException();
Expand Down Expand Up @@ -656,7 +649,9 @@ static void UpdateCurrentState(EvmState state, int pc, long gas, int stackHead)
UInt256 localPreviousDest = previousCallOutputDestination;
if (!UpdateMemoryCost(vmState, ref gasAvailable, in localPreviousDest, (ulong)previousCallOutput.Length))
{
ThrowStackOverflowException();
// Never ran any instructions, so nothing to trace (or mark as end of trace)
traceOpcodes = false;
goto OutOfGas;
}

vmState.Memory.Save(in localPreviousDest, previousCallOutput);
Expand Down Expand Up @@ -2512,14 +2507,6 @@ static void UpdateCurrentState(EvmState state, int pc, long gas, int stackHead)
AccessViolation:
if (traceOpcodes) EndInstructionTraceError(gasAvailable, EvmExceptionType.AccessViolation);
return CallResult.AccessViolationException;

[DoesNotReturn]
[StackTraceHidden]
static void ThrowStackOverflowException()
{
Metrics.EvmExceptions++;
throw new OutOfGasException();
}
}

static bool UpdateMemoryCost(EvmState vmState, ref long gasAvailable, in UInt256 position, in UInt256 length)
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Mev/BeneficiaryTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public void EndBlockTrace() { }
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => false;
public bool IsTracingFees => false;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;
public void ReportReward(Address author, string rewardType, UInt256 rewardValue) { }
public void ReportCodeChange(Address address, byte[]? before, byte[]? after) { }
public void ReportNonceChange(Address address, UInt256? before, UInt256? after) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ public BundleTxTracer(Address beneficiary, Transaction? transaction, int index)
public bool IsTracingStorage => false;
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => false;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;
public long GasSpent { get; set; }
public UInt256? BeneficiaryBalanceBefore { get; private set; }
public UInt256? BeneficiaryBalanceAfter { get; private set; }
Expand Down
10 changes: 6 additions & 4 deletions src/Nethermind/Nethermind.State.Test.Runner/StateTestTxTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,21 @@ public class StateTestTxTracer : ITxTracer
private bool _gasAlreadySetForCurrentOp;

public bool IsTracingReceipt => true;
bool ITxTracer.IsTracingActions => false;
public bool IsTracingActions => false;
public bool IsTracingOpLevelStorage => true;
public bool IsTracingMemory => true;
public bool IsTracingDetailedMemory { get; set; } = true;
bool ITxTracer.IsTracingInstructions => true;
public bool IsTracingInstructions => true;
public bool IsTracingRefunds { get; } = false;
public bool IsTracingCode => false;
public bool IsTracingStack { get; set; } = true;
bool IStateTracer.IsTracingState => false;
bool IStorageTracer.IsTracingStorage => false;
public bool IsTracingState => false;
public bool IsTracingStorage => false;
public bool IsTracingBlockHash { get; } = false;
public bool IsTracingAccess { get; } = false;
public bool IsTracingFees => false;
public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees;


public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Keccak stateRoot = null)
{
Expand Down

0 comments on commit 8ab99ff

Please sign in to comment.