From e031a4305987ee156ab06c8c1d6d9a45b8b323f8 Mon Sep 17 00:00:00 2001 From: Kartik Chopra Date: Fri, 9 Aug 2024 13:44:06 -0400 Subject: [PATCH 1/2] feat: introduce different diff for senior --- consensus/clique/clique.go | 14 +++++++++----- consensus/clique/snapshot.go | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index ecf5be129ccf..f3b21d412aad 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -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" @@ -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 } } @@ -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 { @@ -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) } diff --git a/consensus/clique/snapshot.go b/consensus/clique/snapshot.go index a97115121b82..591f8f593ded 100644 --- a/consensus/clique/snapshot.go +++ b/consensus/clique/snapshot.go @@ -19,6 +19,7 @@ package clique import ( "bytes" "encoding/json" + "sort" "time" "github.com/ethereum/go-ethereum/common" @@ -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 @@ -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 } @@ -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 From dce87aafb2f64896ff17a411702058c3cfffb393 Mon Sep 17 00:00:00 2001 From: Kartik Chopra Date: Fri, 9 Aug 2024 14:03:41 -0400 Subject: [PATCH 2/2] fix: ensure no undefined vars --- consensus/clique/api.go | 2 +- consensus/clique/clique_test.go | 4 ++-- consensus/clique/snapshot_test.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/consensus/clique/api.go b/consensus/clique/api.go index 374b50692d80..cb7e226d4239 100644 --- a/consensus/clique/api.go +++ b/consensus/clique/api.go @@ -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() diff --git a/consensus/clique/clique_test.go b/consensus/clique/clique_test.go index 7cd5919c5eaa..d423f3409ee8 100644 --- a/consensus/clique/clique_test.go +++ b/consensus/clique/clique_test.go @@ -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. @@ -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) diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 370b8f9b5417..f7f60ff308e2 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -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)