mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 05:36:46 +00:00
consensus/clique: partial port to config2
This commit is contained in:
parent
1a63295458
commit
215787789b
5 changed files with 79 additions and 41 deletions
|
|
@ -40,6 +40,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/params/forks"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
|
@ -51,20 +52,25 @@ const (
|
|||
inmemorySignatures = 4096 // Number of recent block signatures to keep in memory
|
||||
)
|
||||
|
||||
const (
|
||||
ExtraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
|
||||
ExtraSeal = crypto.SignatureLength // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||
|
||||
DiffInTurn = 2 // Block difficulty for in-turn signatures
|
||||
DiffNoTurn = 1 // Block difficulty for out-of-turn signatures
|
||||
)
|
||||
|
||||
// Clique proof-of-authority protocol constants.
|
||||
var (
|
||||
epochLength = uint64(30000) // Default number of blocks after which to checkpoint and reset the pending votes
|
||||
|
||||
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
|
||||
extraSeal = crypto.SignatureLength // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||
|
||||
nonceAuthVote = hexutil.MustDecode("0xffffffffffffffff") // Magic nonce number to vote on adding a new signer
|
||||
nonceDropVote = hexutil.MustDecode("0x0000000000000000") // Magic nonce number to vote on removing a signer.
|
||||
|
||||
uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.
|
||||
|
||||
diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures
|
||||
diffNoTurn = big.NewInt(1) // Block difficulty for out-of-turn signatures
|
||||
diffInTurn = big.NewInt(DiffInTurn)
|
||||
diffNoTurn = big.NewInt(DiffNoTurn)
|
||||
)
|
||||
|
||||
// Various error messages to mark blocks invalid. These should be private to
|
||||
|
|
@ -145,10 +151,10 @@ func ecrecover(header *types.Header, sigcache *sigLRU) (common.Address, error) {
|
|||
return address, nil
|
||||
}
|
||||
// Retrieve the signature from the header extra-data
|
||||
if len(header.Extra) < extraSeal {
|
||||
if len(header.Extra) < ExtraSeal {
|
||||
return common.Address{}, errMissingSignature
|
||||
}
|
||||
signature := header.Extra[len(header.Extra)-extraSeal:]
|
||||
signature := header.Extra[len(header.Extra)-ExtraSeal:]
|
||||
|
||||
// Recover the public key and the Ethereum address
|
||||
pubkey, err := crypto.Ecrecover(SealHash(header).Bytes(), signature)
|
||||
|
|
@ -165,7 +171,7 @@ func ecrecover(header *types.Header, sigcache *sigLRU) (common.Address, error) {
|
|||
// Clique is the proof-of-authority consensus engine proposed to support the
|
||||
// Ethereum testnet following the Ropsten attacks.
|
||||
type Clique struct {
|
||||
config *params.CliqueConfig // Consensus engine configuration parameters
|
||||
config *Config // Consensus engine configuration parameters
|
||||
db ethdb.Database // Database to store and retrieve snapshot checkpoints
|
||||
|
||||
recents *lru.Cache[common.Hash, *Snapshot] // Snapshots for recent block to speed up reorgs
|
||||
|
|
@ -182,18 +188,17 @@ type Clique struct {
|
|||
|
||||
// New creates a Clique proof-of-authority consensus engine with the initial
|
||||
// signers set to the ones provided by the user.
|
||||
func New(config *params.CliqueConfig, db ethdb.Database) *Clique {
|
||||
func New(config Config, db ethdb.Database) *Clique {
|
||||
// Set any missing consensus parameters to their defaults
|
||||
conf := *config
|
||||
if conf.Epoch == 0 {
|
||||
conf.Epoch = epochLength
|
||||
if config.Epoch == 0 {
|
||||
config.Epoch = epochLength
|
||||
}
|
||||
// Allocate the snapshot caches and create the engine
|
||||
recents := lru.NewCache[common.Hash, *Snapshot](inmemorySnapshots)
|
||||
signatures := lru.NewCache[common.Hash, common.Address](inmemorySignatures)
|
||||
|
||||
return &Clique{
|
||||
config: &conf,
|
||||
config: &config,
|
||||
db: db,
|
||||
recents: recents,
|
||||
signatures: signatures,
|
||||
|
|
@ -260,14 +265,14 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
|
|||
return errInvalidCheckpointVote
|
||||
}
|
||||
// Check that the extra-data contains both the vanity and signature
|
||||
if len(header.Extra) < extraVanity {
|
||||
if len(header.Extra) < ExtraVanity {
|
||||
return errMissingVanity
|
||||
}
|
||||
if len(header.Extra) < extraVanity+extraSeal {
|
||||
if len(header.Extra) < ExtraVanity+ExtraSeal {
|
||||
return errMissingSignature
|
||||
}
|
||||
// Ensure that the extra-data contains a signer list on checkpoint, but none otherwise
|
||||
signersBytes := len(header.Extra) - extraVanity - extraSeal
|
||||
signersBytes := len(header.Extra) - ExtraVanity - ExtraSeal
|
||||
if !checkpoint && signersBytes != 0 {
|
||||
return errExtraSigners
|
||||
}
|
||||
|
|
@ -292,14 +297,14 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
|
|||
if header.GasLimit > params.MaxGasLimit {
|
||||
return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit)
|
||||
}
|
||||
if chain.Config().IsShanghai(header.Number, header.Time) {
|
||||
if chain.Config().Active(forks.Shanghai, header.Number.Uint64(), header.Time) {
|
||||
return errors.New("clique does not support shanghai fork")
|
||||
}
|
||||
// Verify the non-existence of withdrawalsHash.
|
||||
if header.WithdrawalsHash != nil {
|
||||
return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
|
||||
}
|
||||
if chain.Config().IsCancun(header.Number, header.Time) {
|
||||
if chain.Config().Active(forks.Cancun, header.Number.Uint64(), header.Time) {
|
||||
return errors.New("clique does not support cancun fork")
|
||||
}
|
||||
// Verify the non-existence of cancun-specific header fields
|
||||
|
|
@ -342,7 +347,7 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainHeaderReader, header
|
|||
if header.GasUsed > header.GasLimit {
|
||||
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
|
||||
}
|
||||
if !chain.Config().IsLondon(header.Number) {
|
||||
if !chain.Config().Active(forks.London, header.Number.Uint64(), header.Time) {
|
||||
// Verify BaseFee not present before EIP-1559 fork.
|
||||
if header.BaseFee != nil {
|
||||
return fmt.Errorf("invalid baseFee before fork: have %d, want <nil>", header.BaseFee)
|
||||
|
|
@ -365,8 +370,8 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainHeaderReader, header
|
|||
for i, signer := range snap.signers() {
|
||||
copy(signers[i*common.AddressLength:], signer[:])
|
||||
}
|
||||
extraSuffix := len(header.Extra) - extraSeal
|
||||
if !bytes.Equal(header.Extra[extraVanity:extraSuffix], signers) {
|
||||
extraSuffix := len(header.Extra) - ExtraSeal
|
||||
if !bytes.Equal(header.Extra[ExtraVanity:extraSuffix], signers) {
|
||||
return errMismatchingCheckpointSigners
|
||||
}
|
||||
}
|
||||
|
|
@ -404,9 +409,9 @@ func (c *Clique) snapshot(chain consensus.ChainHeaderReader, number uint64, hash
|
|||
if checkpoint != nil {
|
||||
hash := checkpoint.Hash()
|
||||
|
||||
signers := make([]common.Address, (len(checkpoint.Extra)-extraVanity-extraSeal)/common.AddressLength)
|
||||
signers := make([]common.Address, (len(checkpoint.Extra)-ExtraVanity-ExtraSeal)/common.AddressLength)
|
||||
for i := 0; i < len(signers); i++ {
|
||||
copy(signers[i][:], checkpoint.Extra[extraVanity+i*common.AddressLength:])
|
||||
copy(signers[i][:], checkpoint.Extra[ExtraVanity+i*common.AddressLength:])
|
||||
}
|
||||
snap = newSnapshot(c.config, c.signatures, number, hash, signers)
|
||||
if err := snap.store(c.db); err != nil {
|
||||
|
|
@ -544,17 +549,17 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header
|
|||
header.Difficulty = calcDifficulty(snap, signer)
|
||||
|
||||
// Ensure the extra data has all its components
|
||||
if len(header.Extra) < extraVanity {
|
||||
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
|
||||
if len(header.Extra) < ExtraVanity {
|
||||
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, ExtraVanity-len(header.Extra))...)
|
||||
}
|
||||
header.Extra = header.Extra[:extraVanity]
|
||||
header.Extra = header.Extra[:ExtraVanity]
|
||||
|
||||
if number%c.config.Epoch == 0 {
|
||||
for _, signer := range snap.signers() {
|
||||
header.Extra = append(header.Extra, signer[:]...)
|
||||
}
|
||||
}
|
||||
header.Extra = append(header.Extra, make([]byte, extraSeal)...)
|
||||
header.Extra = append(header.Extra, make([]byte, ExtraSeal)...)
|
||||
|
||||
// Mix digest is reserved for now, set to empty
|
||||
header.MixDigest = common.Hash{}
|
||||
|
|
@ -587,7 +592,8 @@ func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
|
|||
c.Finalize(chain, header, state, body)
|
||||
|
||||
// Assign the final state root to header.
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||
deleteEmptyObjects := chain.Config().Active(forks.SpuriousDragon, header.Number.Uint64(), header.Time)
|
||||
header.Root = state.IntermediateRoot(deleteEmptyObjects)
|
||||
|
||||
// Assemble and return the final block for sealing.
|
||||
return types.NewBlock(header, &types.Body{Transactions: body.Transactions}, receipts, trie.NewStackTrie(nil)), nil
|
||||
|
|
|
|||
|
|
@ -14,13 +14,14 @@
|
|||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package clique
|
||||
package clique_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
|
@ -40,18 +41,19 @@ func TestReimportMirroredState(t *testing.T) {
|
|||
db = rawdb.NewMemoryDatabase()
|
||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
||||
engine = New(params.AllCliqueProtocolChanges.Clique, db)
|
||||
config = clique.ConfigParam.Get(presets.AllCliqueProtocolChanges)
|
||||
engine = clique.New(config, db)
|
||||
signer = new(types.HomesteadSigner)
|
||||
)
|
||||
genspec := &core.Genesis{
|
||||
Config: params.AllCliqueProtocolChanges,
|
||||
ExtraData: make([]byte, extraVanity+common.AddressLength+extraSeal),
|
||||
ExtraData: make([]byte, clique.ExtraVanity+common.AddressLength+clique.ExtraSeal),
|
||||
Alloc: map[common.Address]types.Account{
|
||||
addr: {Balance: big.NewInt(10000000000000000)},
|
||||
},
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
}
|
||||
copy(genspec.ExtraData[extraVanity:], addr[:])
|
||||
copy(genspec.ExtraData[clique.ExtraVanity:], addr[:])
|
||||
|
||||
// Generate a batch of blocks, each properly signed
|
||||
chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), genspec, engine, nil)
|
||||
|
|
@ -60,7 +62,7 @@ func TestReimportMirroredState(t *testing.T) {
|
|||
_, blocks, _ := core.GenerateChainWithGenesis(genspec, engine, 3, func(i int, block *core.BlockGen) {
|
||||
// The chain maker doesn't have access to a chain, so the difficulty will be
|
||||
// lets unset (nil). Set it here to the correct value.
|
||||
block.SetDifficulty(diffInTurn)
|
||||
block.SetDifficulty(big.NewInt(clique.DiffInTurn))
|
||||
|
||||
// We want to simulate an empty middle block, having the same state as the
|
||||
// first one. The last is needs a state change again to force a reorg.
|
||||
|
|
@ -80,7 +82,7 @@ func TestReimportMirroredState(t *testing.T) {
|
|||
header.Extra = make([]byte, extraVanity+extraSeal)
|
||||
header.Difficulty = diffInTurn
|
||||
|
||||
sig, _ := crypto.Sign(SealHash(header).Bytes(), key)
|
||||
sig, _ := crypto.Sign(clique.SealHash(header).Bytes(), key)
|
||||
copy(header.Extra[len(header.Extra)-extraSeal:], sig)
|
||||
blocks[i] = block.WithSeal(header)
|
||||
}
|
||||
|
|
|
|||
31
consensus/clique/config.go
Normal file
31
consensus/clique/config.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2025 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package clique
|
||||
|
||||
import "github.com/ethereum/go-ethereum/params"
|
||||
|
||||
var ConfigParam = params.Define(params.T[Config]{
|
||||
Name: "clique",
|
||||
Optional: true, // optional says
|
||||
Default: Config{},
|
||||
})
|
||||
|
||||
// Config is the consensus engine configs for proof-of-authority based sealing.
|
||||
type Config struct {
|
||||
Period uint64 `json:"period"` // Number of seconds between blocks to enforce
|
||||
Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint
|
||||
}
|
||||
|
|
@ -29,7 +29,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// Vote represents a single vote that an authorized signer made to modify the
|
||||
|
|
@ -52,7 +51,7 @@ type sigLRU = lru.Cache[common.Hash, common.Address]
|
|||
|
||||
// Snapshot is the state of the authorization voting at a given point in time.
|
||||
type Snapshot struct {
|
||||
config *params.CliqueConfig // Consensus engine parameters to fine tune behavior
|
||||
config *Config // Consensus engine parameters to fine tune behavior
|
||||
sigcache *sigLRU // Cache of recent block signatures to speed up ecrecover
|
||||
|
||||
Number uint64 `json:"number"` // Block number where the snapshot was created
|
||||
|
|
@ -66,7 +65,7 @@ type Snapshot struct {
|
|||
// newSnapshot creates a new snapshot with the specified startup parameters. This
|
||||
// method does not initialize the set of recent signers, so only ever use if for
|
||||
// the genesis block.
|
||||
func newSnapshot(config *params.CliqueConfig, sigcache *sigLRU, number uint64, hash common.Hash, signers []common.Address) *Snapshot {
|
||||
func newSnapshot(config *Config, sigcache *sigLRU, number uint64, hash common.Hash, signers []common.Address) *Snapshot {
|
||||
snap := &Snapshot{
|
||||
config: config,
|
||||
sigcache: sigcache,
|
||||
|
|
@ -83,7 +82,7 @@ func newSnapshot(config *params.CliqueConfig, sigcache *sigLRU, number uint64, h
|
|||
}
|
||||
|
||||
// loadSnapshot loads an existing snapshot from the database.
|
||||
func loadSnapshot(config *params.CliqueConfig, sigcache *sigLRU, db ethdb.Database, hash common.Hash) (*Snapshot, error) {
|
||||
func loadSnapshot(config *Config, sigcache *sigLRU, db ethdb.Database, hash common.Hash) (*Snapshot, error) {
|
||||
blob, err := db.Get(append(rawdb.CliqueSnapshotPrefix, hash[:]...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package clique
|
||||
package clique_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
|
|
|||
Loading…
Reference in a new issue