mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 15:47:21 +00:00
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.
This commit is contained in:
parent
b9e2eb5944
commit
2b3d617e04
5 changed files with 22 additions and 18 deletions
|
|
@ -164,8 +164,12 @@ type Message struct {
|
||||||
// or the state prefetching.
|
// or the state prefetching.
|
||||||
SkipNonceChecks bool
|
SkipNonceChecks bool
|
||||||
|
|
||||||
// When SkipFromEOACheck is true, the message sender is not checked to be an EOA.
|
// When set, the message is not treated as a transaction, and certain
|
||||||
SkipFromEOACheck bool
|
// transaction-specific checks are skipped:
|
||||||
|
//
|
||||||
|
// - From is not verified to be an EOA
|
||||||
|
// - GasLimit is not checked against the protocol defined tx gaslimit
|
||||||
|
SkipTransactionChecks bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionToMessage converts a transaction into a Message.
|
// TransactionToMessage converts a transaction into a Message.
|
||||||
|
|
@ -182,7 +186,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
|
||||||
AccessList: tx.AccessList(),
|
AccessList: tx.AccessList(),
|
||||||
SetCodeAuthorizations: tx.SetCodeAuthorizations(),
|
SetCodeAuthorizations: tx.SetCodeAuthorizations(),
|
||||||
SkipNonceChecks: false,
|
SkipNonceChecks: false,
|
||||||
SkipFromEOACheck: false,
|
SkipTransactionChecks: false,
|
||||||
BlobHashes: tx.BlobHashes(),
|
BlobHashes: tx.BlobHashes(),
|
||||||
BlobGasFeeCap: tx.BlobGasFeeCap(),
|
BlobGasFeeCap: tx.BlobGasFeeCap(),
|
||||||
}
|
}
|
||||||
|
|
@ -320,7 +324,12 @@ func (st *stateTransition) preCheck() error {
|
||||||
msg.From.Hex(), stNonce)
|
msg.From.Hex(), stNonce)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !msg.SkipFromEOACheck {
|
isOsaka := st.evm.ChainConfig().IsOsaka(st.evm.Context.BlockNumber, st.evm.Context.Time)
|
||||||
|
if !msg.SkipTransactionChecks {
|
||||||
|
// Verify tx gas limit does not exceed EIP-7825 cap.
|
||||||
|
if isOsaka && msg.GasLimit > params.MaxTxGas {
|
||||||
|
return fmt.Errorf("%w (cap: %d, tx: %d)", ErrGasLimitTooHigh, params.MaxTxGas, msg.GasLimit)
|
||||||
|
}
|
||||||
// Make sure the sender is an EOA
|
// Make sure the sender is an EOA
|
||||||
code := st.state.GetCode(msg.From)
|
code := st.state.GetCode(msg.From)
|
||||||
_, delegated := types.ParseDelegation(code)
|
_, delegated := types.ParseDelegation(code)
|
||||||
|
|
@ -354,7 +363,6 @@ func (st *stateTransition) preCheck() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check the blob version validity
|
// Check the blob version validity
|
||||||
isOsaka := st.evm.ChainConfig().IsOsaka(st.evm.Context.BlockNumber, st.evm.Context.Time)
|
|
||||||
if msg.BlobHashes != nil {
|
if msg.BlobHashes != nil {
|
||||||
// The to field of a blob tx type is mandatory, and a `BlobTx` transaction internally
|
// The to field of a blob tx type is mandatory, and a `BlobTx` transaction internally
|
||||||
// has it as a non-nillable value, so any msg derived from blob transaction has it non-nil.
|
// 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 {
|
||||||
return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From)
|
return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Verify tx gas limit does not exceed EIP-7825 cap.
|
|
||||||
if isOsaka && msg.GasLimit > params.MaxTxGas {
|
|
||||||
return fmt.Errorf("%w (cap: %d, tx: %d)", ErrGasLimitTooHigh, params.MaxTxGas, msg.GasLimit)
|
|
||||||
}
|
|
||||||
return st.buyGas()
|
return st.buyGas()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -984,7 +984,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
msg = args.ToMessage(blockContext.BaseFee, true, true)
|
msg = args.ToMessage(blockContext.BaseFee, true)
|
||||||
tx = args.ToTransaction(types.LegacyTxType)
|
tx = args.ToTransaction(types.LegacyTxType)
|
||||||
traceConfig *TraceConfig
|
traceConfig *TraceConfig
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -699,15 +699,15 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S
|
||||||
} else {
|
} else {
|
||||||
gp.AddGas(globalGasCap)
|
gp.AddGas(globalGasCap)
|
||||||
}
|
}
|
||||||
return applyMessage(ctx, b, args, state, header, timeout, gp, &blockCtx, &vm.Config{NoBaseFee: true}, precompiles, true)
|
return applyMessage(ctx, b, args, state, header, timeout, gp, &blockCtx, &vm.Config{NoBaseFee: true}, precompiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
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) {
|
||||||
// Get a new instance of the EVM.
|
// Get a new instance of the EVM.
|
||||||
if err := args.CallDefaults(gp.Gas(), blockContext.BaseFee, b.ChainConfig().ChainID); err != nil {
|
if err := args.CallDefaults(gp.Gas(), blockContext.BaseFee, b.ChainConfig().ChainID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
msg := args.ToMessage(header.BaseFee, skipChecks, skipChecks)
|
msg := args.ToMessage(header.BaseFee, true)
|
||||||
// Lower the basefee to 0 to avoid breaking EVM
|
// Lower the basefee to 0 to avoid breaking EVM
|
||||||
// invariants (basefee < feecap).
|
// invariants (basefee < feecap).
|
||||||
if msg.GasPrice.Sign() == 0 {
|
if msg.GasPrice.Sign() == 0 {
|
||||||
|
|
@ -858,7 +858,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
||||||
if err := args.CallDefaults(gasCap, header.BaseFee, b.ChainConfig().ChainID); err != nil {
|
if err := args.CallDefaults(gasCap, header.BaseFee, b.ChainConfig().ChainID); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
call := args.ToMessage(header.BaseFee, true, true)
|
call := args.ToMessage(header.BaseFee, true)
|
||||||
|
|
||||||
// Run the gas estimation and wrap any revertals into a custom return
|
// Run the gas estimation and wrap any revertals into a custom return
|
||||||
estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap)
|
estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap)
|
||||||
|
|
@ -1301,7 +1301,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
||||||
statedb := db.Copy()
|
statedb := db.Copy()
|
||||||
// Set the accesslist to the last al
|
// Set the accesslist to the last al
|
||||||
args.AccessList = &accessList
|
args.AccessList = &accessList
|
||||||
msg := args.ToMessage(header.BaseFee, true, true)
|
msg := args.ToMessage(header.BaseFee, true)
|
||||||
|
|
||||||
// Apply the transaction with the access list tracer
|
// Apply the transaction with the access list tracer
|
||||||
tracer := logger.NewAccessListTracer(accessList, addressesToExclude)
|
tracer := logger.NewAccessListTracer(accessList, addressesToExclude)
|
||||||
|
|
|
||||||
|
|
@ -287,7 +287,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
||||||
tracer.reset(txHash, uint(i))
|
tracer.reset(txHash, uint(i))
|
||||||
sim.state.SetTxContext(txHash, i)
|
sim.state.SetTxContext(txHash, i)
|
||||||
// EoA check is always skipped, even in validation mode.
|
// EoA check is always skipped, even in validation mode.
|
||||||
msg := call.ToMessage(header.BaseFee, !sim.validate, true)
|
msg := call.ToMessage(header.BaseFee, !sim.validate)
|
||||||
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)
|
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
txErr := txValidationError(err)
|
txErr := txValidationError(err)
|
||||||
|
|
|
||||||
|
|
@ -443,7 +443,7 @@ func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int,
|
||||||
// core evm. This method is used in calls and traces that do not require a real
|
// core evm. This method is used in calls and traces that do not require a real
|
||||||
// live transaction.
|
// live transaction.
|
||||||
// Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called.
|
// Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called.
|
||||||
func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoACheck bool) *core.Message {
|
func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck bool) *core.Message {
|
||||||
var (
|
var (
|
||||||
gasPrice *big.Int
|
gasPrice *big.Int
|
||||||
gasFeeCap *big.Int
|
gasFeeCap *big.Int
|
||||||
|
|
@ -491,7 +491,7 @@ func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoA
|
||||||
BlobHashes: args.BlobHashes,
|
BlobHashes: args.BlobHashes,
|
||||||
SetCodeAuthorizations: args.AuthorizationList,
|
SetCodeAuthorizations: args.AuthorizationList,
|
||||||
SkipNonceChecks: skipNonceCheck,
|
SkipNonceChecks: skipNonceCheck,
|
||||||
SkipFromEOACheck: skipEoACheck,
|
SkipTransactionChecks: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue