mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-12 01:41:36 +00:00
consensus, core, internal, miner: remove FinalizeAndAssemble (#34726)
This PR removes `FinalizeAndAssemble` from the consensus engine interface and relocates block assembly logic outside of the consensus engine. Block assembly is consensus-agnostic. Most validations can be performed by the caller. For example: - Withdrawals must be nil prior to Shanghai - After Shanghai upgrade, withdrawals must be non-nil, even if empty. The only notable consensus-specific validation is related to uncles. In clique, the concept of uncles does not exist, and any block containing uncles should be considered invalid. Within the block production package, the policy is to produce blocks according to the latest chain specification. As a result, Clique-specific block production is no longer supported. This tradeoff is considered acceptable.
This commit is contained in:
parent
c374e74ee1
commit
d422ab39d5
8 changed files with 51 additions and 108 deletions
|
|
@ -17,7 +17,6 @@
|
|||
package beacon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
|
@ -26,13 +25,10 @@ import (
|
|||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/internal/telemetry"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
|
|
@ -361,48 +357,6 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.
|
|||
// No block reward which is issued by consensus layer instead.
|
||||
}
|
||||
|
||||
// FinalizeAndAssemble implements consensus.Engine, setting the final state and
|
||||
// assembling the block.
|
||||
func (beacon *Beacon) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (result *types.Block, err error) {
|
||||
ctx, _, spanEnd := telemetry.StartSpan(ctx, "consensus.beacon.FinalizeAndAssemble",
|
||||
telemetry.Int64Attribute("block.number", int64(header.Number.Uint64())),
|
||||
telemetry.Int64Attribute("txs.count", int64(len(body.Transactions))),
|
||||
telemetry.Int64Attribute("withdrawals.count", int64(len(body.Withdrawals))),
|
||||
)
|
||||
defer spanEnd(&err)
|
||||
|
||||
if !beacon.IsPoSHeader(header) {
|
||||
block, delegateErr := beacon.ethone.FinalizeAndAssemble(ctx, chain, header, state, body, receipts)
|
||||
return block, delegateErr
|
||||
}
|
||||
shanghai := chain.Config().IsShanghai(header.Number, header.Time)
|
||||
if shanghai {
|
||||
// All blocks after Shanghai must include a withdrawals root.
|
||||
if body.Withdrawals == nil {
|
||||
body.Withdrawals = make([]*types.Withdrawal, 0)
|
||||
}
|
||||
} else {
|
||||
if len(body.Withdrawals) > 0 {
|
||||
return nil, errors.New("withdrawals set before Shanghai activation")
|
||||
}
|
||||
}
|
||||
// Finalize and assemble the block.
|
||||
_, _, finalizeSpanEnd := telemetry.StartSpan(ctx, "consensus.beacon.Finalize")
|
||||
beacon.Finalize(chain, header, state, body)
|
||||
finalizeSpanEnd(nil)
|
||||
|
||||
// Assign the final state root to header.
|
||||
_, _, rootSpanEnd := telemetry.StartSpan(ctx, "consensus.beacon.IntermediateRoot")
|
||||
header.Root = state.IntermediateRoot(true)
|
||||
rootSpanEnd(nil)
|
||||
|
||||
// Assemble the final block.
|
||||
_, _, blockSpanEnd := telemetry.StartSpan(ctx, "consensus.beacon.NewBlock")
|
||||
block := types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
|
||||
blockSpanEnd(nil)
|
||||
return block, nil
|
||||
}
|
||||
|
||||
// Seal generates a new sealing request for the given input block and pushes
|
||||
// the result into the given channel.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package clique
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -34,7 +33,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -43,7 +41,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -580,22 +577,6 @@ func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
|
|||
// No block rewards in PoA, so the state remains as is
|
||||
}
|
||||
|
||||
// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
|
||||
// nor block rewards given, and returns the final block.
|
||||
func (c *Clique) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
|
||||
if len(body.Withdrawals) > 0 {
|
||||
return nil, errors.New("clique does not support withdrawals")
|
||||
}
|
||||
// Finalize block
|
||||
c.Finalize(chain, header, state, body)
|
||||
|
||||
// Assign the final state root to header.
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||
|
||||
// Assemble and return the final block for sealing.
|
||||
return types.NewBlock(header, &types.Body{Transactions: body.Transactions}, receipts, trie.NewStackTrie(nil)), nil
|
||||
}
|
||||
|
||||
// Authorize injects a private key into the consensus engine to mint new blocks
|
||||
// with.
|
||||
func (c *Clique) Authorize(signer common.Address) {
|
||||
|
|
|
|||
|
|
@ -18,11 +18,9 @@
|
|||
package consensus
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
|
@ -88,13 +86,6 @@ type Engine interface {
|
|||
// that happen at finalization (e.g. block rewards).
|
||||
Finalize(chain ChainHeaderReader, header *types.Header, state vm.StateDB, body *types.Body)
|
||||
|
||||
// FinalizeAndAssemble runs any post-transaction state modifications (e.g. block
|
||||
// rewards or process withdrawals) and assembles the final block.
|
||||
//
|
||||
// Note: The block header and state database might be updated to reflect any
|
||||
// consensus rules that happen at finalization (e.g. block rewards).
|
||||
FinalizeAndAssemble(ctx context.Context, chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error)
|
||||
|
||||
// Seal generates a new sealing request for the given input block and pushes
|
||||
// the result into the given channel.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
package ethash
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
|
@ -28,14 +27,12 @@ import (
|
|||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto/keccak"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
|
|
@ -512,22 +509,6 @@ func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.
|
|||
accumulateRewards(chain.Config(), state, header, body.Uncles)
|
||||
}
|
||||
|
||||
// FinalizeAndAssemble implements consensus.Engine, accumulating the block and
|
||||
// uncle rewards, setting the final state and assembling the block.
|
||||
func (ethash *Ethash) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
|
||||
if len(body.Withdrawals) > 0 {
|
||||
return nil, errors.New("ethash does not support withdrawals")
|
||||
}
|
||||
// Finalize block
|
||||
ethash.Finalize(chain, header, state, body)
|
||||
|
||||
// Assign the final state root to header.
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||
|
||||
// Header seems complete, assemble into a block and return
|
||||
return types.NewBlock(header, &types.Body{Transactions: body.Transactions, Uncles: body.Uncles}, receipts, trie.NewStackTrie(nil)), nil
|
||||
}
|
||||
|
||||
// SealHash returns the hash of a block prior to it being sealed.
|
||||
func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
|
||||
hasher := keccak.NewLegacyKeccak256()
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
|
|
@ -411,11 +410,22 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||
b.header.RequestsHash = &reqHash
|
||||
}
|
||||
|
||||
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals}
|
||||
block, err := b.engine.FinalizeAndAssemble(context.Background(), cm, b.header, statedb, &body, b.receipts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
body := types.Body{
|
||||
Transactions: b.txs,
|
||||
Uncles: b.uncles,
|
||||
Withdrawals: b.withdrawals,
|
||||
}
|
||||
if !config.IsShanghai(b.header.Number, b.header.Time) {
|
||||
if body.Withdrawals != nil {
|
||||
panic("unexpected withdrawal before shanghai")
|
||||
}
|
||||
} else {
|
||||
if body.Withdrawals == nil {
|
||||
body.Withdrawals = make([]*types.Withdrawal, 0)
|
||||
}
|
||||
}
|
||||
// Assemble the block for delivery.
|
||||
block := AssembleBlock(b.engine, cm, b.header, statedb, &body, b.receipts)
|
||||
|
||||
// Write state changes to db
|
||||
root, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number), config.IsCancun(b.header.Number, b.header.Time))
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
|
|
@ -30,6 +31,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/internal/telemetry"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
// StateProcessor is a basic Processor, which takes care of transitioning
|
||||
|
|
@ -372,3 +374,11 @@ func onSystemCallStart(tracer *tracing.Hooks, ctx *tracing.VMContext) {
|
|||
tracer.OnSystemCallStart()
|
||||
}
|
||||
}
|
||||
|
||||
// AssembleBlock finalizes the state and assembles the block with provided
|
||||
// body and receipts.
|
||||
func AssembleBlock(engine consensus.Engine, chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) *types.Block {
|
||||
engine.Finalize(chain, header, state, body)
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -416,13 +416,13 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
|||
|
||||
blockBody := &types.Body{
|
||||
Transactions: txes,
|
||||
Withdrawals: *block.BlockOverrides.Withdrawals,
|
||||
Withdrawals: *block.BlockOverrides.Withdrawals, // Withdrawal is also sanitized as non-nil
|
||||
}
|
||||
chainHeadReader := &simChainHeadReader{ctx, sim.b}
|
||||
b, err := sim.b.Engine().FinalizeAndAssemble(ctx, chainHeadReader, header, sim.state, blockBody, receipts)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Assemble the block
|
||||
b := core.AssembleBlock(sim.b.Engine(), chainHeadReader, header, sim.state, blockBody, receipts)
|
||||
|
||||
repairLogs(callResults, b.Hash())
|
||||
return b, callResults, senders, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,7 +183,21 @@ func (miner *Miner) generateWork(ctx context.Context, genParam *generateParams,
|
|||
}
|
||||
}
|
||||
}
|
||||
body := types.Body{Transactions: work.txs, Withdrawals: genParam.withdrawals}
|
||||
// Construct the block body, the withdrawal list should never be null
|
||||
// if Shanghai has been activated.
|
||||
body := types.Body{
|
||||
Transactions: work.txs,
|
||||
Withdrawals: genParam.withdrawals,
|
||||
}
|
||||
if !miner.chainConfig.IsShanghai(work.header.Number, work.header.Time) {
|
||||
if body.Withdrawals != nil {
|
||||
return &newPayloadResult{err: errors.New("unexpected withdrawals before shanghai")}
|
||||
}
|
||||
} else {
|
||||
if body.Withdrawals == nil {
|
||||
body.Withdrawals = make([]*types.Withdrawal, 0)
|
||||
}
|
||||
}
|
||||
|
||||
allLogs := make([]*types.Log, 0)
|
||||
for _, r := range work.receipts {
|
||||
|
|
@ -211,11 +225,11 @@ func (miner *Miner) generateWork(ctx context.Context, genParam *generateParams,
|
|||
reqHash := types.CalcRequestsHash(requests)
|
||||
work.header.RequestsHash = &reqHash
|
||||
}
|
||||
// Assemble the block for delivery.
|
||||
_, _, assembleSpanEnd := telemetry.StartSpan(ctx, "miner.AssembleBlock")
|
||||
block := core.AssembleBlock(miner.engine, miner.chain, work.header, work.state, &body, work.receipts)
|
||||
assembleSpanEnd(nil)
|
||||
|
||||
block, err := miner.engine.FinalizeAndAssemble(ctx, miner.chain, work.header, work.state, &body, work.receipts)
|
||||
if err != nil {
|
||||
return &newPayloadResult{err: err}
|
||||
}
|
||||
return &newPayloadResult{
|
||||
block: block,
|
||||
fees: totalFees(block, work.receipts),
|
||||
|
|
@ -413,6 +427,7 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*
|
|||
func (miner *Miner) commitTransactions(ctx context.Context, env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
||||
ctx, _, spanEnd := telemetry.StartSpan(ctx, "miner.commitTransactions")
|
||||
defer spanEnd(nil)
|
||||
|
||||
isCancun := miner.chainConfig.IsCancun(env.header.Number, env.header.Time)
|
||||
for {
|
||||
// Check interruption signal and abort building if it's fired.
|
||||
|
|
@ -529,6 +544,7 @@ func (miner *Miner) commitTransactions(ctx context.Context, env *environment, pl
|
|||
func (miner *Miner) fillTransactions(ctx context.Context, interrupt *atomic.Int32, env *environment) (err error) {
|
||||
ctx, span, spanEnd := telemetry.StartSpan(ctx, "miner.fillTransactions")
|
||||
defer spanEnd(&err)
|
||||
|
||||
miner.confMu.RLock()
|
||||
tip := miner.config.GasPrice
|
||||
prio := miner.prio
|
||||
|
|
|
|||
Loading…
Reference in a new issue