Skip to content

Commit

Permalink
fix/Introduce Trace/NoValidation mode for transaction excecution (#3688)
Browse files Browse the repository at this point in the history
* Introduce Trace/NoValidation mode for transaction excecution

* fix

* Fix

* Added test for trace_replayBlockTransactions.

Co-authored-by: user <klaudia.jazgar@gmail.com>
  • Loading branch information
LukaszRozmej and kjazgar authored Dec 15, 2021
1 parent 4b4baa3 commit 71113ad
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,17 @@ public void ReportAction(long gas, UInt256 value, Address @from, Address to, Rea
PushAction(action);
}

private string GetCreateMethod(ExecutionType callType)
private string? GetCreateMethod(ExecutionType callType)
{
return callType == ExecutionType.Create ? "create" : "create2";
switch (callType)
{
case ExecutionType.Create:
return "create";
case ExecutionType.Create2:
return "create2";
default:
return null;
}
}

public void ReportSelfDestruct(Address address, UInt256 balance, Address refundAddress)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,10 @@ public interface ITransactionProcessor
/// Execute transaction, keep the state uncommitted
/// </summary>
void BuildUp(Transaction transaction, BlockHeader block, ITxTracer txTracer);

/// <summary>
/// Call transaction, no validations, commit state
/// </summary>
void Trace(Transaction transaction, BlockHeader block, ITxTracer txTracer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,19 @@ public ReadOnlyTransactionProcessor(ITransactionProcessor transactionProcessor,
_stateProvider.StateRoot = startState ?? throw new ArgumentException(nameof(startState));
}

public void Execute(Transaction transaction, BlockHeader block, ITxTracer txTracer)
{
public void Execute(Transaction transaction, BlockHeader block, ITxTracer txTracer) =>
_transactionProcessor.Execute(transaction, block, txTracer);
}


public void CallAndRestore(Transaction transaction, BlockHeader block, ITxTracer txTracer)
{
public void CallAndRestore(Transaction transaction, BlockHeader block, ITxTracer txTracer) =>
_transactionProcessor.CallAndRestore(transaction, block, txTracer);
}

public void BuildUp(Transaction transaction, BlockHeader block, ITxTracer txTracer)
{
public void BuildUp(Transaction transaction, BlockHeader block, ITxTracer txTracer) =>
_transactionProcessor.BuildUp(transaction, block, txTracer);
}

public void Trace(Transaction transaction, BlockHeader block, ITxTracer txTracer) =>
_transactionProcessor.Trace(transaction, block, txTracer);


public bool IsContractDeployed(Address address) => _stateProvider.IsContract(address);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.
//

using Nethermind.Core;
using Nethermind.Evm.Tracing;

namespace Nethermind.Evm.TransactionProcessing
{
public class TraceTransactionProcessorAdapter : ITransactionProcessorAdapter
{
private readonly ITransactionProcessor _transactionProcessor;

public TraceTransactionProcessorAdapter(ITransactionProcessor transactionProcessor)
{
_transactionProcessor = transactionProcessor;
}

public void Execute(Transaction transaction, BlockHeader block, ITxTracer txTracer) =>
_transactionProcessor.Trace(transaction, block, txTracer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,16 @@ private enum ExecutionOptions
/// Restore state after execution
/// </summary>
Restore = 2,

/// <summary>
/// Skip potential fail checks
/// </summary>
NoValidation = Commit | 4,

/// <summary>
/// Commit and later restore state, use for CallAndRestore
/// Commit and later restore state also skip validation, use for CallAndRestore
/// </summary>
CommitAndRestore = Commit | Restore
CommitAndRestore = Commit | Restore | NoValidation
}

public TransactionProcessor(
Expand Down Expand Up @@ -105,6 +110,11 @@ public void Execute(Transaction transaction, BlockHeader block, ITxTracer txTrac
{
Execute(transaction, block, txTracer, ExecutionOptions.Commit);
}

public void Trace(Transaction transaction, BlockHeader block, ITxTracer txTracer)
{
Execute(transaction, block, txTracer, ExecutionOptions.NoValidation);
}

private void QuickFail(Transaction tx, BlockHeader block, ITxTracer txTracer, bool eip658NotEnabled,
string? reason)
Expand Down Expand Up @@ -134,9 +144,10 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra
bool eip658NotEnabled = !_specProvider.GetSpec(block.Number).IsEip658Enabled;

// restore is CallAndRestore - previous call, we will restore state after the execution
bool restore = (executionOptions & ExecutionOptions.Restore) != ExecutionOptions.None;
bool restore = (executionOptions & ExecutionOptions.Restore) == ExecutionOptions.Restore;
bool noValidation = (executionOptions & ExecutionOptions.NoValidation) == ExecutionOptions.NoValidation;
// commit - is for standard execute, we will commit thee state after execution
bool commit = (executionOptions & ExecutionOptions.Commit) != ExecutionOptions.None || eip658NotEnabled;
bool commit = (executionOptions & ExecutionOptions.Commit) == ExecutionOptions.Commit || eip658NotEnabled;
//!commit - is for build up during block production, we won't commit state after each transaction to support rollbacks
//we commit only after all block is constructed
bool notSystemTransaction = !transaction.IsSystem();
Expand All @@ -150,7 +161,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra

UInt256 value = transaction.Value;

if (!transaction.TryCalculatePremiumPerGas(block.BaseFeePerGas, out UInt256 premiumPerGas) && !restore)
if (!transaction.TryCalculatePremiumPerGas(block.BaseFeePerGas, out UInt256 premiumPerGas) && !noValidation)
{
TraceLogInvalidTx(transaction, "MINER_PREMIUM_IS_NEGATIVE");
QuickFail(transaction, block, txTracer, eip658NotEnabled, "miner premium is negative");
Expand All @@ -174,7 +185,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra
return;
}

if (!restore && _stateProvider.IsInvalidContractSender(spec, caller))
if (!noValidation && _stateProvider.IsInvalidContractSender(spec, caller))
{
TraceLogInvalidTx(transaction, "SENDER_IS_CONTRACT");
QuickFail(transaction, block, txTracer, eip658NotEnabled, "sender has deployed code");
Expand All @@ -193,7 +204,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra
return;
}

if (!restore && gasLimit > block.GasLimit - block.GasUsed)
if (!noValidation && gasLimit > block.GasLimit - block.GasUsed)
{
TraceLogInvalidTx(transaction,
$"BLOCK_GAS_LIMIT_EXCEEDED {gasLimit} > {block.GasLimit} - {block.GasUsed}");
Expand All @@ -220,7 +231,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra
else
{
TraceLogInvalidTx(transaction, $"SENDER_ACCOUNT_DOES_NOT_EXIST {caller}");
if (!commit || restore || effectiveGasPrice == UInt256.Zero)
if (!commit || noValidation || effectiveGasPrice == UInt256.Zero)
{
deleteCallerAccount = !commit || restore;
_stateProvider.CreateAccount(caller, UInt256.Zero);
Expand All @@ -234,21 +245,21 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra
}
}

UInt256 senderReservedGasPayment = restore ? UInt256.Zero : (ulong)gasLimit * effectiveGasPrice;
UInt256 senderReservedGasPayment = noValidation ? UInt256.Zero : (ulong)gasLimit * effectiveGasPrice;

if (notSystemTransaction)
{
UInt256 senderBalance = _stateProvider.GetBalance(caller);
if (!restore && ((ulong)intrinsicGas * effectiveGasPrice + value > senderBalance ||
senderReservedGasPayment + value > senderBalance))
if (!noValidation && ((ulong)intrinsicGas * effectiveGasPrice + value > senderBalance ||
senderReservedGasPayment + value > senderBalance))
{
TraceLogInvalidTx(transaction,
$"INSUFFICIENT_SENDER_BALANCE: ({caller})_BALANCE = {senderBalance}");
QuickFail(transaction, block, txTracer, eip658NotEnabled, "insufficient sender balance");
return;
}

if (!restore && spec.IsEip1559Enabled && !transaction.IsServiceTransaction &&
if (!noValidation && spec.IsEip1559Enabled && !transaction.IsFree() &&
senderBalance < (UInt256)transaction.GasLimit * transaction.MaxFeePerGas + value)
{
TraceLogInvalidTx(transaction,
Expand Down Expand Up @@ -451,7 +462,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra
_stateProvider.Commit(spec, txTracer.IsTracingState ? txTracer : NullStateTracer.Instance);
}

if (!restore && notSystemTransaction)
if (!noValidation && notSystemTransaction)
{
block.GasUsed += spentGas;
}
Expand Down
Loading

1 comment on commit 71113ad

@Jircs1
Copy link

@Jircs1 Jircs1 commented on 71113ad Mar 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😁

Please sign in to comment.