mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-13 03:26:38 +00:00
core/vm: implement EIP 7825 - Transaction Gas Limit Cap
Co-authored-by: Jared Wasinger <j-wasinger@hotmail.com>
This commit is contained in:
parent
b62c0c67fa
commit
61d8a93182
9 changed files with 64 additions and 18 deletions
|
|
@ -183,6 +183,9 @@ func Transaction(ctx *cli.Context) error {
|
||||||
if chainConfig.IsShanghai(new(big.Int), 0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
|
if chainConfig.IsShanghai(new(big.Int), 0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
|
||||||
r.Error = errors.New("max initcode size exceeded")
|
r.Error = errors.New("max initcode size exceeded")
|
||||||
}
|
}
|
||||||
|
if chainConfig.IsOsaka(new(big.Int), 0) && tx.Gas() > params.MaxTxGas {
|
||||||
|
r.Error = errors.New("gas limit exceeds maximum")
|
||||||
|
}
|
||||||
results = append(results, r)
|
results = append(results, r)
|
||||||
}
|
}
|
||||||
out, err := json.MarshalIndent(results, "", " ")
|
out, err := json.MarshalIndent(results, "", " ")
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,9 @@ var (
|
||||||
// Message validation errors:
|
// Message validation errors:
|
||||||
ErrEmptyAuthList = errors.New("EIP-7702 transaction with empty auth list")
|
ErrEmptyAuthList = errors.New("EIP-7702 transaction with empty auth list")
|
||||||
ErrSetCodeTxCreate = errors.New("EIP-7702 transaction cannot be used to create contract")
|
ErrSetCodeTxCreate = errors.New("EIP-7702 transaction cannot be used to create contract")
|
||||||
|
|
||||||
|
// -- EIP-7825 errors --
|
||||||
|
ErrGasLimitTooHigh = errors.New("transaction gas limit too high")
|
||||||
)
|
)
|
||||||
|
|
||||||
// EIP-7702 state transition errors.
|
// EIP-7702 state transition errors.
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,10 @@ 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 st.evm.ChainConfig().IsOsaka(st.evm.Context.BlockNumber, st.evm.Context.Time) && msg.GasLimit > params.MaxTxGas {
|
||||||
|
return fmt.Errorf("%w (cap: %d, tx: %d)", ErrGasLimitTooHigh, params.MaxTxGas, msg.GasLimit)
|
||||||
|
}
|
||||||
return st.buyGas()
|
return st.buyGas()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1638,6 +1638,11 @@ func (p *BlobPool) Pending(filter txpool.PendingFilter) map[common.Address][]*tx
|
||||||
break // blobfee too low, cannot be included, discard rest of txs from the account
|
break // blobfee too low, cannot be included, discard rest of txs from the account
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if filter.GasLimitCap != 0 {
|
||||||
|
if tx.execGas > filter.GasLimitCap {
|
||||||
|
break // execution gas limit is too high
|
||||||
|
}
|
||||||
|
}
|
||||||
// Transaction was accepted according to the filter, append to the pending list
|
// Transaction was accepted according to the filter, append to the pending list
|
||||||
lazies = append(lazies, &txpool.LazyTransaction{
|
lazies = append(lazies, &txpool.LazyTransaction{
|
||||||
Pool: p,
|
Pool: p,
|
||||||
|
|
|
||||||
|
|
@ -530,11 +530,19 @@ func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address]
|
||||||
txs := list.Flatten()
|
txs := list.Flatten()
|
||||||
|
|
||||||
// If the miner requests tip enforcement, cap the lists now
|
// If the miner requests tip enforcement, cap the lists now
|
||||||
if minTipBig != nil {
|
if minTipBig != nil || filter.GasLimitCap != 0 {
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
if tx.EffectiveGasTipIntCmp(minTipBig, baseFeeBig) < 0 {
|
if minTipBig != nil {
|
||||||
txs = txs[:i]
|
if tx.EffectiveGasTipIntCmp(minTipBig, baseFeeBig) < 0 {
|
||||||
break
|
txs = txs[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if filter.GasLimitCap != 0 {
|
||||||
|
if tx.Gas() > filter.GasLimitCap {
|
||||||
|
txs = txs[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1255,6 +1263,21 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
|
||||||
}
|
}
|
||||||
pool.mu.Lock()
|
pool.mu.Lock()
|
||||||
if reset != nil {
|
if reset != nil {
|
||||||
|
if reset.newHead != nil && reset.oldHead != nil {
|
||||||
|
// Discard the transactions with the gas limit higher than the cap.
|
||||||
|
if pool.chainconfig.IsOsaka(reset.newHead.Number, reset.newHead.Time) && !pool.chainconfig.IsOsaka(reset.oldHead.Number, reset.oldHead.Time) {
|
||||||
|
var hashes []common.Hash
|
||||||
|
pool.all.Range(func(hash common.Hash, tx *types.Transaction) bool {
|
||||||
|
if tx.Gas() > params.MaxTxGas {
|
||||||
|
hashes = append(hashes, hash)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
for _, hash := range hashes {
|
||||||
|
pool.removeTx(hash, true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Reset from the old head to the new, rescheduling any reorged transactions
|
// Reset from the old head to the new, rescheduling any reorged transactions
|
||||||
pool.reset(reset.oldHead, reset.newHead)
|
pool.reset(reset.oldHead, reset.newHead)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,9 +73,10 @@ type LazyResolver interface {
|
||||||
// a very specific call site in mind and each one can be evaluated very cheaply
|
// a very specific call site in mind and each one can be evaluated very cheaply
|
||||||
// by the pool implementations. Only add new ones that satisfy those constraints.
|
// by the pool implementations. Only add new ones that satisfy those constraints.
|
||||||
type PendingFilter struct {
|
type PendingFilter struct {
|
||||||
MinTip *uint256.Int // Minimum miner tip required to include a transaction
|
MinTip *uint256.Int // Minimum miner tip required to include a transaction
|
||||||
BaseFee *uint256.Int // Minimum 1559 basefee needed to include a transaction
|
BaseFee *uint256.Int // Minimum 1559 basefee needed to include a transaction
|
||||||
BlobFee *uint256.Int // Minimum 4844 blobfee needed to include a blob transaction
|
BlobFee *uint256.Int // Minimum 4844 blobfee needed to include a blob transaction
|
||||||
|
GasLimitCap uint64 // Maximum gas can be used for a single transaction execution (0 means no limit)
|
||||||
|
|
||||||
OnlyPlainTxs bool // Return only plain EVM transactions (peer-join announces, block space filling)
|
OnlyPlainTxs bool // Return only plain EVM transactions (peer-join announces, block space filling)
|
||||||
OnlyBlobTxs bool // Return only blob transactions (block blob-space filling)
|
OnlyBlobTxs bool // Return only blob transactions (block blob-space filling)
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,9 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
|
||||||
if rules.IsShanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
|
if rules.IsShanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
|
||||||
return fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize)
|
return fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize)
|
||||||
}
|
}
|
||||||
|
if rules.IsOsaka && tx.Gas() > params.MaxTxGas {
|
||||||
|
return fmt.Errorf("%w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, params.MaxTxGas, tx.Gas())
|
||||||
|
}
|
||||||
// Transactions can't be negative. This may never happen using RLP decoded
|
// Transactions can't be negative. This may never happen using RLP decoded
|
||||||
// transactions but may occur for transactions created using the RPC.
|
// transactions but may occur for transactions created using the RPC.
|
||||||
if tx.Value().Sign() < 0 {
|
if tx.Value().Sign() < 0 {
|
||||||
|
|
|
||||||
|
|
@ -462,6 +462,9 @@ func (miner *Miner) fillTransactions(interrupt *atomic.Int32, env *environment)
|
||||||
if env.header.ExcessBlobGas != nil {
|
if env.header.ExcessBlobGas != nil {
|
||||||
filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(miner.chainConfig, env.header))
|
filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(miner.chainConfig, env.header))
|
||||||
}
|
}
|
||||||
|
if miner.chainConfig.IsOsaka(env.header.Number, env.header.Time) {
|
||||||
|
filter.GasLimitCap = params.MaxTxGas
|
||||||
|
}
|
||||||
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
|
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
|
||||||
pendingPlainTxs := miner.txpool.Pending(filter)
|
pendingPlainTxs := miner.txpool.Pending(filter)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,17 +28,18 @@ const (
|
||||||
MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1).
|
MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1).
|
||||||
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
|
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
|
||||||
|
|
||||||
MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis.
|
MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis.
|
||||||
ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction.
|
ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction.
|
||||||
SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
|
SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
|
||||||
CallValueTransferGas uint64 = 9000 // Paid for CALL when the value transfer is non-zero.
|
CallValueTransferGas uint64 = 9000 // Paid for CALL when the value transfer is non-zero.
|
||||||
CallNewAccountGas uint64 = 25000 // Paid for CALL when the destination address didn't exist prior.
|
CallNewAccountGas uint64 = 25000 // Paid for CALL when the destination address didn't exist prior.
|
||||||
TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions.
|
TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions.
|
||||||
TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
|
MaxTxGas uint64 = 30_000_000 // eip-7825 maximum transaction gas limit
|
||||||
TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
|
TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
|
||||||
QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation.
|
TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
|
||||||
LogDataGas uint64 = 8 // Per byte in a LOG* operation's data.
|
QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation.
|
||||||
CallStipend uint64 = 2300 // Free gas given at beginning of call.
|
LogDataGas uint64 = 8 // Per byte in a LOG* operation's data.
|
||||||
|
CallStipend uint64 = 2300 // Free gas given at beginning of call.
|
||||||
|
|
||||||
Keccak256Gas uint64 = 30 // Once per KECCAK256 operation.
|
Keccak256Gas uint64 = 30 // Once per KECCAK256 operation.
|
||||||
Keccak256WordGas uint64 = 6 // Once per word of the KECCAK256 operation's data.
|
Keccak256WordGas uint64 = 6 // Once per word of the KECCAK256 operation's data.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue