mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-04-23 01:52:23 +00:00
core,miner,params: implement EIP-7934 - RLP Execution Block Size Limit (#31990)
This commit is contained in:
parent
1505a025af
commit
ee882b0eaf
4 changed files with 62 additions and 7 deletions
|
|
@ -49,6 +49,10 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain) *Bloc
|
||||||
// header's transaction and uncle roots. The headers are assumed to be already
|
// header's transaction and uncle roots. The headers are assumed to be already
|
||||||
// validated at this point.
|
// validated at this point.
|
||||||
func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
|
// check EIP 7934 RLP-encoded block size cap
|
||||||
|
if v.config.IsOsaka(block.Number(), block.Time()) && block.Size() > params.BlockRLPSizeCap {
|
||||||
|
return ErrBlockOversized
|
||||||
|
}
|
||||||
// Check whether the block is already imported.
|
// Check whether the block is already imported.
|
||||||
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
|
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
|
||||||
return ErrKnownBlock
|
return ErrKnownBlock
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,10 @@ var (
|
||||||
|
|
||||||
// ErrNoGenesis is returned when there is no Genesis Block.
|
// ErrNoGenesis is returned when there is no Genesis Block.
|
||||||
ErrNoGenesis = errors.New("genesis not found in chain")
|
ErrNoGenesis = errors.New("genesis not found in chain")
|
||||||
|
|
||||||
|
// ErrBlockOversized is returned if the size of the RLP-encoded block
|
||||||
|
// exceeds the cap established by EIP 7934
|
||||||
|
ErrBlockOversized = errors.New("block RLP-encoded size exceeds maximum")
|
||||||
)
|
)
|
||||||
|
|
||||||
// List of evm-call-message pre-checking errors. All state transition messages will
|
// List of evm-call-message pre-checking errors. All state transition messages will
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ type environment struct {
|
||||||
signer types.Signer
|
signer types.Signer
|
||||||
state *state.StateDB // apply state changes here
|
state *state.StateDB // apply state changes here
|
||||||
tcount int // tx count in cycle
|
tcount int // tx count in cycle
|
||||||
|
size uint64 // size of the block we are building
|
||||||
gasPool *core.GasPool // available gas used to pack transactions
|
gasPool *core.GasPool // available gas used to pack transactions
|
||||||
coinbase common.Address
|
coinbase common.Address
|
||||||
evm *vm.EVM
|
evm *vm.EVM
|
||||||
|
|
@ -69,6 +70,11 @@ const (
|
||||||
commitInterruptNewHead
|
commitInterruptNewHead
|
||||||
commitInterruptResubmit
|
commitInterruptResubmit
|
||||||
commitInterruptTimeout
|
commitInterruptTimeout
|
||||||
|
|
||||||
|
// cap the size of blocks we will produce below the max allowed by
|
||||||
|
// EIP-7934. This gives us buffer room if the estimated size of the
|
||||||
|
// block we are building is off from the actual encoded size.
|
||||||
|
blockRLPSizeCapBuffer = 1_000_000
|
||||||
)
|
)
|
||||||
|
|
||||||
// newPayloadResult is the result of payload generation.
|
// newPayloadResult is the result of payload generation.
|
||||||
|
|
@ -96,12 +102,37 @@ type generateParams struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateWork generates a sealing block based on the given parameters.
|
// generateWork generates a sealing block based on the given parameters.
|
||||||
func (miner *Miner) generateWork(params *generateParams, witness bool) *newPayloadResult {
|
func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPayloadResult {
|
||||||
work, err := miner.prepareWork(params, witness)
|
work, err := miner.prepareWork(genParam, witness)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &newPayloadResult{err: err}
|
return &newPayloadResult{err: err}
|
||||||
}
|
}
|
||||||
if !params.noTxs {
|
var includedWithdrawals types.Withdrawals
|
||||||
|
|
||||||
|
// If we are post-osaka, incorporate the requested withdrawals into the
|
||||||
|
// block size calculation up-front to ensure that all requested withdrawals
|
||||||
|
// can be included even if we hit the size cap when filling the block with
|
||||||
|
// txs.
|
||||||
|
//
|
||||||
|
// Also, ensure that including all requested withdrawals wouldn't bring us
|
||||||
|
// over the block size cap limit. The withdrawal cap ensures that this can't
|
||||||
|
// actually happen right now, but it doesn't hurt to make this code
|
||||||
|
// future-proof for a situation where the withdrawal cap is lifted.
|
||||||
|
if miner.chainConfig.IsOsaka(work.header.Number, work.header.Time) {
|
||||||
|
maxBlockSize := params.BlockRLPSizeCap - blockRLPSizeCapBuffer
|
||||||
|
|
||||||
|
for _, withdrawal := range genParam.withdrawals {
|
||||||
|
if int(work.size)+params.WithdrawalSize > maxBlockSize {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
work.size += params.WithdrawalSize
|
||||||
|
includedWithdrawals = append(includedWithdrawals, withdrawal)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
includedWithdrawals = genParam.withdrawals
|
||||||
|
}
|
||||||
|
|
||||||
|
if !genParam.noTxs {
|
||||||
interrupt := new(atomic.Int32)
|
interrupt := new(atomic.Int32)
|
||||||
timer := time.AfterFunc(miner.config.Recommit, func() {
|
timer := time.AfterFunc(miner.config.Recommit, func() {
|
||||||
interrupt.Store(commitInterruptTimeout)
|
interrupt.Store(commitInterruptTimeout)
|
||||||
|
|
@ -113,8 +144,8 @@ func (miner *Miner) generateWork(params *generateParams, witness bool) *newPaylo
|
||||||
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit))
|
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
body := types.Body{Transactions: work.txs, Withdrawals: includedWithdrawals}
|
||||||
|
|
||||||
body := types.Body{Transactions: work.txs, Withdrawals: params.withdrawals}
|
|
||||||
allLogs := make([]*types.Log, 0)
|
allLogs := make([]*types.Log, 0)
|
||||||
for _, r := range work.receipts {
|
for _, r := range work.receipts {
|
||||||
allLogs = append(allLogs, r.Logs...)
|
allLogs = append(allLogs, r.Logs...)
|
||||||
|
|
@ -262,6 +293,7 @@ func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase
|
||||||
witness: state.Witness(),
|
witness: state.Witness(),
|
||||||
evm: vm.NewEVM(core.NewEVMBlockContext(header, miner.chain, &coinbase), state, miner.chainConfig, vm.Config{}),
|
evm: vm.NewEVM(core.NewEVMBlockContext(header, miner.chain, &coinbase), state, miner.chainConfig, vm.Config{}),
|
||||||
chainConfig: miner.chainConfig,
|
chainConfig: miner.chainConfig,
|
||||||
|
size: uint64(header.Size()),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,6 +307,7 @@ func (miner *Miner) commitTransaction(env *environment, tx *types.Transaction) e
|
||||||
}
|
}
|
||||||
env.txs = append(env.txs, tx)
|
env.txs = append(env.txs, tx)
|
||||||
env.receipts = append(env.receipts, receipt)
|
env.receipts = append(env.receipts, receipt)
|
||||||
|
env.size += tx.Size()
|
||||||
env.tcount++
|
env.tcount++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -300,6 +333,7 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio
|
||||||
env.receipts = append(env.receipts, receipt)
|
env.receipts = append(env.receipts, receipt)
|
||||||
env.sidecars = append(env.sidecars, sc)
|
env.sidecars = append(env.sidecars, sc)
|
||||||
env.blobs += len(sc.Blobs)
|
env.blobs += len(sc.Blobs)
|
||||||
|
env.size += tx.WithoutBlobTxSidecar().Size()
|
||||||
*env.header.BlobGasUsed += receipt.BlobGasUsed
|
*env.header.BlobGasUsed += receipt.BlobGasUsed
|
||||||
env.tcount++
|
env.tcount++
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -320,7 +354,11 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
||||||
gasLimit := env.header.GasLimit
|
var (
|
||||||
|
isOsaka = miner.chainConfig.IsOsaka(env.header.Number, env.header.Time)
|
||||||
|
isCancun = miner.chainConfig.IsCancun(env.header.Number, env.header.Time)
|
||||||
|
gasLimit = env.header.GasLimit
|
||||||
|
)
|
||||||
if env.gasPool == nil {
|
if env.gasPool == nil {
|
||||||
env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
||||||
}
|
}
|
||||||
|
|
@ -376,7 +414,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
|
||||||
// Most of the blob gas logic here is agnostic as to if the chain supports
|
// Most of the blob gas logic here is agnostic as to if the chain supports
|
||||||
// blobs or not, however the max check panics when called on a chain without
|
// blobs or not, however the max check panics when called on a chain without
|
||||||
// a defined schedule, so we need to verify it's safe to call.
|
// a defined schedule, so we need to verify it's safe to call.
|
||||||
if miner.chainConfig.IsCancun(env.header.Number, env.header.Time) {
|
if isCancun {
|
||||||
left := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) - env.blobs
|
left := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) - env.blobs
|
||||||
if left < int(ltx.BlobGas/params.BlobTxBlobGasPerBlob) {
|
if left < int(ltx.BlobGas/params.BlobTxBlobGasPerBlob) {
|
||||||
log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas/params.BlobTxBlobGasPerBlob)
|
log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas/params.BlobTxBlobGasPerBlob)
|
||||||
|
|
@ -393,8 +431,14 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if inclusion of the transaction would put the block size over the
|
||||||
|
// maximum we allow, don't add any more txs to the payload.
|
||||||
|
if isOsaka && env.size+tx.Size() > params.BlockRLPSizeCap-blockRLPSizeCapBuffer {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure all transactions after osaka have cell proofs
|
// Make sure all transactions after osaka have cell proofs
|
||||||
if miner.chainConfig.IsOsaka(env.header.Number, env.header.Time) {
|
if isOsaka {
|
||||||
if sidecar := tx.BlobTxSidecar(); sidecar != nil {
|
if sidecar := tx.BlobTxSidecar(); sidecar != nil {
|
||||||
if sidecar.Version == 0 {
|
if sidecar.Version == 0 {
|
||||||
log.Info("Including blob tx with v0 sidecar, recomputing proofs", "hash", ltx.Hash)
|
log.Info("Including blob tx with v0 sidecar, recomputing proofs", "hash", ltx.Hash)
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,9 @@ const (
|
||||||
BlobBaseCost = 1 << 14 // Base execution gas cost for a blob.
|
BlobBaseCost = 1 << 14 // Base execution gas cost for a blob.
|
||||||
|
|
||||||
HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.
|
HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.
|
||||||
|
|
||||||
|
WithdrawalSize = 23 // size of a withdrawal
|
||||||
|
BlockRLPSizeCap = 9_961_472 // maximum size of an RLP-encoded block
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bls12381G1MultiExpDiscountTable is the gas discount table for BLS12-381 G1 multi exponentiation operation
|
// Bls12381G1MultiExpDiscountTable is the gas discount table for BLS12-381 G1 multi exponentiation operation
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue