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

Add block value to getPayload result #4884

Merged
merged 24 commits into from
Dec 5, 2022
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -77,6 +77,7 @@ public UserOperationTxTracer(
public bool IsTracingStorage => false;
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => true;
public bool IsTracingFees => false;

public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs,
Keccak? stateRoot = null)
Expand Down Expand Up @@ -330,5 +331,10 @@ private void AddToAccessedStorage(Address address, UInt256 index)

AccessedStorage.Add(address, new HashSet<UInt256> { index });
}

public void ReportFees(UInt256 fees, UInt256 burntFees)
{
throw new NotImplementedException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Nethermind.Blockchain;
using Nethermind.Blockchain.Find;
using Nethermind.Core;
using Nethermind.Core.Attributes;
using Nethermind.Core.Crypto;
using Nethermind.Db;
using Nethermind.Evm.Tracing;
using Nethermind.Evm.Tracing.GethStyle;
using Nethermind.Evm.Tracing.ParityStyle;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Generic;
Expand All @@ -24,6 +24,7 @@ public class TestAllTracerWithOutput : ITxTracer
public bool IsTracingStorage => true;
public bool IsTracingBlockHash => true;
public bool IsTracingAccess { get; set; } = true;
public bool IsTracingFees => true;

public byte[] ReturnValue { get; set; }

Expand Down Expand Up @@ -165,5 +166,9 @@ public void ReportExtraGasPressure(long extraGasPressure)
public void ReportAccess(IReadOnlySet<Address> accessedAddresses, IReadOnlySet<StorageCell> accessedStorageCells)
{
}

public void ReportFees(UInt256 fees, UInt256 burntFees)
{
}
}
}
246 changes: 246 additions & 0 deletions src/Nethermind/Nethermind.Evm.Test/TransactionProcessorFeeTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Threading;
using FluentAssertions;
using Nethermind.Core;
using Nethermind.Core.Extensions;
using Nethermind.Core.Test.Builders;
using Nethermind.Crypto;
using Nethermind.Db;
using Nethermind.Evm.Tracing;
using Nethermind.Evm.TransactionProcessing;
using Nethermind.Logging;
using Nethermind.Specs;
using Nethermind.Specs.Forks;
using Nethermind.Specs.Test;
using Nethermind.State;
using Nethermind.Trie.Pruning;
using NUnit.Framework;

namespace Nethermind.Evm.Test;

public class TransactionProcessorFeeTests
{
private TestSpecProvider _specProvider;
private IEthereumEcdsa _ethereumEcdsa;
private TransactionProcessor _transactionProcessor;
private IStateProvider _stateProvider;
private OverridableReleaseSpec _spec;

[SetUp]
public void Setup()
{
_spec = new(London.Instance);
_specProvider = new TestSpecProvider(_spec);

TrieStore trieStore = new(new MemDb(), LimboLogs.Instance);

_stateProvider = new StateProvider(trieStore, new MemDb(), LimboLogs.Instance);
_stateProvider.CreateAccount(TestItem.AddressA, 1.Ether());
_stateProvider.Commit(_specProvider.GenesisSpec);
_stateProvider.CommitTree(0);

StorageProvider storageProvider = new(trieStore, _stateProvider, LimboLogs.Instance);
VirtualMachine virtualMachine = new(TestBlockhashProvider.Instance, _specProvider, LimboLogs.Instance);
_transactionProcessor = new TransactionProcessor(_specProvider, _stateProvider, storageProvider, virtualMachine,
LimboLogs.Instance);
_ethereumEcdsa = new EthereumEcdsa(_specProvider.ChainId, LimboLogs.Instance);
}

[TestCase(true, true)]
[TestCase(false, true)]
[TestCase(true, false)]
[TestCase(false, false)]
public void Check_fees_with_fee_collector(bool isTransactionEip1559, bool withFeeCollector)
{
if (withFeeCollector)
{
_spec.Eip1559FeeCollector = TestItem.AddressC;
}

Transaction tx = Build.A.Transaction
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).WithGasPrice(10).WithMaxFeePerGas(10)
.WithType(isTransactionEip1559 ? TxType.EIP1559 : TxType.Legacy).WithGasLimit(21000).TestObject;
Block block = Build.A.Block.WithNumber(1)
.WithBeneficiary(TestItem.AddressB).WithBaseFeePerGas(1).WithTransactions(tx).WithGasLimit(21000)
.TestObject;

FeesTracer tracer = new();
CompositeBlockTracer compositeTracer = new();
compositeTracer.Add(tracer);
compositeTracer.Add(NullBlockTracer.Instance);

ExecuteAndTrace(block, compositeTracer);

tracer.Fees.Should().Be(189000);
tracer.BurntFees.Should().Be(21000);
}


[TestCase(false)]
[TestCase(true)]
public void Check_paid_fees_multiple_transactions(bool withFeeCollector)
{
if (withFeeCollector)
{
_spec.Eip1559FeeCollector = TestItem.AddressC;
}

Transaction tx1 = Build.A.Transaction
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).WithType(TxType.EIP1559)
.WithMaxFeePerGas(3).WithMaxPriorityFeePerGas(1).WithGasLimit(21000).TestObject;
Transaction tx2 = Build.A.Transaction.WithType(TxType.Legacy)
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).WithNonce(1)
.WithGasPrice(10).WithGasLimit(21000).TestObject;
Block block = Build.A.Block.WithNumber(0).WithBaseFeePerGas(2)
.WithBeneficiary(TestItem.AddressB).WithTransactions(tx1, tx2).WithGasLimit(42000).TestObject;

FeesTracer tracer = new();
ExecuteAndTrace(block, tracer);

// tx1: 1 * 21000
// tx2: (10 - 2) * 21000 = 168000
tracer.Fees.Should().Be(189000);

block.GasUsed.Should().Be(42000);
tracer.BurntFees.Should().Be(84000);
}


[Test]
public void Check_paid_fees_with_byte_code()
{
byte[] byteCode = Prepare.EvmCode
.CallWithValue(Address.Zero, 0, 1)
.PushData(1)
.PushData(1)
.Op(Instruction.SSTORE)
.PushData(0)
.PushData(1)
.Op(Instruction.SSTORE)
.Op(Instruction.STOP)
.Done;
Transaction tx1 = Build.A.Transaction
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).WithMaxFeePerGas(3).WithMaxPriorityFeePerGas(2)
.WithType(TxType.EIP1559).WithGasLimit(21000).TestObject;
Transaction tx2 = Build.A.Transaction
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).WithNonce(1).WithGasPrice(10)
.WithType(TxType.Legacy).WithGasLimit(21000).TestObject;
Transaction tx3 = Build.A.Transaction
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).WithNonce(2).WithMaxFeePerGas(2).WithMaxPriorityFeePerGas(1)
.WithType(TxType.EIP1559).WithCode(byteCode)
.WithGasLimit(60000).TestObject;
Block block = Build.A.Block.WithNumber(MainnetSpecProvider.LondonBlockNumber)
.WithBeneficiary(TestItem.AddressB).WithBaseFeePerGas(1).WithTransactions(tx1, tx2, tx3)
.WithGasLimit(102000).TestObject;

FeesTracer tracer = new();
ExecuteAndTrace(block, tracer);

// tx1: 2 * 21000
// tx2: (10 - 1) * 21000
// tx3: 1 * 60000
tracer.Fees.Should().Be(291000);

block.GasUsed.Should().Be(102000);
tracer.BurntFees.Should().Be(102000);
}

[TestCase(false)]
[TestCase(true)]
public void Should_stop_when_cancellation(bool withCancellation)
{
Transaction tx1 = Build.A.Transaction
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).WithType(TxType.EIP1559)
.WithMaxFeePerGas(3).WithMaxPriorityFeePerGas(1).WithGasLimit(21000).TestObject;
Transaction tx2 = Build.A.Transaction.WithType(TxType.Legacy)
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).WithNonce(1)
.WithGasPrice(10).WithGasLimit(21000).TestObject;
Block block = Build.A.Block.WithNumber(0).WithBaseFeePerGas(2)
.WithBeneficiary(TestItem.AddressB).WithTransactions(tx1, tx2).WithGasLimit(42000).TestObject;

FeesTracer feesTracer = new();

CancellationTokenSource source = new();
CancellationToken token = source.Token;

CancellationBlockTracer cancellationBlockTracer = new(feesTracer, token);

BlockReceiptsTracer blockTracer = new();
blockTracer.SetOtherTracer(cancellationBlockTracer);

blockTracer.StartNewBlockTrace(block);
{
var txTracer = blockTracer.StartNewTxTrace(tx1);
_transactionProcessor.Execute(tx1, block.Header, txTracer);
blockTracer.EndTxTrace();
}

if (withCancellation)
{
source.Cancel();
}

try
{
var txTracer = blockTracer.StartNewTxTrace(tx2);
_transactionProcessor.Execute(tx2, block.Header, txTracer);
blockTracer.EndTxTrace();
blockTracer.EndBlockTrace();
}
catch (OperationCanceledException) { }

if (withCancellation)
{
// tx1: 1 * 21000
feesTracer.Fees.Should().Be(21000);
feesTracer.BurntFees.Should().Be(42000);
}
else
{
// tx2: (10 - 2) * 21000 = 168000
feesTracer.Fees.Should().Be(189000);
feesTracer.BurntFees.Should().Be(84000);
}
}

[Test]
public void Check_fees_with_free_transaction()
{
Transaction tx1 = Build.A.Transaction
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).WithType(TxType.EIP1559)
.WithMaxFeePerGas(3).WithMaxPriorityFeePerGas(1).WithGasLimit(21000).TestObject;
Transaction tx2 = Build.A.Transaction
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).WithNonce(1).WithIsServiceTransaction(true)
.WithType(TxType.EIP1559).WithMaxFeePerGas(3)
.WithMaxPriorityFeePerGas(1).WithGasLimit(21000).TestObject;
Transaction tx3 = new SystemTransaction();
Block block = Build.A.Block.WithNumber(0).WithBaseFeePerGas(1)
.WithBeneficiary(TestItem.AddressB).WithTransactions(tx1, tx2, tx3).WithGasLimit(42000).TestObject;

FeesTracer tracer = new();
ExecuteAndTrace(block, tracer);

tracer.Fees.Should().Be(42000);

block.GasUsed.Should().Be(42000);
tracer.BurntFees.Should().Be(21000);
}

private void ExecuteAndTrace(Block block, IBlockTracer otherTracer)
{
BlockReceiptsTracer tracer = new();
tracer.SetOtherTracer(otherTracer);

tracer.StartNewBlockTrace(block);
foreach (Transaction tx in block.Transactions)
{
var txTracer = tracer.StartNewTxTrace(tx);
_transactionProcessor.Execute(tx, block.Header, txTracer);
tracer.EndTxTrace();
}
tracer.EndBlockTrace();
}
}
8 changes: 7 additions & 1 deletion src/Nethermind/Nethermind.Evm/Tracing/AccessTxTracer.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -30,6 +30,7 @@ public class AccessTxTracer : ITxTracer
public bool IsTracingStack => false;
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => true;
public bool IsTracingFees => false;

public AccessTxTracer(params Address[] addressesToOptimize)
{
Expand Down Expand Up @@ -212,6 +213,11 @@ public void ReportAccess(IReadOnlySet<Address> accessedAddresses, IReadOnlySet<S
AccessList = new AccessList(dictionary.ToDictionary(k => k.Key, v => (IReadOnlySet<UInt256>)v.Value));
}

public void ReportFees(UInt256 fees, UInt256 burntFees)
{
throw new NotImplementedException();
}

public long GasSpent { get; set; }
public AccessList? AccessList { get; private set; }
}
Expand Down
2 changes: 2 additions & 0 deletions src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public static AlwaysCancelTxTracer Instance
public bool IsTracingStorage => true;
public bool IsTracingBlockHash => true;
public bool IsTracingAccess => true;
public bool IsTracingFees => true;

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

Expand Down Expand Up @@ -93,5 +94,6 @@ public static AlwaysCancelTxTracer Instance
public void ReportRefund(long refund) => throw new OperationCanceledException(ErrorMessage);
public void ReportExtraGasPressure(long extraGasPressure) => throw new OperationCanceledException(ErrorMessage);
public void ReportAccess(IReadOnlySet<Address> accessedAddresses, IReadOnlySet<StorageCell> accessedStorageCells) => throw new OperationCanceledException(ErrorMessage);
public void ReportFees(UInt256 fees, UInt256 burntFees) => throw new OperationCanceledException(ErrorMessage);
}
}
9 changes: 9 additions & 0 deletions src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class BlockReceiptsTracer : IBlockTracer, ITxTracer, IJournal<int>

public bool IsTracingBlockHash => _currentTxTracer.IsTracingBlockHash;
public bool IsTracingAccess => _currentTxTracer.IsTracingAccess;
public bool IsTracingFees => _currentTxTracer.IsTracingFees;

private IBlockTracer _otherTracer = NullBlockTracer.Instance;

Expand Down Expand Up @@ -182,6 +183,14 @@ public void ReportBlockHash(Keccak blockHash) =>
public void SetOperationMemory(List<string> memoryTrace) =>
_currentTxTracer.SetOperationMemory(memoryTrace);

public void ReportFees(UInt256 fees, UInt256 burntFees)
{
if (_currentTxTracer.IsTracingFees)
{
_currentTxTracer.ReportFees(fees, burntFees);
deffrian marked this conversation as resolved.
Show resolved Hide resolved
}
}

private ITxTracer _currentTxTracer = NullTxTracer.Instance;
private int _currentIndex;
private readonly List<TxReceipt> _txReceipts = new();
Expand Down
6 changes: 6 additions & 0 deletions src/Nethermind/Nethermind.Evm/Tracing/CallOutputTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class CallOutputTracer : ITxTracer
public bool IsTracingStorage => false;
public bool IsTracingBlockHash => false;
public bool IsTracingAccess => false;
public bool IsTracingFees => false;

public byte[] ReturnValue { get; set; }

Expand Down Expand Up @@ -187,5 +188,10 @@ public void ReportAccess(IReadOnlySet<Address> accessedAddresses, IReadOnlySet<S
{
throw new NotImplementedException();
}

public void ReportFees(UInt256 fees, UInt256 burntFees)
{
throw new NotImplementedException();
}
}
}
Loading