Skip to content

Commit 2b3d617

Browse files
authored
internal/ethapi: skip tx gas limit check for calls (#32641)
This disables the tx gaslimit cap for eth_call and related RPC operations. I don't like how this fix works. Ideally we'd be checking the tx gaslimit somewhere else, like in the block validator, or any other place that considers block transactions. Doing the check in StateTransition means it affects all possible ways of executing a message. The challenge is finding a place for this check that also triggers correctly in tests where it is wanted. So for now, we are just combining this with the EOA sender check for transactions. Both are disabled for call-type messages.
1 parent b9e2eb5 commit 2b3d617

File tree

5 files changed

+22
-18
lines changed

5 files changed

+22
-18
lines changed

core/state_transition.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,12 @@ type Message struct {
164164
// or the state prefetching.
165165
SkipNonceChecks bool
166166

167-
// When SkipFromEOACheck is true, the message sender is not checked to be an EOA.
168-
SkipFromEOACheck bool
167+
// When set, the message is not treated as a transaction, and certain
168+
// transaction-specific checks are skipped:
169+
//
170+
// - From is not verified to be an EOA
171+
// - GasLimit is not checked against the protocol defined tx gaslimit
172+
SkipTransactionChecks bool
169173
}
170174

171175
// TransactionToMessage converts a transaction into a Message.
@@ -182,7 +186,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
182186
AccessList: tx.AccessList(),
183187
SetCodeAuthorizations: tx.SetCodeAuthorizations(),
184188
SkipNonceChecks: false,
185-
SkipFromEOACheck: false,
189+
SkipTransactionChecks: false,
186190
BlobHashes: tx.BlobHashes(),
187191
BlobGasFeeCap: tx.BlobGasFeeCap(),
188192
}
@@ -320,7 +324,12 @@ func (st *stateTransition) preCheck() error {
320324
msg.From.Hex(), stNonce)
321325
}
322326
}
323-
if !msg.SkipFromEOACheck {
327+
isOsaka := st.evm.ChainConfig().IsOsaka(st.evm.Context.BlockNumber, st.evm.Context.Time)
328+
if !msg.SkipTransactionChecks {
329+
// Verify tx gas limit does not exceed EIP-7825 cap.
330+
if isOsaka && msg.GasLimit > params.MaxTxGas {
331+
return fmt.Errorf("%w (cap: %d, tx: %d)", ErrGasLimitTooHigh, params.MaxTxGas, msg.GasLimit)
332+
}
324333
// Make sure the sender is an EOA
325334
code := st.state.GetCode(msg.From)
326335
_, delegated := types.ParseDelegation(code)
@@ -354,7 +363,6 @@ func (st *stateTransition) preCheck() error {
354363
}
355364
}
356365
// Check the blob version validity
357-
isOsaka := st.evm.ChainConfig().IsOsaka(st.evm.Context.BlockNumber, st.evm.Context.Time)
358366
if msg.BlobHashes != nil {
359367
// The to field of a blob tx type is mandatory, and a `BlobTx` transaction internally
360368
// has it as a non-nillable value, so any msg derived from blob transaction has it non-nil.
@@ -398,10 +406,6 @@ func (st *stateTransition) preCheck() error {
398406
return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From)
399407
}
400408
}
401-
// Verify tx gas limit does not exceed EIP-7825 cap.
402-
if isOsaka && msg.GasLimit > params.MaxTxGas {
403-
return fmt.Errorf("%w (cap: %d, tx: %d)", ErrGasLimitTooHigh, params.MaxTxGas, msg.GasLimit)
404-
}
405409
return st.buyGas()
406410
}
407411

eth/tracers/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
984984
return nil, err
985985
}
986986
var (
987-
msg = args.ToMessage(blockContext.BaseFee, true, true)
987+
msg = args.ToMessage(blockContext.BaseFee, true)
988988
tx = args.ToTransaction(types.LegacyTxType)
989989
traceConfig *TraceConfig
990990
)

internal/ethapi/api.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -699,15 +699,15 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S
699699
} else {
700700
gp.AddGas(globalGasCap)
701701
}
702-
return applyMessage(ctx, b, args, state, header, timeout, gp, &blockCtx, &vm.Config{NoBaseFee: true}, precompiles, true)
702+
return applyMessage(ctx, b, args, state, header, timeout, gp, &blockCtx, &vm.Config{NoBaseFee: true}, precompiles)
703703
}
704704

705-
func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, timeout time.Duration, gp *core.GasPool, blockContext *vm.BlockContext, vmConfig *vm.Config, precompiles vm.PrecompiledContracts, skipChecks bool) (*core.ExecutionResult, error) {
705+
func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, timeout time.Duration, gp *core.GasPool, blockContext *vm.BlockContext, vmConfig *vm.Config, precompiles vm.PrecompiledContracts) (*core.ExecutionResult, error) {
706706
// Get a new instance of the EVM.
707707
if err := args.CallDefaults(gp.Gas(), blockContext.BaseFee, b.ChainConfig().ChainID); err != nil {
708708
return nil, err
709709
}
710-
msg := args.ToMessage(header.BaseFee, skipChecks, skipChecks)
710+
msg := args.ToMessage(header.BaseFee, true)
711711
// Lower the basefee to 0 to avoid breaking EVM
712712
// invariants (basefee < feecap).
713713
if msg.GasPrice.Sign() == 0 {
@@ -858,7 +858,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
858858
if err := args.CallDefaults(gasCap, header.BaseFee, b.ChainConfig().ChainID); err != nil {
859859
return 0, err
860860
}
861-
call := args.ToMessage(header.BaseFee, true, true)
861+
call := args.ToMessage(header.BaseFee, true)
862862

863863
// Run the gas estimation and wrap any revertals into a custom return
864864
estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap)
@@ -1301,7 +1301,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
13011301
statedb := db.Copy()
13021302
// Set the accesslist to the last al
13031303
args.AccessList = &accessList
1304-
msg := args.ToMessage(header.BaseFee, true, true)
1304+
msg := args.ToMessage(header.BaseFee, true)
13051305

13061306
// Apply the transaction with the access list tracer
13071307
tracer := logger.NewAccessListTracer(accessList, addressesToExclude)

internal/ethapi/simulate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
287287
tracer.reset(txHash, uint(i))
288288
sim.state.SetTxContext(txHash, i)
289289
// EoA check is always skipped, even in validation mode.
290-
msg := call.ToMessage(header.BaseFee, !sim.validate, true)
290+
msg := call.ToMessage(header.BaseFee, !sim.validate)
291291
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)
292292
if err != nil {
293293
txErr := txValidationError(err)

internal/ethapi/transaction_args.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int,
443443
// core evm. This method is used in calls and traces that do not require a real
444444
// live transaction.
445445
// Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called.
446-
func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoACheck bool) *core.Message {
446+
func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck bool) *core.Message {
447447
var (
448448
gasPrice *big.Int
449449
gasFeeCap *big.Int
@@ -491,7 +491,7 @@ func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoA
491491
BlobHashes: args.BlobHashes,
492492
SetCodeAuthorizations: args.AuthorizationList,
493493
SkipNonceChecks: skipNonceCheck,
494-
SkipFromEOACheck: skipEoACheck,
494+
SkipTransactionChecks: true,
495495
}
496496
}
497497

0 commit comments

Comments
 (0)