Skip to content

Commit 1320ca3

Browse files
Marchhilltanishqjasoria
authored andcommitted
Fix/unspent gas 7623 master (#8017)
Co-authored-by: Tanishq Jasoria <[email protected]>
1 parent 34da23e commit 1320ca3

File tree

2 files changed

+104
-2
lines changed

2 files changed

+104
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
2+
// SPDX-License-Identifier: LGPL-3.0-only
3+
4+
using Grpc.Core;
5+
using Nethermind.Core;
6+
using Nethermind.Core.Extensions;
7+
using Nethermind.Core.Specs;
8+
using Nethermind.Core.Test.Builders;
9+
using Nethermind.Crypto;
10+
using Nethermind.Db;
11+
using Nethermind.Evm.Tracing;
12+
using Nethermind.Evm.TransactionProcessing;
13+
using Nethermind.Facade;
14+
using Nethermind.Int256;
15+
using Nethermind.Logging;
16+
using Nethermind.Specs;
17+
using Nethermind.Specs.Forks;
18+
using Nethermind.State;
19+
using Nethermind.Trie.Pruning;
20+
using NUnit.Framework;
21+
22+
namespace Nethermind.Evm.Test;
23+
24+
public class TransactionProcessorEip7623Tests
25+
{
26+
private ISpecProvider _specProvider;
27+
private IEthereumEcdsa _ethereumEcdsa;
28+
private TransactionProcessor _transactionProcessor;
29+
private IWorldState _stateProvider;
30+
31+
[SetUp]
32+
public void Setup()
33+
{
34+
MemDb stateDb = new();
35+
_specProvider = new TestSpecProvider(Prague.Instance);
36+
TrieStore trieStore = new(stateDb, LimboLogs.Instance);
37+
_stateProvider = new WorldState(trieStore, new MemDb(), LimboLogs.Instance);
38+
CodeInfoRepository codeInfoRepository = new();
39+
VirtualMachine virtualMachine = new(new TestBlockhashProvider(_specProvider), _specProvider, codeInfoRepository, LimboLogs.Instance);
40+
_transactionProcessor = new TransactionProcessor(_specProvider, _stateProvider, virtualMachine, codeInfoRepository, LimboLogs.Instance);
41+
_ethereumEcdsa = new EthereumEcdsa(_specProvider.ChainId);
42+
}
43+
44+
[TestCase(21006, true, TestName = "GasLimit=IntrinsicGas")]
45+
[TestCase(21010, false, TestName = "GasLimit=FloorGas")]
46+
47+
public void transaction_validation_intrinsic_below_floor(long gasLimit, bool isFail)
48+
{
49+
_stateProvider.CreateAccount(TestItem.AddressA, 1.Ether());
50+
_stateProvider.Commit(_specProvider.GenesisSpec);
51+
_stateProvider.CommitTree(0);
52+
53+
Transaction tx = Build.A.Transaction
54+
.WithData([0])
55+
.WithGasPrice(1)
56+
.WithMaxFeePerGas(1)
57+
.WithTo(TestItem.AddressB)
58+
.WithValue(100.GWei())
59+
.WithGasLimit(gasLimit)
60+
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA)
61+
.TestObject;
62+
63+
Block block = Build.A.Block.WithNumber(long.MaxValue)
64+
.WithTimestamp(MainnetSpecProvider.PragueBlockTimestamp)
65+
.WithTransactions(tx)
66+
.WithGasLimit(10000000).TestObject;
67+
68+
TransactionResult result = _transactionProcessor.Execute(tx, block.Header, NullTxTracer.Instance);
69+
Assert.That(result.Fail, Is.EqualTo(isFail));
70+
}
71+
72+
[Test]
73+
public void balance_validation_intrinsic_below_floor()
74+
{
75+
_stateProvider.CreateAccount(TestItem.AddressA, 1.Ether());
76+
_stateProvider.Commit(_specProvider.GenesisSpec);
77+
_stateProvider.CommitTree(0);
78+
79+
Transaction tx = Build.A.Transaction
80+
.WithData([0])
81+
.WithGasPrice(1)
82+
.WithMaxFeePerGas(1)
83+
.WithTo(TestItem.AddressB)
84+
.WithValue(100.GWei())
85+
.WithGasLimit(21010)
86+
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA)
87+
.TestObject;
88+
89+
Block block = Build.A.Block.WithNumber(long.MaxValue)
90+
.WithTimestamp(MainnetSpecProvider.PragueBlockTimestamp)
91+
.WithTransactions(tx)
92+
.WithGasLimit(10000000).TestObject;
93+
94+
_transactionProcessor.Execute(tx, block.Header, NullTxTracer.Instance);
95+
96+
UInt256 balance = _stateProvider.GetBalance(TestItem.AddressA);
97+
Assert.That(balance, Is.EqualTo(1.Ether() - 100.GWei() - 21010));
98+
}
99+
}

src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs

+5-2
Original file line numberDiff line numberDiff line change
@@ -763,17 +763,20 @@ protected virtual GasConsumed Refund(Transaction tx, BlockHeader header, IReleas
763763
spentGas -= unspentGas;
764764
operationGas -= unspentGas;
765765
spentGas = Math.Max(spentGas, floorGas);
766+
// As per eip-7623, the spent gas is updated to the maximum of the actual gas used or the floor gas,
767+
// now we need to recalculate the unspent gas that should be refunded.
768+
var unspentGasRefund = tx.GasLimit - spentGas;
766769

767770
long totalToRefund = codeInsertRefund;
768771
if (!substate.ShouldRevert)
769772
totalToRefund += substate.Refund + substate.DestroyList.Count * RefundOf.Destroy(spec.IsEip3529Enabled);
770773
long actualRefund = RefundHelper.CalculateClaimableRefund(spentGas, totalToRefund, spec);
771774

772775
if (Logger.IsTrace)
773-
Logger.Trace("Refunding unused gas of " + unspentGas + " and refund of " + actualRefund);
776+
Logger.Trace("Refunding unused gas of " + unspentGasRefund + " and refund of " + actualRefund);
774777
// If noValidation we didn't charge for gas, so do not refund
775778
if (!opts.HasFlag(ExecutionOptions.SkipValidation))
776-
WorldState.AddToBalance(tx.SenderAddress!, (ulong)(unspentGas + actualRefund) * gasPrice, spec);
779+
WorldState.AddToBalance(tx.SenderAddress!, (ulong)(unspentGasRefund + actualRefund) * gasPrice, spec);
777780
spentGas -= actualRefund;
778781
operationGas -= actualRefund;
779782
}

0 commit comments

Comments
 (0)