Skip to content

Commit 470dba8

Browse files
authored
core/vm: set basefee to 0 internally on eth_call (#28470)
* core/vm: set basefee to 0 internally on eth_call * core: nicer 0-basefee, make it work for blob fees too * internal/ethapi: make tests a bit more complex * core: fix blob fee checker * core: make code a bit more readable * core: fix some test error strings * core/vm: Get rid of weird comment * core: dict wrong typo
1 parent 4d9f3cd commit 470dba8

File tree

7 files changed

+82
-26
lines changed

7 files changed

+82
-26
lines changed

core/evm.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,15 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
7777

7878
// NewEVMTxContext creates a new transaction context for a single transaction.
7979
func NewEVMTxContext(msg *Message) vm.TxContext {
80-
return vm.TxContext{
80+
ctx := vm.TxContext{
8181
Origin: msg.From,
8282
GasPrice: new(big.Int).Set(msg.GasPrice),
8383
BlobHashes: msg.BlobHashes,
8484
}
85+
if msg.BlobGasFeeCap != nil {
86+
ctx.BlobFeeCap = new(big.Int).Set(msg.BlobGasFeeCap)
87+
}
88+
return ctx
8589
}
8690

8791
// GetHashFn returns a GetHashFunc which retrieves header hashes by number

core/state_processor_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,15 @@ func TestStateProcessorErrors(t *testing.T) {
9595
}), signer, key1)
9696
return tx
9797
}
98-
var mkBlobTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, hashes []common.Hash) *types.Transaction {
98+
var mkBlobTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap, blobGasFeeCap *big.Int, hashes []common.Hash) *types.Transaction {
9999
tx, err := types.SignTx(types.NewTx(&types.BlobTx{
100100
Nonce: nonce,
101101
GasTipCap: uint256.MustFromBig(gasTipCap),
102102
GasFeeCap: uint256.MustFromBig(gasFeeCap),
103103
Gas: gasLimit,
104104
To: to,
105105
BlobHashes: hashes,
106+
BlobFeeCap: uint256.MustFromBig(blobGasFeeCap),
106107
Value: new(uint256.Int),
107108
}), signer, key1)
108109
if err != nil {
@@ -196,7 +197,7 @@ func TestStateProcessorErrors(t *testing.T) {
196197
txs: []*types.Transaction{
197198
mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(0), big.NewInt(0)),
198199
},
199-
want: "could not apply tx 0 [0xc4ab868fef0c82ae0387b742aee87907f2d0fc528fc6ea0a021459fb0fc4a4a8]: max fee per gas less than block base fee: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas: 0 baseFee: 875000000",
200+
want: "could not apply tx 0 [0xc4ab868fef0c82ae0387b742aee87907f2d0fc528fc6ea0a021459fb0fc4a4a8]: max fee per gas less than block base fee: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas: 0, baseFee: 875000000",
200201
},
201202
{ // ErrTipVeryHigh
202203
txs: []*types.Transaction{
@@ -247,9 +248,9 @@ func TestStateProcessorErrors(t *testing.T) {
247248
},
248249
{ // ErrBlobFeeCapTooLow
249250
txs: []*types.Transaction{
250-
mkBlobTx(0, common.Address{}, params.TxGas, big.NewInt(1), big.NewInt(1), []common.Hash{(common.Hash{1})}),
251+
mkBlobTx(0, common.Address{}, params.TxGas, big.NewInt(1), big.NewInt(1), big.NewInt(0), []common.Hash{(common.Hash{1})}),
251252
},
252-
want: "could not apply tx 0 [0x6c11015985ce82db691d7b2d017acda296db88b811c3c60dc71449c76256c716]: max fee per gas less than block base fee: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas: 1 baseFee: 875000000",
253+
want: "could not apply tx 0 [0x6c11015985ce82db691d7b2d017acda296db88b811c3c60dc71449c76256c716]: max fee per gas less than block base fee: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas: 1, baseFee: 875000000",
253254
},
254255
} {
255256
block := GenerateBadBlock(gspec.ToBlock(), beacon.New(ethash.NewFaker()), tt.txs, gspec.Config)

core/state_transition.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,11 @@ func (st *StateTransition) preCheck() error {
287287
msg.From.Hex(), codeHash)
288288
}
289289
}
290-
291290
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
292291
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
293292
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
294-
if !st.evm.Config.NoBaseFee || msg.GasFeeCap.BitLen() > 0 || msg.GasTipCap.BitLen() > 0 {
293+
skipCheck := st.evm.Config.NoBaseFee && msg.GasFeeCap.BitLen() == 0 && msg.GasTipCap.BitLen() == 0
294+
if !skipCheck {
295295
if l := msg.GasFeeCap.BitLen(); l > 256 {
296296
return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
297297
msg.From.Hex(), l)
@@ -307,7 +307,7 @@ func (st *StateTransition) preCheck() error {
307307
// This will panic if baseFee is nil, but basefee presence is verified
308308
// as part of header validation.
309309
if msg.GasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
310-
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
310+
return fmt.Errorf("%w: address %v, maxFeePerGas: %s, baseFee: %s", ErrFeeCapTooLow,
311311
msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee)
312312
}
313313
}
@@ -324,17 +324,21 @@ func (st *StateTransition) preCheck() error {
324324
}
325325
}
326326
}
327-
327+
// Check that the user is paying at least the current blob fee
328328
if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) {
329329
if st.blobGasUsed() > 0 {
330-
// Check that the user is paying at least the current blob fee
331-
blobFee := st.evm.Context.BlobBaseFee
332-
if st.msg.BlobGasFeeCap.Cmp(blobFee) < 0 {
333-
return fmt.Errorf("%w: address %v have %v want %v", ErrBlobFeeCapTooLow, st.msg.From.Hex(), st.msg.BlobGasFeeCap, blobFee)
330+
// Skip the checks if gas fields are zero and blobBaseFee was explicitly disabled (eth_call)
331+
skipCheck := st.evm.Config.NoBaseFee && msg.BlobGasFeeCap.BitLen() == 0
332+
if !skipCheck {
333+
// This will panic if blobBaseFee is nil, but blobBaseFee presence
334+
// is verified as part of header validation.
335+
if msg.BlobGasFeeCap.Cmp(st.evm.Context.BlobBaseFee) < 0 {
336+
return fmt.Errorf("%w: address %v blobGasFeeCap: %v, blobBaseFee: %v", ErrBlobFeeCapTooLow,
337+
msg.From.Hex(), msg.BlobGasFeeCap, st.evm.Context.BlobBaseFee)
338+
}
334339
}
335340
}
336341
}
337-
338342
return st.buyGas()
339343
}
340344

core/vm/evm.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ type BlockContext struct {
7272
BlockNumber *big.Int // Provides information for NUMBER
7373
Time uint64 // Provides information for TIME
7474
Difficulty *big.Int // Provides information for DIFFICULTY
75-
BaseFee *big.Int // Provides information for BASEFEE
76-
BlobBaseFee *big.Int // Provides information for BLOBBASEFEE
75+
BaseFee *big.Int // Provides information for BASEFEE (0 if vm runs with NoBaseFee flag and 0 gas price)
76+
BlobBaseFee *big.Int // Provides information for BLOBBASEFEE (0 if vm runs with NoBaseFee flag and 0 blob gas price)
7777
Random *common.Hash // Provides information for PREVRANDAO
7878
}
7979

@@ -82,8 +82,9 @@ type BlockContext struct {
8282
type TxContext struct {
8383
// Message information
8484
Origin common.Address // Provides information for ORIGIN
85-
GasPrice *big.Int // Provides information for GASPRICE
85+
GasPrice *big.Int // Provides information for GASPRICE (and is used to zero the basefee if NoBaseFee is set)
8686
BlobHashes []common.Hash // Provides information for BLOBHASH
87+
BlobFeeCap *big.Int // Is used to zero the blobbasefee if NoBaseFee is set
8788
}
8889

8990
// EVM is the Ethereum Virtual Machine base object and provides
@@ -125,6 +126,17 @@ type EVM struct {
125126
// NewEVM returns a new EVM. The returned EVM is not thread safe and should
126127
// only ever be used *once*.
127128
func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM {
129+
// If basefee tracking is disabled (eth_call, eth_estimateGas, etc), and no
130+
// gas prices were specified, lower the basefee to 0 to avoid breaking EVM
131+
// invariants (basefee < feecap)
132+
if config.NoBaseFee {
133+
if txCtx.GasPrice.BitLen() == 0 {
134+
blockCtx.BaseFee = new(big.Int)
135+
}
136+
if txCtx.BlobFeeCap != nil && txCtx.BlobFeeCap.BitLen() == 0 {
137+
blockCtx.BlobBaseFee = new(big.Int)
138+
}
139+
}
128140
evm := &EVM{
129141
Context: blockCtx,
130142
TxContext: txCtx,
@@ -160,14 +172,6 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
160172
return evm.interpreter
161173
}
162174

163-
// SetBlockContext updates the block context of the EVM.
164-
func (evm *EVM) SetBlockContext(blockCtx BlockContext) {
165-
evm.Context = blockCtx
166-
num := blockCtx.BlockNumber
167-
timestamp := blockCtx.Time
168-
evm.chainRules = evm.chainConfig.Rules(num, blockCtx.Random != nil, timestamp)
169-
}
170-
171175
// Call executes the contract associated with the addr with the given input as
172176
// parameters. It also handles any necessary value transfer required and takes
173177
// the necessary steps to create accounts and reverses the state in case of an

core/vm/runtime/env.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ func NewEnv(cfg *Config) *vm.EVM {
2626
Origin: cfg.Origin,
2727
GasPrice: cfg.GasPrice,
2828
BlobHashes: cfg.BlobHashes,
29+
BlobFeeCap: cfg.BlobFeeCap,
2930
}
3031
blockContext := vm.BlockContext{
3132
CanTransfer: core.CanTransfer,

core/vm/runtime/runtime.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type Config struct {
4646
BaseFee *big.Int
4747
BlobBaseFee *big.Int
4848
BlobHashes []common.Hash
49+
BlobFeeCap *big.Int
4950
Random *common.Hash
5051

5152
State *state.StateDB
@@ -97,7 +98,7 @@ func setDefaults(cfg *Config) {
9798
cfg.BaseFee = big.NewInt(params.InitialBaseFee)
9899
}
99100
if cfg.BlobBaseFee == nil {
100-
cfg.BlobBaseFee = new(big.Int)
101+
cfg.BlobBaseFee = big.NewInt(params.BlobTxMinBlobGasprice)
101102
}
102103
}
103104

internal/ethapi/api_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,47 @@ func TestEstimateGas(t *testing.T) {
678678
},
679679
expectErr: core.ErrInsufficientFunds,
680680
},
681+
// Test for a bug where the gas price was set to zero but the basefee non-zero
682+
//
683+
// contract BasefeeChecker {
684+
// constructor() {
685+
// require(tx.gasprice >= block.basefee);
686+
// if (tx.gasprice > 0) {
687+
// require(block.basefee > 0);
688+
// }
689+
// }
690+
//}
691+
{
692+
blockNumber: rpc.LatestBlockNumber,
693+
call: TransactionArgs{
694+
From: &accounts[0].addr,
695+
Input: hex2Bytes("6080604052348015600f57600080fd5b50483a1015601c57600080fd5b60003a111560315760004811603057600080fd5b5b603f80603e6000396000f3fe6080604052600080fdfea264697066735822122060729c2cee02b10748fae5200f1c9da4661963354973d9154c13a8e9ce9dee1564736f6c63430008130033"),
696+
GasPrice: (*hexutil.Big)(big.NewInt(1_000_000_000)), // Legacy as pricing
697+
},
698+
expectErr: nil,
699+
want: 67617,
700+
},
701+
{
702+
blockNumber: rpc.LatestBlockNumber,
703+
call: TransactionArgs{
704+
From: &accounts[0].addr,
705+
Input: hex2Bytes("6080604052348015600f57600080fd5b50483a1015601c57600080fd5b60003a111560315760004811603057600080fd5b5b603f80603e6000396000f3fe6080604052600080fdfea264697066735822122060729c2cee02b10748fae5200f1c9da4661963354973d9154c13a8e9ce9dee1564736f6c63430008130033"),
706+
MaxFeePerGas: (*hexutil.Big)(big.NewInt(1_000_000_000)), // 1559 gas pricing
707+
},
708+
expectErr: nil,
709+
want: 67617,
710+
},
711+
{
712+
blockNumber: rpc.LatestBlockNumber,
713+
call: TransactionArgs{
714+
From: &accounts[0].addr,
715+
Input: hex2Bytes("6080604052348015600f57600080fd5b50483a1015601c57600080fd5b60003a111560315760004811603057600080fd5b5b603f80603e6000396000f3fe6080604052600080fdfea264697066735822122060729c2cee02b10748fae5200f1c9da4661963354973d9154c13a8e9ce9dee1564736f6c63430008130033"),
716+
GasPrice: nil, // No legacy gas pricing
717+
MaxFeePerGas: nil, // No 1559 gas pricing
718+
},
719+
expectErr: nil,
720+
want: 67595,
721+
},
681722
}
682723
for i, tc := range testSuite {
683724
result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides)

0 commit comments

Comments
 (0)