Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion consensus/clique/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func (api *API) Status() (*status, error) {
if h == nil {
return nil, fmt.Errorf("missing block %d", n)
}
if h.Difficulty.Cmp(diffInTurn) == 0 {
if h.Difficulty.Cmp(diffInTurnSenior) == 0 || h.Difficulty.Cmp(diffInTurnSubordinate) == 0 {
optimals++
}
diff += h.Difficulty.Uint64()
Expand Down
14 changes: 9 additions & 5 deletions consensus/clique/clique.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ var (

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
diffInTurnSenior = big.NewInt(7) // Block difficulty for in-turn signatures
diffInTurnSubordinate = big.NewInt(2) // Block difficulty for in-turn signatures
diffNoTurn = big.NewInt(1) // Block difficulty for out-of-turn signatures

blockSizeGaugeName = "clique/block_size_in_bytes"
gasUsedInBlock = "clique/gas_used_in_block"
Expand Down Expand Up @@ -296,7 +297,7 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
}
// Ensure that the block's difficulty is meaningful (may not be correct at this point)
if number > 0 {
if header.Difficulty == nil || (header.Difficulty.Cmp(diffInTurn) != 0 && header.Difficulty.Cmp(diffNoTurn) != 0) {
if header.Difficulty == nil || (header.Difficulty.Cmp(diffInTurnSenior) != 0 && header.Difficulty.Cmp(diffInTurnSenior) != 0 && header.Difficulty.Cmp(diffInTurnSubordinate) != 0) {
return errInvalidDifficulty
}
}
Expand Down Expand Up @@ -505,7 +506,7 @@ func (c *Clique) verifySeal(snap *Snapshot, header *types.Header, parents []*typ
// Ensure that the difficulty corresponds to the turn-ness of the signer
if !c.fakeDiff {
inturn := snap.inturn(header.Number.Uint64(), signer)
if inturn && header.Difficulty.Cmp(diffInTurn) != 0 {
if inturn && (header.Difficulty.Cmp(diffInTurnSenior) != 0 || header.Difficulty.Cmp(diffInTurnSubordinate) != 0) {
return errWrongDifficulty
}
if !inturn && header.Difficulty.Cmp(diffNoTurn) != 0 {
Expand Down Expand Up @@ -710,7 +711,10 @@ func (c *Clique) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64,

func calcDifficulty(snap *Snapshot, signer common.Address) *big.Int {
if snap.inturn(snap.Number+1, signer) {
return new(big.Int).Set(diffInTurn)
if snap.isSenior(signer) {
return new(big.Int).Set(diffInTurnSenior)
}
return new(big.Int).Set(diffInTurnSubordinate)
}
return new(big.Int).Set(diffNoTurn)
}
Expand Down
4 changes: 2 additions & 2 deletions consensus/clique/clique_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,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(diffInTurnSenior)

// 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.
Expand All @@ -79,7 +79,7 @@ func TestReimportMirroredState(t *testing.T) {
header.ParentHash = blocks[i-1].Hash()
}
header.Extra = make([]byte, extraVanity+extraSeal)
header.Difficulty = diffInTurn
header.Difficulty = diffInTurnSenior

sig, _ := crypto.Sign(SealHash(header).Bytes(), key)
copy(header.Extra[len(header.Extra)-extraSeal:], sig)
Expand Down
19 changes: 19 additions & 0 deletions consensus/clique/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package clique
import (
"bytes"
"encoding/json"
"sort"
"time"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -60,6 +61,7 @@ type Snapshot struct {
Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections
Votes []*Vote `json:"votes"` // List of votes cast in chronological order
Tally map[common.Address]Tally `json:"tally"` // Current vote tally to avoid recalculating
Seniors map[common.Address]struct{} `json:"seniors"` // Set of senior signers
}

// newSnapshot creates a new snapshot with the specified startup parameters. This
Expand All @@ -74,10 +76,21 @@ func newSnapshot(config *params.CliqueConfig, sigcache *sigLRU, number uint64, h
Signers: make(map[common.Address]struct{}),
Recents: make(map[uint64]common.Address),
Tally: make(map[common.Address]Tally),
Seniors: make(map[common.Address]struct{}),
}
for _, signer := range signers {
snap.Signers[signer] = struct{}{}
}
sortedSigners := make([]common.Address, 0, len(snap.Signers))
for signer := range snap.Signers {
sortedSigners = append(sortedSigners, signer)
}
sort.Slice(sortedSigners, func(i, j int) bool {
return bytes.Compare(sortedSigners[i].Bytes(), sortedSigners[j].Bytes()) < 0
})
if len(sortedSigners) > 0 {
snap.Seniors[sortedSigners[0]] = struct{}{}
}
return snap
}

Expand Down Expand Up @@ -312,6 +325,12 @@ func (s *Snapshot) signers() []common.Address {
return sigs
}

// isSenior checks if the given address is a senior signer.
func (s *Snapshot) isSenior(address common.Address) bool {
_, senior := s.Seniors[address]
return senior
}

// inturn returns if a signer at a given block height is in-turn or not.
func (s *Snapshot) inturn(number uint64, signer common.Address) bool {
signers, offset := s.signers(), 0
Expand Down
2 changes: 1 addition & 1 deletion consensus/clique/snapshot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ func (tt *cliqueTest) run(t *testing.T) {
header.Extra = make([]byte, extraVanity+len(auths)*common.AddressLength+extraSeal)
accounts.checkpoint(header, auths)
}
header.Difficulty = diffInTurn // Ignored, we just need a valid number
header.Difficulty = diffInTurnSenior // Ignored, we just need a valid number

// Generate the signature, embed it into the header and the block
accounts.sign(header, tt.votes[j].signer)
Expand Down