core: nicer 0-basefee, make it work for blob fees too

This commit is contained in:
Péter Szilágyi 2023-11-07 11:55:27 +02:00
parent 849c0d4a40
commit de24a7a612
6 changed files with 39 additions and 27 deletions

View file

@ -77,11 +77,15 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
// NewEVMTxContext creates a new transaction context for a single transaction. // NewEVMTxContext creates a new transaction context for a single transaction.
func NewEVMTxContext(msg *Message) vm.TxContext { func NewEVMTxContext(msg *Message) vm.TxContext {
return vm.TxContext{ ctx := vm.TxContext{
Origin: msg.From, Origin: msg.From,
GasPrice: new(big.Int).Set(msg.GasPrice), GasPrice: new(big.Int).Set(msg.GasPrice),
BlobHashes: msg.BlobHashes, BlobHashes: msg.BlobHashes,
} }
if msg.BlobGasFeeCap != nil {
ctx.BlobFeeCap = new(big.Int).Set(msg.BlobGasFeeCap)
}
return ctx
} }
// GetHashFn returns a GetHashFunc which retrieves header hashes by number // GetHashFn returns a GetHashFunc which retrieves header hashes by number

View file

@ -287,7 +287,6 @@ func (st *StateTransition) preCheck() error {
msg.From.Hex(), codeHash) msg.From.Hex(), codeHash)
} }
} }
// Make sure that transaction gasFeeCap is greater than the baseFee (post london) // Make sure that transaction gasFeeCap is greater than the baseFee (post london)
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) { if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call) // Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
@ -307,7 +306,7 @@ func (st *StateTransition) preCheck() error {
// This will panic if baseFee is nil, but basefee presence is verified // This will panic if baseFee is nil, but basefee presence is verified
// as part of header validation. // as part of header validation.
if msg.GasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 { if msg.GasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow, return fmt.Errorf("%w: address %v, maxFeePerGas: %s, baseFee: %s", ErrFeeCapTooLow,
msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee) msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee)
} }
} }
@ -324,17 +323,24 @@ func (st *StateTransition) preCheck() error {
} }
} }
} }
// Check that the user is paying at least the current blob fee
if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) { if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) {
if st.blobGasUsed() > 0 { if st.blobGasUsed() > 0 {
// Check that the user is paying at least the current blob fee // Skip the checks if gas fields are zero and blobBaseFee was explicitly disabled (eth_call)
blobFee := st.evm.Context.BlobBaseFee if !st.evm.Config.NoBaseFee && msg.BlobGasFeeCap.BitLen() > 0 {
if st.msg.BlobGasFeeCap.Cmp(blobFee) < 0 { if l := msg.BlobGasFeeCap.BitLen(); l > 256 {
return fmt.Errorf("%w: address %v have %v want %v", ErrBlobFeeCapTooLow, st.msg.From.Hex(), st.msg.BlobGasFeeCap, blobFee) return fmt.Errorf("%w: address %v, blobGasFeeCap bit length: %d", ErrFeeCapVeryHigh,
msg.From.Hex(), l)
}
// This will panic if blobBaseFee is nil, but blobBaseFee presence
// is verified as part of header validation.
if msg.BlobGasFeeCap.Cmp(st.evm.Context.BlobBaseFee) < 0 {
return fmt.Errorf("%w: address %v blobGasFeeCap: %v, blobBaseFee: %v", ErrBlobFeeCapTooLow,
msg.From.Hex(), msg.BlobGasFeeCap, st.evm.Context.BlobBaseFee)
}
} }
} }
} }
return st.buyGas() return st.buyGas()
} }

View file

@ -215,12 +215,8 @@ func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
// opBaseFee implements BASEFEE opcode // opBaseFee implements BASEFEE opcode
func opBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func opBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.evm.Config.NoBaseFee {
scope.Stack.push(new(uint256.Int))
} else {
baseFee, _ := uint256.FromBig(interpreter.evm.Context.BaseFee) baseFee, _ := uint256.FromBig(interpreter.evm.Context.BaseFee)
scope.Stack.push(baseFee) scope.Stack.push(baseFee)
}
return nil, nil return nil, nil
} }

View file

@ -72,8 +72,8 @@ type BlockContext struct {
BlockNumber *big.Int // Provides information for NUMBER BlockNumber *big.Int // Provides information for NUMBER
Time uint64 // Provides information for TIME Time uint64 // Provides information for TIME
Difficulty *big.Int // Provides information for DIFFICULTY Difficulty *big.Int // Provides information for DIFFICULTY
BaseFee *big.Int // Provides information for BASEFEE BaseFee *big.Int // Provides information for BASEFEE (0 if vm runs with NoBaseFee flag and 0 gas price)
BlobBaseFee *big.Int // Provides information for BLOBBASEFEE BlobBaseFee *big.Int // Provides information for BLOBBASEFEE (0 if vm runs with NoBaseFee flag and 0 blob gas price)
Random *common.Hash // Provides information for PREVRANDAO Random *common.Hash // Provides information for PREVRANDAO
} }
@ -82,7 +82,8 @@ type BlockContext struct {
type TxContext struct { type TxContext struct {
// Message information // Message information
Origin common.Address // Provides information for ORIGIN Origin common.Address // Provides information for ORIGIN
GasPrice *big.Int // Provides information for GASPRICE GasPrice *big.Int // Provides information for GASPRICE (and is used to zero the basefee if NoBaseFee is set)
BlobFeeCap *big.Int // Provides information for BLOBGASPRICE(?) (and is used to zero the blobbasefee if NoBaseFee is set)
BlobHashes []common.Hash // Provides information for BLOBHASH BlobHashes []common.Hash // Provides information for BLOBHASH
} }
@ -125,6 +126,17 @@ type EVM struct {
// NewEVM returns a new EVM. The returned EVM is not thread safe and should // NewEVM returns a new EVM. The returned EVM is not thread safe and should
// only ever be used *once*. // only ever be used *once*.
func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM {
// If basefee tracking is disabled (eth_call, eth_estimateGas, etc), and no
// gas prices were specified, lower the basefee to 0 to avoid breaking EVM
// invariants (basefee < feecap)
if config.NoBaseFee {
if txCtx.GasPrice.BitLen() == 0 {
blockCtx.BaseFee = new(big.Int)
}
if txCtx.BlobFeeCap != nil && txCtx.BlobFeeCap.BitLen() == 0 {
blockCtx.BlobBaseFee = new(big.Int)
}
}
evm := &EVM{ evm := &EVM{
Context: blockCtx, Context: blockCtx,
TxContext: txCtx, TxContext: txCtx,
@ -160,14 +172,6 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
return evm.interpreter return evm.interpreter
} }
// SetBlockContext updates the block context of the EVM.
func (evm *EVM) SetBlockContext(blockCtx BlockContext) {
evm.Context = blockCtx
num := blockCtx.BlockNumber
timestamp := blockCtx.Time
evm.chainRules = evm.chainConfig.Rules(num, blockCtx.Random != nil, timestamp)
}
// Call executes the contract associated with the addr with the given input as // Call executes the contract associated with the addr with the given input as
// parameters. It also handles any necessary value transfer required and takes // parameters. It also handles any necessary value transfer required and takes
// the necessary steps to create accounts and reverses the state in case of an // the necessary steps to create accounts and reverses the state in case of an

View file

@ -26,6 +26,7 @@ func NewEnv(cfg *Config) *vm.EVM {
Origin: cfg.Origin, Origin: cfg.Origin,
GasPrice: cfg.GasPrice, GasPrice: cfg.GasPrice,
BlobHashes: cfg.BlobHashes, BlobHashes: cfg.BlobHashes,
BlobFeeCap: cfg.BlobFeeCap,
} }
blockContext := vm.BlockContext{ blockContext := vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,

View file

@ -46,6 +46,7 @@ type Config struct {
BaseFee *big.Int BaseFee *big.Int
BlobBaseFee *big.Int BlobBaseFee *big.Int
BlobHashes []common.Hash BlobHashes []common.Hash
BlobFeeCap *big.Int
Random *common.Hash Random *common.Hash
State *state.StateDB State *state.StateDB
@ -97,7 +98,7 @@ func setDefaults(cfg *Config) {
cfg.BaseFee = big.NewInt(params.InitialBaseFee) cfg.BaseFee = big.NewInt(params.InitialBaseFee)
} }
if cfg.BlobBaseFee == nil { if cfg.BlobBaseFee == nil {
cfg.BlobBaseFee = new(big.Int) cfg.BlobBaseFee = big.NewInt(params.BlobTxMinBlobGasprice)
} }
} }