mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 15:47:21 +00:00
core/vm: implement EIP 7825 - Transaction Gas Limit Cap
This commit is contained in:
parent
4d0c1f9060
commit
9630ce3c7e
6 changed files with 85 additions and 19 deletions
|
|
@ -84,6 +84,10 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
|||
// Blob transactions may be present after the Cancun fork.
|
||||
var blobs int
|
||||
for i, tx := range block.Transactions() {
|
||||
if v.config.IsOsaka(block.Number(), block.Time()) && tx.Gas() > params.MaxTxGas {
|
||||
return fmt.Errorf("transaction exceeds maximum allowed gas limit (has %d gas)", tx.Gas())
|
||||
}
|
||||
|
||||
// Count the number of blobs to validate against the header's blobGasUsed
|
||||
blobs += len(tx.BlobHashes())
|
||||
|
||||
|
|
|
|||
|
|
@ -1255,6 +1255,20 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
|
|||
}
|
||||
pool.mu.Lock()
|
||||
if reset != nil {
|
||||
if reset.newHead != nil && reset.oldHead != nil {
|
||||
if pool.chainconfig.IsOsaka(reset.newHead.Number, reset.newHead.Time) && !pool.chainconfig.IsOsaka(reset.oldHead.Number, reset.oldHead.Time) {
|
||||
var removeHashes []common.Hash
|
||||
pool.all.Range(func(hash common.Hash, tx *types.Transaction) bool {
|
||||
if tx.Gas() > params.MaxTxGas {
|
||||
removeHashes = append(removeHashes, hash)
|
||||
}
|
||||
return true
|
||||
})
|
||||
for _, hash := range removeHashes {
|
||||
pool.all.Remove(hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reset from the old head to the new, rescheduling any reorged transactions
|
||||
pool.reset(reset.oldHead, reset.newHead)
|
||||
|
||||
|
|
@ -1279,7 +1293,7 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
|
|||
// because of another transaction (e.g. higher gas price).
|
||||
if reset != nil {
|
||||
pool.demoteUnexecutables()
|
||||
if reset.newHead != nil {
|
||||
if reset.newHead != reset.oldHead {
|
||||
if pool.chainconfig.IsLondon(new(big.Int).Add(reset.newHead.Number, big.NewInt(1))) {
|
||||
pendingBaseFee := eip1559.CalcBaseFee(pool.chainconfig, reset.newHead)
|
||||
pool.priced.SetBaseFee(pendingBaseFee)
|
||||
|
|
|
|||
|
|
@ -75,6 +75,9 @@ type TxPool struct {
|
|||
term chan struct{} // Termination channel to detect a closed pool
|
||||
|
||||
sync chan chan error // Testing / simulator channel to block until internal reset is done
|
||||
|
||||
headLock sync.RWMutex
|
||||
head *types.Header // this reflects the state from the latest pool reset
|
||||
}
|
||||
|
||||
// New creates a new transaction pool to gather, sort and filter inbound
|
||||
|
|
@ -103,6 +106,7 @@ func New(gasTip uint64, chain BlockChain, subpools []SubPool) (*TxPool, error) {
|
|||
quit: make(chan chan error),
|
||||
term: make(chan struct{}),
|
||||
sync: make(chan chan error),
|
||||
head: head,
|
||||
}
|
||||
reserver := NewReservationTracker()
|
||||
for i, subpool := range subpools {
|
||||
|
|
@ -202,6 +206,9 @@ func (p *TxPool) loop(head *types.Header) {
|
|||
}
|
||||
select {
|
||||
case resetDone <- newHead:
|
||||
p.headLock.Lock()
|
||||
p.head = newHead
|
||||
p.headLock.Unlock()
|
||||
case <-p.term:
|
||||
}
|
||||
}(oldHead, newHead)
|
||||
|
|
@ -256,6 +263,14 @@ func (p *TxPool) loop(head *types.Header) {
|
|||
errc <- nil
|
||||
}
|
||||
|
||||
// Head returns the header which corresponds to the most recent successful pool
|
||||
// reset.
|
||||
func (p *TxPool) Head() *types.Header {
|
||||
p.headLock.RLock()
|
||||
defer p.headLock.RUnlock()
|
||||
return types.CopyHeader(p.head)
|
||||
}
|
||||
|
||||
// SetGasTip updates the minimum gas tip required by the transaction pool for a
|
||||
// new transaction, and drops all transactions below this threshold.
|
||||
func (p *TxPool) SetGasTip(tip *big.Int) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
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("transaction gas exceeded max allowed (%d): %d", params.MaxTxGas, tx.Gas())
|
||||
}
|
||||
// Transactions can't be negative. This may never happen using RLP decoded
|
||||
// transactions but may occur for transactions created using the RPC.
|
||||
if tx.Value().Sign() < 0 {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ type environment struct {
|
|||
sidecars []*types.BlobTxSidecar
|
||||
blobs int
|
||||
|
||||
witness *stateless.Witness
|
||||
witness *stateless.Witness
|
||||
chainConfig *params.ChainConfig
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
@ -254,12 +255,13 @@ func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase
|
|||
}
|
||||
// Note the passed coinbase may be different with header.Coinbase.
|
||||
return &environment{
|
||||
signer: types.MakeSigner(miner.chainConfig, header.Number, header.Time),
|
||||
state: state,
|
||||
coinbase: coinbase,
|
||||
header: header,
|
||||
witness: state.Witness(),
|
||||
evm: vm.NewEVM(core.NewEVMBlockContext(header, miner.chain, &coinbase), state, miner.chainConfig, vm.Config{}),
|
||||
signer: types.MakeSigner(miner.chainConfig, header.Number, header.Time),
|
||||
state: state,
|
||||
coinbase: coinbase,
|
||||
header: header,
|
||||
witness: state.Witness(),
|
||||
evm: vm.NewEVM(core.NewEVMBlockContext(header, miner.chain, &coinbase), state, miner.chainConfig, vm.Config{}),
|
||||
chainConfig: miner.chainConfig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -443,6 +445,23 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
|
|||
return nil
|
||||
}
|
||||
|
||||
// fiterTxsAboveGas removes any transactions from the set which exceed a gas threshold.
|
||||
// If a transaction is removed, all higher-nonce transactions from the same account
|
||||
// will also be filtered out.
|
||||
func filterTxsAboveGas(txs map[common.Address][]*txpool.LazyTransaction, maxGas uint64) {
|
||||
for sender, senderTxs := range txs {
|
||||
for i, tx := range senderTxs {
|
||||
if tx.Gas > maxGas {
|
||||
if i == 0 {
|
||||
delete(txs, sender)
|
||||
} else {
|
||||
txs[sender] = txs[sender][:i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fillTransactions retrieves the pending transactions from the txpool and fills them
|
||||
// into the given sealing block. The transaction selection and ordering strategy can
|
||||
// be customized with the plugin in the future.
|
||||
|
|
@ -472,6 +491,16 @@ func (miner *Miner) fillTransactions(interrupt *atomic.Int32, env *environment)
|
|||
prioPlainTxs, normalPlainTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingPlainTxs
|
||||
prioBlobTxs, normalBlobTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingBlobTxs
|
||||
|
||||
// if we have just entered the Osaka fork, it is possible due to the async
|
||||
// nature of txpool resets that the state of the pool has not finished resetting
|
||||
// to a post-fork block. If so, it may not have removed txs that exceed the
|
||||
// eip-7825 transaction maximum gas limit.
|
||||
poolHead := miner.txpool.Head()
|
||||
if env.chainConfig.IsOsaka(env.header.Number, env.header.Time) && !env.chainConfig.IsOsaka(poolHead.Number, poolHead.Time) {
|
||||
filterTxsAboveGas(prioPlainTxs, params.MaxTxGas)
|
||||
filterTxsAboveGas(prioBlobTxs, params.MaxTxGas)
|
||||
}
|
||||
|
||||
for _, account := range prio {
|
||||
if txs := normalPlainTxs[account]; len(txs) > 0 {
|
||||
delete(normalPlainTxs, account)
|
||||
|
|
|
|||
|
|
@ -28,17 +28,18 @@ const (
|
|||
MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1).
|
||||
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
|
||||
|
||||
MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
|
||||
QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation.
|
||||
LogDataGas uint64 = 8 // Per byte in a LOG* operation's data.
|
||||
CallStipend uint64 = 2300 // Free gas given at beginning of call.
|
||||
MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis.
|
||||
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.
|
||||
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.
|
||||
TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions.
|
||||
MaxTxGas uint64 = 30_000_000 // eip-7825 maximum transaction gas limit
|
||||
TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
|
||||
TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
|
||||
QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation.
|
||||
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.
|
||||
Keccak256WordGas uint64 = 6 // Once per word of the KECCAK256 operation's data.
|
||||
|
|
|
|||
Loading…
Reference in a new issue