@@ -17,15 +17,21 @@ package core_test
1717
1818import (
1919 "fmt"
20+ "math/big"
2021 "testing"
2122
23+ "github.com/google/go-cmp/cmp"
24+ "github.com/holiman/uint256"
2225 "github.com/stretchr/testify/require"
2326
2427 "github.com/ava-labs/libevm/common"
2528 "github.com/ava-labs/libevm/core"
29+ "github.com/ava-labs/libevm/core/types"
30+ "github.com/ava-labs/libevm/crypto"
2631 "github.com/ava-labs/libevm/libevm"
2732 "github.com/ava-labs/libevm/libevm/ethtest"
2833 "github.com/ava-labs/libevm/libevm/hookstest"
34+ "github.com/ava-labs/libevm/params"
2935)
3036
3137func TestCanExecuteTransaction (t * testing.T ) {
@@ -54,3 +60,106 @@ func TestCanExecuteTransaction(t *testing.T) {
5460 _ , err := core .ApplyMessage (evm , msg , new (core.GasPool ).AddGas (30e6 ))
5561 require .EqualError (t , err , makeErr (msg .From , msg .To , value ).Error ())
5662}
63+
64+ func TestMinimumGasConsumption (t * testing.T ) {
65+ // All transactions will be basic transfers so consume [params.TxGas] by
66+ // default.
67+ tests := []struct {
68+ name string
69+ gasLimit , minConsumption uint64
70+ wantUsed uint64
71+ }{
72+ {
73+ name : "consume_extra" ,
74+ gasLimit : 1e6 ,
75+ minConsumption : 5e5 ,
76+ wantUsed : 5e5 ,
77+ },
78+ {
79+ name : "consume_extra" ,
80+ gasLimit : 1e6 ,
81+ minConsumption : 4e5 ,
82+ wantUsed : 4e5 ,
83+ },
84+ {
85+ name : "no_extra_consumption" ,
86+ gasLimit : 50_000 ,
87+ minConsumption : params .TxGas - 1 ,
88+ wantUsed : params .TxGas ,
89+ },
90+ {
91+ name : "zero_min" ,
92+ gasLimit : 50_000 ,
93+ minConsumption : 0 ,
94+ wantUsed : params .TxGas ,
95+ },
96+ {
97+ name : "consume_extra_by_one" ,
98+ gasLimit : 1e6 ,
99+ minConsumption : params .TxGas + 1 ,
100+ wantUsed : params .TxGas + 1 ,
101+ },
102+ {
103+ name : "min_capped_at_limit" ,
104+ gasLimit : 1e6 ,
105+ minConsumption : 2e6 ,
106+ wantUsed : 1e6 ,
107+ },
108+ }
109+
110+ const gasPrice = params .Wei
111+
112+ for _ , tt := range tests {
113+ t .Run (tt .name , func (t * testing.T ) {
114+ hooks := & hookstest.Stub {
115+ MinimumGasConsumptionFn : func (limit uint64 ) uint64 {
116+ require .Equal (t , limit , tt .gasLimit )
117+ return tt .minConsumption
118+ },
119+ }
120+ hooks .Register (t )
121+
122+ key , err := crypto .GenerateKey ()
123+ require .NoError (t , err , "libevm/crypto.GenerateKey()" )
124+
125+ stateDB , evm := ethtest .NewZeroEVM (t )
126+ signer := types .LatestSigner (evm .ChainConfig ())
127+ tx := types .MustSignNewTx (
128+ key , signer ,
129+ & types.LegacyTx {
130+ GasPrice : big .NewInt (gasPrice ),
131+ Gas : tt .gasLimit ,
132+ To : & common.Address {},
133+ Value : big .NewInt (0 ),
134+ },
135+ )
136+ msg , err := core .TransactionToMessage (tx , signer , big .NewInt (gasPrice ))
137+ require .NoError (t , err , "core.TransactionToMessage(types.MustSignNewTx(...))" )
138+
139+ const startingBalance = 10 * params .Ether
140+ stateDB .SetNonce (msg .From , 0 )
141+ stateDB .SetBalance (msg .From , uint256 .NewInt (startingBalance ))
142+
143+ gotPool := core .GasPool (1e9 ) // modified when passed as pointer
144+ wantPool := gotPool - core .GasPool (tt .wantUsed )
145+
146+ got , err := core .ApplyMessage (evm , msg , & gotPool )
147+ require .NoError (t , err , "core.ApplyMessage()" )
148+
149+ want := & core.ExecutionResult {
150+ UsedGas : tt .wantUsed ,
151+ }
152+ if diff := cmp .Diff (want , got ); diff != "" {
153+ t .Errorf ("core.ApplyMessage(...) diff (-want +got):\n %s" , diff )
154+ }
155+ if gotPool != wantPool {
156+ t .Errorf ("After core.ApplyMessage(..., *%T); got %[1]T = %[1]d; want %d" , gotPool , wantPool )
157+ }
158+
159+ wantBalance := startingBalance - tt .wantUsed * gasPrice
160+ if got := stateDB .GetBalance (msg .From ); ! got .IsUint64 () || got .Uint64 () != wantBalance {
161+ t .Errorf ("got remaining balance %s; want %d" , got .String (), wantBalance )
162+ }
163+ })
164+ }
165+ }
0 commit comments