txpool: limit max gas when mining is enabled; (#2435)

This commit is contained in:
galaio 2024-05-09 15:54:31 +08:00 committed by GitHub
parent 901ea2e0d2
commit 7bc5a3353d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 58 additions and 0 deletions

@ -25,6 +25,8 @@ import (
"strings" "strings"
"time" "time"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
@ -456,6 +458,10 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon
// Set the gas price to the limits from the CLI and start mining // Set the gas price to the limits from the CLI and start mining
gasprice := flags.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) gasprice := flags.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
ethBackend.TxPool().SetGasTip(gasprice) ethBackend.TxPool().SetGasTip(gasprice)
gasCeil := ethBackend.Miner().GasCeil()
if gasCeil > params.SystemTxsGas {
ethBackend.TxPool().SetMaxGas(gasCeil - params.SystemTxsGas)
}
if err := ethBackend.StartMining(); err != nil { if err := ethBackend.StartMining(); err != nil {
utils.Fatalf("Failed to start mining: %v", err) utils.Fatalf("Failed to start mining: %v", err)
} }

@ -27,6 +27,7 @@ import (
"path/filepath" "path/filepath"
"sort" "sort"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -305,6 +306,7 @@ type BlobPool struct {
head *types.Header // Current head of the chain head *types.Header // Current head of the chain
state *state.StateDB // Current state at the head of the chain state *state.StateDB // Current state at the head of the chain
gasTip *uint256.Int // Currently accepted minimum gas tip gasTip *uint256.Int // Currently accepted minimum gas tip
maxGas atomic.Uint64 // Currently accepted max gas, it will be modified by MinerAPI
lookup map[common.Hash]uint64 // Lookup table mapping hashes to tx billy entries lookup map[common.Hash]uint64 // Lookup table mapping hashes to tx billy entries
index map[common.Address][]*blobTxMeta // Blob transactions grouped by accounts, sorted by nonce index map[common.Address][]*blobTxMeta // Blob transactions grouped by accounts, sorted by nonce
@ -1098,6 +1100,7 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error {
Accept: 1 << types.BlobTxType, Accept: 1 << types.BlobTxType,
MaxSize: txMaxSize, MaxSize: txMaxSize,
MinTip: p.gasTip.ToBig(), MinTip: p.gasTip.ToBig(),
MaxGas: p.GetMaxGas(),
} }
if err := txpool.ValidateTransaction(tx, p.head, p.signer, baseOpts); err != nil { if err := txpool.ValidateTransaction(tx, p.head, p.signer, baseOpts); err != nil {
return err return err
@ -1671,3 +1674,11 @@ func (p *BlobPool) Status(hash common.Hash) txpool.TxStatus {
} }
return txpool.TxStatusUnknown return txpool.TxStatusUnknown
} }
func (p *BlobPool) SetMaxGas(maxGas uint64) {
p.maxGas.Store(maxGas)
}
func (p *BlobPool) GetMaxGas() uint64 {
return p.maxGas.Load()
}

@ -219,6 +219,7 @@ type LegacyPool struct {
scope event.SubscriptionScope scope event.SubscriptionScope
signer types.Signer signer types.Signer
mu sync.RWMutex mu sync.RWMutex
maxGas atomic.Uint64 // Currently accepted max gas, it will be modified by MinerAPI
currentHead atomic.Pointer[types.Header] // Current head of the blockchain currentHead atomic.Pointer[types.Header] // Current head of the blockchain
currentState *state.StateDB // Current state in the blockchain head currentState *state.StateDB // Current state in the blockchain head
@ -670,6 +671,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro
1<<types.DynamicFeeTxType, 1<<types.DynamicFeeTxType,
MaxSize: txMaxSize, MaxSize: txMaxSize,
MinTip: pool.gasTip.Load().ToBig(), MinTip: pool.gasTip.Load().ToBig(),
MaxGas: pool.GetMaxGas(),
} }
if local { if local {
opts.MinTip = new(big.Int) opts.MinTip = new(big.Int)
@ -1769,6 +1771,14 @@ func (pool *LegacyPool) demoteUnexecutables() {
} }
} }
func (pool *LegacyPool) GetMaxGas() uint64 {
return pool.maxGas.Load()
}
func (pool *LegacyPool) SetMaxGas(maxGas uint64) {
pool.maxGas.Store(maxGas)
}
// addressByHeartbeat is an account address tagged with its last activity timestamp. // addressByHeartbeat is an account address tagged with its last activity timestamp.
type addressByHeartbeat struct { type addressByHeartbeat struct {
address common.Address address common.Address

@ -166,4 +166,7 @@ type SubPool interface {
// Status returns the known status (unknown/pending/queued) of a transaction // Status returns the known status (unknown/pending/queued) of a transaction
// identified by their hashes. // identified by their hashes.
Status(hash common.Hash) TxStatus Status(hash common.Hash) TxStatus
// SetMaxGas limit max acceptable tx gas when mine is enabled
SetMaxGas(maxGas uint64)
} }

@ -284,6 +284,12 @@ func (p *TxPool) SetGasTip(tip *big.Int) {
} }
} }
func (p *TxPool) SetMaxGas(gas uint64) {
for _, subpool := range p.subpools {
subpool.SetMaxGas(gas)
}
}
// Has returns an indicator whether the pool has a transaction cached with the // Has returns an indicator whether the pool has a transaction cached with the
// given hash. // given hash.
func (p *TxPool) Has(hash common.Hash) bool { func (p *TxPool) Has(hash common.Hash) bool {

@ -45,6 +45,7 @@ type ValidationOptions struct {
Accept uint8 // Bitmap of transaction types that should be accepted for the calling pool Accept uint8 // Bitmap of transaction types that should be accepted for the calling pool
MaxSize uint64 // Maximum size of a transaction that the caller can meaningfully handle MaxSize uint64 // Maximum size of a transaction that the caller can meaningfully handle
MinTip *big.Int // Minimum gas tip needed to allow a transaction into the caller pool MinTip *big.Int // Minimum gas tip needed to allow a transaction into the caller pool
MaxGas uint64 // Max acceptable transaction gas in the txpool
} }
// ValidateTransaction is a helper method to check whether a transaction is valid // ValidateTransaction is a helper method to check whether a transaction is valid
@ -86,6 +87,12 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
if head.GasLimit < tx.Gas() { if head.GasLimit < tx.Gas() {
return ErrGasLimit return ErrGasLimit
} }
// Ensure the transaction doesn't exceed the current miner max acceptable limit gas
if opts.MaxGas > 0 && opts.MaxGas < tx.Gas() {
return ErrGasLimit
}
// Sanity check for extremely large numbers (supported by RLP or RPC) // Sanity check for extremely large numbers (supported by RLP or RPC)
if tx.GasFeeCap().BitLen() > 256 { if tx.GasFeeCap().BitLen() > 256 {
return core.ErrFeeCapVeryHigh return core.ErrFeeCapVeryHigh

@ -20,6 +20,8 @@ import (
"math/big" "math/big"
"time" "time"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
) )
@ -71,6 +73,9 @@ func (api *MinerAPI) SetGasPrice(gasPrice hexutil.Big) bool {
// SetGasLimit sets the gaslimit to target towards during mining. // SetGasLimit sets the gaslimit to target towards during mining.
func (api *MinerAPI) SetGasLimit(gasLimit hexutil.Uint64) bool { func (api *MinerAPI) SetGasLimit(gasLimit hexutil.Uint64) bool {
api.e.Miner().SetGasCeil(uint64(gasLimit)) api.e.Miner().SetGasCeil(uint64(gasLimit))
if api.e.Miner().Mining() && uint64(gasLimit) > params.SystemTxsGas {
api.e.TxPool().SetMaxGas(uint64(gasLimit) - params.SystemTxsGas)
}
return true return true
} }

@ -295,3 +295,7 @@ func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscript
func (miner *Miner) BuildPayload(args *BuildPayloadArgs) (*Payload, error) { func (miner *Miner) BuildPayload(args *BuildPayloadArgs) (*Payload, error) {
return miner.worker.buildPayload(args) return miner.worker.buildPayload(args)
} }
func (miner *Miner) GasCeil() uint64 {
return miner.worker.getGasCeil()
}

@ -329,6 +329,12 @@ func (w *worker) setGasCeil(ceil uint64) {
w.config.GasCeil = ceil w.config.GasCeil = ceil
} }
func (w *worker) getGasCeil() uint64 {
w.mu.Lock()
defer w.mu.Unlock()
return w.config.GasCeil
}
// setExtra sets the content used to initialize the block extra field. // setExtra sets the content used to initialize the block extra field.
func (w *worker) setExtra(extra []byte) { func (w *worker) setExtra(extra []byte) {
w.mu.Lock() w.mu.Lock()