From 93cb8b9c94e4fad2015b8765ba2fd886be536c5e Mon Sep 17 00:00:00 2001 From: battlmonstr Date: Wed, 10 Jan 2024 17:09:38 +0100 Subject: [PATCH] bor: remove duplicate validator_set file and debug logger --- cmd/devnet/services/polygon/heimdall.go | 4 +- eth/stagedsync/stagedsynctest/harness.go | 6 +- polygon/bor/bor.go | 2 +- polygon/bor/bor_test.go | 4 +- polygon/bor/snapshot.go | 4 +- polygon/bor/snapshot_test.go | 16 +- polygon/bor/valset/validator_set.go | 40 +- polygon/sync/difficulty.go | 10 +- polygon/sync/difficulty_test.go | 2 +- turbo/jsonrpc/bor_helper.go | 2 + turbo/jsonrpc/bor_snapshot.go | 2 +- turbo/jsonrpc/validator_set.go | 704 ----------------------- 12 files changed, 43 insertions(+), 753 deletions(-) delete mode 100644 turbo/jsonrpc/validator_set.go diff --git a/cmd/devnet/services/polygon/heimdall.go b/cmd/devnet/services/polygon/heimdall.go index 8e00cecd414..81426a68e52 100644 --- a/cmd/devnet/services/polygon/heimdall.go +++ b/cmd/devnet/services/polygon/heimdall.go @@ -357,7 +357,7 @@ func (h *Heimdall) addValidator(validatorAddress libcommon.Address, votingPower VotingPower: votingPower, ProposerPriority: proposerPriority, }, - }, h.logger) + }) } else { h.validatorSet.UpdateWithChangeSet([]*valset.Validator{ { @@ -366,7 +366,7 @@ func (h *Heimdall) addValidator(validatorAddress libcommon.Address, votingPower VotingPower: votingPower, ProposerPriority: proposerPriority, }, - }, h.logger) + }) } } diff --git a/eth/stagedsync/stagedsynctest/harness.go b/eth/stagedsync/stagedsynctest/harness.go index 76fddead0be..a2b6169999c 100644 --- a/eth/stagedsync/stagedsynctest/harness.go +++ b/eth/stagedsync/stagedsynctest/harness.go @@ -109,7 +109,7 @@ func InitHarness(ctx context.Context, t *testing.T, cfg HarnessCfg) Harness { } if cfg.ChainConfig.Bor != nil { - h.setHeimdallNextMockSpan(logger) + h.setHeimdallNextMockSpan() h.mockBorSpanner() h.mockHeimdallClient() } @@ -501,7 +501,7 @@ func (h *Harness) mockChainHeaderReader(ctrl *gomock.Controller) consensus.Chain return mockChainHR } -func (h *Harness) setHeimdallNextMockSpan(logger log.Logger) { +func (h *Harness) setHeimdallNextMockSpan() { validators := []*valset.Validator{ { ID: 1, @@ -511,7 +511,7 @@ func (h *Harness) setHeimdallNextMockSpan(logger log.Logger) { }, } - validatorSet := valset.NewValidatorSet(validators, logger) + validatorSet := valset.NewValidatorSet(validators) selectedProducers := make([]valset.Validator, len(validators)) for i := range validators { selectedProducers[i] = *validators[i] diff --git a/polygon/bor/bor.go b/polygon/bor/bor.go index 2bdf64a04c6..9d96308d3c8 100644 --- a/polygon/bor/bor.go +++ b/polygon/bor/bor.go @@ -1496,7 +1496,7 @@ func getUpdatedValidatorSet(oldValidatorSet *valset.ValidatorSet, newVals []*val } } - if err := v.UpdateWithChangeSet(changes, logger); err != nil { + if err := v.UpdateWithChangeSet(changes); err != nil { logger.Error("[bor] Error while updating change set", "error", err) } diff --git a/polygon/bor/bor_test.go b/polygon/bor/bor_test.go index c1341fb0286..0c9f3c6d3f5 100644 --- a/polygon/bor/bor_test.go +++ b/polygon/bor/bor_test.go @@ -306,7 +306,7 @@ func newValidator(t *testing.T, heimdall *test_heimdall, blocks map[uint64]*type VotingPower: 1000, ProposerPriority: 1, }, - }, logger) + }) } else { heimdall.validatorSet.UpdateWithChangeSet([]*valset.Validator{ { @@ -315,7 +315,7 @@ func newValidator(t *testing.T, heimdall *test_heimdall, blocks map[uint64]*type VotingPower: 1000, ProposerPriority: 1, }, - }, logger) + }) } bor.Authorize(validatorAddress, func(_ libcommon.Address, mimeType string, message []byte) ([]byte, error) { diff --git a/polygon/bor/snapshot.go b/polygon/bor/snapshot.go index 7d055164807..cf4bbef43d1 100644 --- a/polygon/bor/snapshot.go +++ b/polygon/bor/snapshot.go @@ -51,7 +51,7 @@ func NewSnapshot( sigcache: sigcache, Number: number, Hash: hash, - ValidatorSet: valset.NewValidatorSet(validators, logger), + ValidatorSet: valset.NewValidatorSet(validators), Recents: make(map[uint64]common.Address), } return snap @@ -187,7 +187,7 @@ func (s *Snapshot) Apply(parent *types.Header, headers []*types.Header, logger l // get validators from headers and use that for new validator set newVals, _ := valset.ParseValidators(validatorBytes) v := getUpdatedValidatorSet(snap.ValidatorSet.Copy(), newVals, logger) - v.IncrementProposerPriority(1, logger) + v.IncrementProposerPriority(1) snap.ValidatorSet = v } diff --git a/polygon/bor/snapshot_test.go b/polygon/bor/snapshot_test.go index c5bdb215452..4a6d940328f 100644 --- a/polygon/bor/snapshot_test.go +++ b/polygon/bor/snapshot_test.go @@ -5,12 +5,12 @@ import ( "sort" "testing" + "github.com/maticnetwork/crand" + "github.com/stretchr/testify/require" + libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon/polygon/bor" "github.com/ledgerwatch/erigon/polygon/bor/valset" - "github.com/ledgerwatch/log/v3" - "github.com/maticnetwork/crand" - "github.com/stretchr/testify/require" ) const ( @@ -21,7 +21,7 @@ func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) { t.Parallel() validators := buildRandomValidatorSet(numVals) - validatorSet := valset.NewValidatorSet(validators, log.New()) + validatorSet := valset.NewValidatorSet(validators) snap := bor.Snapshot{ ValidatorSet: validatorSet, } @@ -49,7 +49,7 @@ func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) { // give highest ProposerPriority to a particular val, so that they become the proposer validators[proposerIndex].VotingPower = 200 snap := bor.Snapshot{ - ValidatorSet: valset.NewValidatorSet(validators, log.New()), + ValidatorSet: valset.NewValidatorSet(validators), } // choose a signer at an index greater than proposer index @@ -71,7 +71,7 @@ func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) { // give highest ProposerPriority to a particular val, so that they become the proposer validators[proposerIndex].VotingPower = 200 snap := bor.Snapshot{ - ValidatorSet: valset.NewValidatorSet(validators, log.New()), + ValidatorSet: valset.NewValidatorSet(validators), } // choose a signer at an index greater than proposer index @@ -89,7 +89,7 @@ func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) { validators := buildRandomValidatorSet(numVals) snap := bor.Snapshot{ - ValidatorSet: valset.NewValidatorSet(validators, log.New()), + ValidatorSet: valset.NewValidatorSet(validators), } dummyProposerAddress := randomAddress() @@ -111,7 +111,7 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) { validators := buildRandomValidatorSet(numVals) snap := bor.Snapshot{ - ValidatorSet: valset.NewValidatorSet(validators, log.New()), + ValidatorSet: valset.NewValidatorSet(validators), } dummySignerAddress := randomAddress() diff --git a/polygon/bor/valset/validator_set.go b/polygon/bor/valset/validator_set.go index 4f540dc8e1e..864bb132bed 100644 --- a/polygon/bor/valset/validator_set.go +++ b/polygon/bor/valset/validator_set.go @@ -11,8 +11,6 @@ import ( "sort" "strings" - "github.com/ledgerwatch/log/v3" - libcommon "github.com/ledgerwatch/erigon-lib/common" ) @@ -56,16 +54,16 @@ type ValidatorSet struct { // the new ValidatorSet will have an empty list of Validators. // The addresses of validators in `valz` must be unique otherwise the // function panics. -func NewValidatorSet(valz []*Validator, logger log.Logger) *ValidatorSet { +func NewValidatorSet(valz []*Validator) *ValidatorSet { vals := &ValidatorSet{} - err := vals.updateWithChangeSet(valz, false, logger) + err := vals.updateWithChangeSet(valz, false) if err != nil { panic(fmt.Sprintf("cannot create validator set: %s", err)) } if len(valz) > 0 { - vals.IncrementProposerPriority(1, logger) + vals.IncrementProposerPriority(1) } return vals @@ -77,9 +75,9 @@ func (vals *ValidatorSet) IsNilOrEmpty() bool { } // Increment ProposerPriority and update the proposer on a copy, and return it. -func (vals *ValidatorSet) CopyIncrementProposerPriority(times int, logger log.Logger) *ValidatorSet { +func (vals *ValidatorSet) CopyIncrementProposerPriority(times int) *ValidatorSet { validatorCopy := vals.Copy() - validatorCopy.IncrementProposerPriority(times, logger) + validatorCopy.IncrementProposerPriority(times) return validatorCopy } @@ -87,7 +85,7 @@ func (vals *ValidatorSet) CopyIncrementProposerPriority(times int, logger log.Lo // IncrementProposerPriority increments ProposerPriority of each validator and updates the // proposer. Panics if validator set is empty. // `times` must be positive. -func (vals *ValidatorSet) IncrementProposerPriority(times int, logger log.Logger) { +func (vals *ValidatorSet) IncrementProposerPriority(times int) { if vals.IsNilOrEmpty() { panic("empty validator set") } @@ -99,14 +97,14 @@ func (vals *ValidatorSet) IncrementProposerPriority(times int, logger log.Logger // Cap the difference between priorities to be proportional to 2*totalPower by // re-normalizing priorities, i.e., rescale all priorities by multiplying with: // 2*totalVotingPower/(maxPriority - minPriority) - diffMax := PriorityWindowSizeFactor * vals.TotalVotingPower(logger) + diffMax := PriorityWindowSizeFactor * vals.TotalVotingPower() vals.RescalePriorities(diffMax) vals.shiftByAvgProposerPriority() var proposer *Validator // Call IncrementProposerPriority(1) times times. for i := 0; i < times; i++ { - proposer = vals.incrementProposerPriority(logger) + proposer = vals.incrementProposerPriority() } vals.Proposer = proposer @@ -136,7 +134,7 @@ func (vals *ValidatorSet) RescalePriorities(diffMax int64) { } } -func (vals *ValidatorSet) incrementProposerPriority(logger log.Logger) *Validator { +func (vals *ValidatorSet) incrementProposerPriority() *Validator { for _, val := range vals.Validators { // Check for overflow for sum. newPrio := safeAddClip(val.ProposerPriority, val.VotingPower) @@ -145,7 +143,7 @@ func (vals *ValidatorSet) incrementProposerPriority(logger log.Logger) *Validato // Decrement the validator with most ProposerPriority. mostest := vals.getValWithMostPriority() // Mind the underflow. - mostest.ProposerPriority = safeSubClip(mostest.ProposerPriority, vals.TotalVotingPower(logger)) + mostest.ProposerPriority = safeSubClip(mostest.ProposerPriority, vals.TotalVotingPower()) return mostest } @@ -305,10 +303,8 @@ func (vals *ValidatorSet) UpdateTotalVotingPower() error { // TotalVotingPower returns the sum of the voting powers of all validators. // It recomputes the total voting power if required. -func (vals *ValidatorSet) TotalVotingPower(logger log.Logger) int64 { +func (vals *ValidatorSet) TotalVotingPower() int64 { if vals.totalVotingPower == 0 { - logger.Info("invoking updateTotalVotingPower before returning it") - if err := vals.UpdateTotalVotingPower(); err != nil { // Can/should we do better? panic(err) @@ -429,8 +425,8 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e // 'updates' should be a list of proper validator changes, i.e. they have been verified // by processChanges for duplicates and invalid values. // No changes are made to the validator set 'vals'. -func verifyUpdates(updates []*Validator, vals *ValidatorSet, logger log.Logger) (updatedTotalVotingPower int64, numNewValidators int, err error) { - updatedTotalVotingPower = vals.TotalVotingPower(logger) +func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVotingPower int64, numNewValidators int, err error) { + updatedTotalVotingPower = vals.TotalVotingPower() for _, valUpdate := range updates { address := valUpdate.Address @@ -578,7 +574,7 @@ func (vals *ValidatorSet) applyRemovals(deletes []*Validator) { // If 'allowDeletes' is false then delete operations (identified by validators with voting power 0) // are not allowed and will trigger an error if present in 'changes'. // The 'allowDeletes' flag is set to false by NewValidatorSet() and to true by UpdateWithChangeSet(). -func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes bool, logger log.Logger) error { +func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes bool) error { if len(changes) < 1 { return nil } @@ -599,7 +595,7 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes } // Verify that applying the 'updates' against 'vals' will not result in error. - updatedTotalVotingPower, numNewValidators, err := verifyUpdates(updates, vals, logger) + updatedTotalVotingPower, numNewValidators, err := verifyUpdates(updates, vals) if err != nil { return err } @@ -620,7 +616,7 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes } // Scale and center. - vals.RescalePriorities(PriorityWindowSizeFactor * vals.TotalVotingPower(logger)) + vals.RescalePriorities(PriorityWindowSizeFactor * vals.TotalVotingPower()) vals.shiftByAvgProposerPriority() return nil @@ -654,8 +650,8 @@ func (vals *ValidatorSet) UpdateValidatorMap() { // // If an error is detected during verification steps, it is returned and the validator set // is not changed. -func (vals *ValidatorSet) UpdateWithChangeSet(changes []*Validator, logger log.Logger) error { - return vals.updateWithChangeSet(changes, true, logger) +func (vals *ValidatorSet) UpdateWithChangeSet(changes []*Validator) error { + return vals.updateWithChangeSet(changes, true) } // Difficulty returns the difficulty for a particular signer at the current snapshot number diff --git a/polygon/sync/difficulty.go b/polygon/sync/difficulty.go index 74ec83958ec..6717df0064e 100644 --- a/polygon/sync/difficulty.go +++ b/polygon/sync/difficulty.go @@ -25,13 +25,11 @@ type difficultyCalculatorImpl struct { span *heimdallspan.HeimdallSpan validatorSetFactory func() validatorSetInterface signaturesCache *lru.ARCCache[libcommon.Hash, libcommon.Address] - - log log.Logger } // valset.ValidatorSet abstraction for unit tests type validatorSetInterface interface { - IncrementProposerPriority(times int, logger log.Logger) + IncrementProposerPriority(times int) Difficulty(signer libcommon.Address) (uint64, error) } @@ -50,8 +48,6 @@ func NewDifficultyCalculator( span: span, validatorSetFactory: validatorSetFactory, signaturesCache: signaturesCache, - - log: log, } if validatorSetFactory == nil { @@ -62,7 +58,7 @@ func NewDifficultyCalculator( } func (impl *difficultyCalculatorImpl) makeValidatorSet() validatorSetInterface { - return valset.NewValidatorSet(impl.span.ValidatorSet.Validators, impl.log) + return valset.NewValidatorSet(impl.span.ValidatorSet.Validators) } func (impl *difficultyCalculatorImpl) SetSpan(span *heimdallspan.HeimdallSpan) { @@ -82,7 +78,7 @@ func (impl *difficultyCalculatorImpl) signerDifficulty(signer libcommon.Address, sprintNum := impl.borConfig.CalculateSprintNumber(headerNum) if sprintNum > 0 { - validatorSet.IncrementProposerPriority(int(sprintNum), impl.log) + validatorSet.IncrementProposerPriority(int(sprintNum)) } return validatorSet.Difficulty(signer) diff --git a/polygon/sync/difficulty_test.go b/polygon/sync/difficulty_test.go index 11d4639524d..9a0a184b5fb 100644 --- a/polygon/sync/difficulty_test.go +++ b/polygon/sync/difficulty_test.go @@ -20,7 +20,7 @@ type testValidatorSetInterface struct { sprintNum int } -func (v *testValidatorSetInterface) IncrementProposerPriority(times int, _ log.Logger) { +func (v *testValidatorSetInterface) IncrementProposerPriority(times int) { v.sprintNum = times } diff --git a/turbo/jsonrpc/bor_helper.go b/turbo/jsonrpc/bor_helper.go index dd9ef47d574..db0ad4ea60b 100644 --- a/turbo/jsonrpc/bor_helper.go +++ b/turbo/jsonrpc/bor_helper.go @@ -117,6 +117,8 @@ func validatorContains(a []*valset.Validator, x *valset.Validator) (*valset.Vali return nil, false } +type ValidatorSet = valset.ValidatorSet + // getUpdatedValidatorSet applies changes to a validator set and returns a new validator set func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*valset.Validator) *ValidatorSet { v := oldValidatorSet diff --git a/turbo/jsonrpc/bor_snapshot.go b/turbo/jsonrpc/bor_snapshot.go index 0b41a8117a3..f92d6153a44 100644 --- a/turbo/jsonrpc/bor_snapshot.go +++ b/turbo/jsonrpc/bor_snapshot.go @@ -539,7 +539,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { } // check if signer is in validator set - if !snap.ValidatorSet.HasAddress(signer.Bytes()) { + if !snap.ValidatorSet.HasAddress(signer) { return nil, &bor.UnauthorizedSignerError{Number: number, Signer: signer.Bytes()} } diff --git a/turbo/jsonrpc/validator_set.go b/turbo/jsonrpc/validator_set.go deleted file mode 100644 index 7f4ddf735b8..00000000000 --- a/turbo/jsonrpc/validator_set.go +++ /dev/null @@ -1,704 +0,0 @@ -package jsonrpc - -// Tendermint leader selection algorithm - -import ( - "bytes" - "fmt" - "math" - "math/big" - "sort" - "strings" - - libcommon "github.com/ledgerwatch/erigon-lib/common" - "github.com/ledgerwatch/log/v3" - - "github.com/ledgerwatch/erigon/polygon/bor/valset" -) - -// MaxTotalVotingPower - the maximum allowed total voting power. -// It needs to be sufficiently small to, in all cases: -// 1. prevent clipping in incrementProposerPriority() -// 2. let (diff+diffMax-1) not overflow in IncrementProposerPriority() -// (Proof of 1 is tricky, left to the reader). -// It could be higher, but this is sufficiently large for our purposes, -// and leaves room for defensive purposes. -// PriorityWindowSizeFactor - is a constant that when multiplied with the total voting power gives -// the maximum allowed distance between validator priorities. - -const ( - MaxTotalVotingPower = int64(math.MaxInt64) / 8 - PriorityWindowSizeFactor = 2 -) - -// ValidatorSet represent a set of *Validator at a given height. -// The validators can be fetched by address or index. -// The index is in order of .Address, so the indices are fixed -// for all rounds of a given blockchain height - ie. the validators -// are sorted by their address. -// On the other hand, the .ProposerPriority of each validator and -// the designated .GetProposer() of a set changes every round, -// upon calling .IncrementProposerPriority(). -// NOTE: Not goroutine-safe. -// NOTE: All get/set to validators should copy the value for safety. -type ValidatorSet struct { - // NOTE: persisted via reflect, must be exported. - Validators []*valset.Validator `json:"validators"` - Proposer *valset.Validator `json:"proposer"` - - // cached (unexported) - totalVotingPower int64 -} - -// NewValidatorSet initializes a ValidatorSet by copying over the -// values from `valz`, a list of Validators. If valz is nil or empty, -// the new ValidatorSet will have an empty list of Validators. -// The addresses of validators in `valz` must be unique otherwise the -// function panics. -func NewValidatorSet(valz []*valset.Validator) *ValidatorSet { - vals := &ValidatorSet{} - err := vals.updateWithChangeSet(valz, false) - if err != nil { - panic(fmt.Sprintf("cannot create validator set: %s", err)) - } - if len(valz) > 0 { - vals.IncrementProposerPriority(1) - } - return vals -} - -// Nil or empty validator sets are invalid. -func (vals *ValidatorSet) IsNilOrEmpty() bool { - return vals == nil || len(vals.Validators) == 0 -} - -// Increment ProposerPriority and update the proposer on a copy, and return it. -func (vals *ValidatorSet) CopyIncrementProposerPriority(times int) *ValidatorSet { - copy := vals.Copy() - copy.IncrementProposerPriority(times) - return copy -} - -// IncrementProposerPriority increments ProposerPriority of each validator and updates the -// proposer. Panics if validator set is empty. -// `times` must be positive. -func (vals *ValidatorSet) IncrementProposerPriority(times int) { - if vals.IsNilOrEmpty() { - panic("empty validator set") - } - if times <= 0 { - panic("Cannot call IncrementProposerPriority with non-positive times") - } - - // Cap the difference between priorities to be proportional to 2*totalPower by - // re-normalizing priorities, i.e., rescale all priorities by multiplying with: - // 2*totalVotingPower/(maxPriority - minPriority) - diffMax := PriorityWindowSizeFactor * vals.TotalVotingPower() - vals.RescalePriorities(diffMax) - vals.shiftByAvgProposerPriority() - - var proposer *valset.Validator - // Call IncrementProposerPriority(1) times times. - for i := 0; i < times; i++ { - proposer = vals.incrementProposerPriority() - } - - vals.Proposer = proposer -} - -func (vals *ValidatorSet) RescalePriorities(diffMax int64) { - if vals.IsNilOrEmpty() { - panic("empty validator set") - } - // NOTE: This check is merely a sanity check which could be - // removed if all tests would init. voting power appropriately; - // i.e. diffMax should always be > 0 - if diffMax <= 0 { - return - } - - // Calculating ceil(diff/diffMax): - // Re-normalization is performed by dividing by an integer for simplicity. - // NOTE: This may make debugging priority issues easier as well. - diff := computeMaxMinPriorityDiff(vals) - ratio := (diff + diffMax - 1) / diffMax - if diff > diffMax { - for _, val := range vals.Validators { - val.ProposerPriority = val.ProposerPriority / ratio - } - } -} - -func (vals *ValidatorSet) incrementProposerPriority() *valset.Validator { - for _, val := range vals.Validators { - // Check for overflow for sum. - newPrio := safeAddClip(val.ProposerPriority, val.VotingPower) - val.ProposerPriority = newPrio - } - // Decrement the validator with most ProposerPriority. - mostest := vals.getValWithMostPriority() - // Mind the underflow. - mostest.ProposerPriority = safeSubClip(mostest.ProposerPriority, vals.TotalVotingPower()) - - return mostest -} - -// Should not be called on an empty validator set. -func (vals *ValidatorSet) computeAvgProposerPriority() int64 { - n := int64(len(vals.Validators)) - sum := big.NewInt(0) - for _, val := range vals.Validators { - sum.Add(sum, big.NewInt(val.ProposerPriority)) - } - avg := sum.Div(sum, big.NewInt(n)) - if avg.IsInt64() { - return avg.Int64() - } - - // This should never happen: each val.ProposerPriority is in bounds of int64. - panic(fmt.Sprintf("Cannot represent avg ProposerPriority as an int64 %v", avg)) -} - -// Compute the difference between the max and min ProposerPriority of that set. -func computeMaxMinPriorityDiff(vals *ValidatorSet) int64 { - if vals.IsNilOrEmpty() { - panic("empty validator set") - } - max := int64(math.MinInt64) - min := int64(math.MaxInt64) - for _, v := range vals.Validators { - if v.ProposerPriority < min { - min = v.ProposerPriority - } - if v.ProposerPriority > max { - max = v.ProposerPriority - } - } - diff := max - min - if diff < 0 { - return -1 * diff - } else { - return diff - } -} - -func (vals *ValidatorSet) getValWithMostPriority() *valset.Validator { - var res *valset.Validator - for _, val := range vals.Validators { - res = res.Cmp(val) - } - return res -} - -func (vals *ValidatorSet) shiftByAvgProposerPriority() { - if vals.IsNilOrEmpty() { - panic("empty validator set") - } - avgProposerPriority := vals.computeAvgProposerPriority() - for _, val := range vals.Validators { - val.ProposerPriority = safeSubClip(val.ProposerPriority, avgProposerPriority) - } -} - -// Makes a copy of the validator list. -func validatorListCopy(valsList []*valset.Validator) []*valset.Validator { - if valsList == nil { - return nil - } - valsCopy := make([]*valset.Validator, len(valsList)) - for i, val := range valsList { - valsCopy[i] = val.Copy() - } - return valsCopy -} - -// Copy each validator into a new ValidatorSet. -func (vals *ValidatorSet) Copy() *ValidatorSet { - return &ValidatorSet{ - Validators: validatorListCopy(vals.Validators), - Proposer: vals.Proposer, - totalVotingPower: vals.totalVotingPower, - } -} - -// HasAddress returns true if address given is in the validator set, false - -// otherwise. -func (vals *ValidatorSet) HasAddress(address []byte) bool { - idx := sort.Search(len(vals.Validators), func(i int) bool { - return bytes.Compare(address, vals.Validators[i].Address.Bytes()) <= 0 - }) - return idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address) -} - -// GetByAddress returns an index of the validator with address and validator -// itself if found. Otherwise, -1 and nil are returned. -func (vals *ValidatorSet) GetByAddress(address libcommon.Address) (index int, val *valset.Validator) { - idx := sort.Search(len(vals.Validators), func(i int) bool { - return bytes.Compare(address.Bytes(), vals.Validators[i].Address.Bytes()) <= 0 - }) - if idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address.Bytes()) { - return idx, vals.Validators[idx].Copy() - } - return -1, nil -} - -// GetByIndex returns the validator's address and validator itself by index. -// It returns nil values if index is less than 0 or greater or equal to -// len(ValidatorSet.Validators). -func (vals *ValidatorSet) GetByIndex(index int) (address []byte, val *valset.Validator) { - if index < 0 || index >= len(vals.Validators) { - return nil, nil - } - val = vals.Validators[index] - return val.Address.Bytes(), val.Copy() -} - -// Size returns the length of the validator set. -func (vals *ValidatorSet) Size() int { - return len(vals.Validators) -} - -// Force recalculation of the set's total voting power. -func (vals *ValidatorSet) UpdateTotalVotingPower() error { - - sum := int64(0) - for _, val := range vals.Validators { - // mind overflow - sum = safeAddClip(sum, val.VotingPower) - if sum > MaxTotalVotingPower { - return &valset.TotalVotingPowerExceededError{Sum: sum, Validators: vals.Validators} - } - } - vals.totalVotingPower = sum - return nil -} - -// TotalVotingPower returns the sum of the voting powers of all validators. -// It recomputes the total voting power if required. -func (vals *ValidatorSet) TotalVotingPower() int64 { - if vals.totalVotingPower == 0 { - log.Info("invoking updateTotalVotingPower before returning it") - if err := vals.UpdateTotalVotingPower(); err != nil { - // Can/should we do better? - panic(err) - } - } - return vals.totalVotingPower -} - -// GetProposer returns the current proposer. If the validator set is empty, nil -// is returned. -func (vals *ValidatorSet) GetProposer() (proposer *valset.Validator) { - if len(vals.Validators) == 0 { - return nil - } - if vals.Proposer == nil { - vals.Proposer = vals.findProposer() - } - return vals.Proposer.Copy() -} - -func (vals *ValidatorSet) findProposer() *valset.Validator { - var proposer *valset.Validator - for _, val := range vals.Validators { - if proposer == nil || !bytes.Equal(val.Address.Bytes(), proposer.Address.Bytes()) { - proposer = proposer.Cmp(val) - } - } - return proposer -} - -// Hash returns the Merkle root hash build using validators (as leaves) in the -// set. -// func (vals *ValidatorSet) Hash() []byte { -// if len(vals.Validators) == 0 { -// return nil -// } -// bzs := make([][]byte, len(vals.Validators)) -// for i, val := range vals.Validators { -// bzs[i] = val.Bytes() -// } -// return merkle.SimpleHashFromByteSlices(bzs) -// } - -// Iterate will run the given function over the set. -func (vals *ValidatorSet) Iterate(fn func(index int, val *valset.Validator) bool) { - for i, val := range vals.Validators { - stop := fn(i, val.Copy()) - if stop { - break - } - } -} - -// Checks changes against duplicates, splits the changes in updates and removals, sorts them by address. -// -// Returns: -// updates, removals - the sorted lists of updates and removals -// err - non-nil if duplicate entries or entries with negative voting power are seen -// -// No changes are made to 'origChanges'. -func processChanges(origChanges []*valset.Validator) (updates, removals []*valset.Validator, err error) { - // Make a deep copy of the changes and sort by address. - changes := validatorListCopy(origChanges) - sort.Sort(ValidatorsByAddress(changes)) - - removals = make([]*valset.Validator, 0, len(changes)) - updates = make([]*valset.Validator, 0, len(changes)) - var prevAddr libcommon.Address - - // Scan changes by address and append valid validators to updates or removals lists. - for _, valUpdate := range changes { - if bytes.Equal(valUpdate.Address.Bytes(), prevAddr.Bytes()) { - err = fmt.Errorf("duplicate entry %v in %v", valUpdate, changes) - return nil, nil, err - } - if valUpdate.VotingPower < 0 { - err = fmt.Errorf("voting power can't be negative: %v", valUpdate) - return nil, nil, err - } - if valUpdate.VotingPower > MaxTotalVotingPower { - err = fmt.Errorf("to prevent clipping/ overflow, voting power can't be higher than %v: %v ", - MaxTotalVotingPower, valUpdate) - return nil, nil, err - } - if valUpdate.VotingPower == 0 { - removals = append(removals, valUpdate) - } else { - updates = append(updates, valUpdate) - } - prevAddr = valUpdate.Address - } - return updates, removals, err -} - -// Verifies a list of updates against a validator set, making sure the allowed -// total voting power would not be exceeded if these updates would be applied to the set. -// -// Returns: -// updatedTotalVotingPower - the new total voting power if these updates would be applied -// numNewValidators - number of new validators -// err - non-nil if the maximum allowed total voting power would be exceeded -// -// 'updates' should be a list of proper validator changes, i.e. they have been verified -// by processChanges for duplicates and invalid values. -// No changes are made to the validator set 'vals'. -func verifyUpdates(updates []*valset.Validator, vals *ValidatorSet) (updatedTotalVotingPower int64, numNewValidators int, err error) { - - updatedTotalVotingPower = vals.TotalVotingPower() - - for _, valUpdate := range updates { - address := valUpdate.Address - _, val := vals.GetByAddress(address) - if val == nil { - // New validator, add its voting power the the total. - updatedTotalVotingPower += valUpdate.VotingPower - numNewValidators++ - } else { - // Updated validator, add the difference in power to the total. - updatedTotalVotingPower += valUpdate.VotingPower - val.VotingPower - } - overflow := updatedTotalVotingPower > MaxTotalVotingPower - if overflow { - err = fmt.Errorf( - "failed to add/update validator %v, total voting power would exceed the max allowed %v", - valUpdate, MaxTotalVotingPower) - return 0, 0, err - } - } - - return updatedTotalVotingPower, numNewValidators, nil -} - -// Computes the proposer priority for the validators not present in the set based on 'updatedTotalVotingPower'. -// Leaves unchanged the priorities of validators that are changed. -// -// 'updates' parameter must be a list of unique validators to be added or updated. -// No changes are made to the validator set 'vals'. -func computeNewPriorities(updates []*valset.Validator, vals *ValidatorSet, updatedTotalVotingPower int64) { - - for _, valUpdate := range updates { - address := valUpdate.Address - _, val := vals.GetByAddress(address) - if val == nil { - // add val - // Set ProposerPriority to -C*totalVotingPower (with C ~= 1.125) to make sure validators can't - // un-bond and then re-bond to reset their (potentially previously negative) ProposerPriority to zero. - // - // Contract: updatedVotingPower < MaxTotalVotingPower to ensure ProposerPriority does - // not exceed the bounds of int64. - // - // Compute ProposerPriority = -1.125*totalVotingPower == -(updatedVotingPower + (updatedVotingPower >> 3)). - valUpdate.ProposerPriority = -(updatedTotalVotingPower + (updatedTotalVotingPower >> 3)) - } else { - valUpdate.ProposerPriority = val.ProposerPriority - } - } - -} - -// Merges the vals' validator list with the updates list. -// When two elements with same address are seen, the one from updates is selected. -// Expects updates to be a list of updates sorted by address with no duplicates or errors, -// must have been validated with verifyUpdates() and priorities computed with computeNewPriorities(). -func (vals *ValidatorSet) applyUpdates(updates []*valset.Validator) { - - existing := vals.Validators - merged := make([]*valset.Validator, len(existing)+len(updates)) - i := 0 - - for len(existing) > 0 && len(updates) > 0 { - if bytes.Compare(existing[0].Address.Bytes(), updates[0].Address.Bytes()) < 0 { // unchanged validator - merged[i] = existing[0] - existing = existing[1:] - } else { - // Apply add or update. - merged[i] = updates[0] - if bytes.Equal(existing[0].Address.Bytes(), updates[0].Address.Bytes()) { - // bor.Validator is present in both, advance existing. - existing = existing[1:] - } - updates = updates[1:] - } - i++ - } - - // Add the elements which are left. - for j := 0; j < len(existing); j++ { - merged[i] = existing[j] - i++ - } - // OR add updates which are left. - for j := 0; j < len(updates); j++ { - merged[i] = updates[j] - i++ - } - - vals.Validators = merged[:i] -} - -// Checks that the validators to be removed are part of the validator set. -// No changes are made to the validator set 'vals'. -func verifyRemovals(deletes []*valset.Validator, vals *ValidatorSet) error { - - for _, valUpdate := range deletes { - address := valUpdate.Address - _, val := vals.GetByAddress(address) - if val == nil { - return fmt.Errorf("failed to find validator %X to remove", address) - } - } - if len(deletes) > len(vals.Validators) { - panic("more deletes than validators") - } - return nil -} - -// Removes the validators specified in 'deletes' from validator set 'vals'. -// Should not fail as verification has been done before. -func (vals *ValidatorSet) applyRemovals(deletes []*valset.Validator) { - - existing := vals.Validators - - merged := make([]*valset.Validator, len(existing)-len(deletes)) - i := 0 - - // Loop over deletes until we removed all of them. - for len(deletes) > 0 { - if bytes.Equal(existing[0].Address.Bytes(), deletes[0].Address.Bytes()) { - deletes = deletes[1:] - } else { // Leave it in the resulting slice. - merged[i] = existing[0] - i++ - } - existing = existing[1:] - } - - // Add the elements which are left. - for j := 0; j < len(existing); j++ { - merged[i] = existing[j] - i++ - } - - vals.Validators = merged[:i] -} - -// Main function used by UpdateWithChangeSet() and NewValidatorSet(). -// If 'allowDeletes' is false then delete operations (identified by validators with voting power 0) -// are not allowed and will trigger an error if present in 'changes'. -// The 'allowDeletes' flag is set to false by NewValidatorSet() and to true by UpdateWithChangeSet(). -func (vals *ValidatorSet) updateWithChangeSet(changes []*valset.Validator, allowDeletes bool) error { - - if len(changes) < 1 { - return nil - } - - // Check for duplicates within changes, split in 'updates' and 'deletes' lists (sorted). - updates, deletes, err := processChanges(changes) - if err != nil { - return err - } - - if !allowDeletes && len(deletes) != 0 { - return fmt.Errorf("cannot process validators with voting power 0: %v", deletes) - } - - // Verify that applying the 'deletes' against 'vals' will not result in error. - if err := verifyRemovals(deletes, vals); err != nil { - return err - } - - // Verify that applying the 'updates' against 'vals' will not result in error. - updatedTotalVotingPower, numNewValidators, err := verifyUpdates(updates, vals) - if err != nil { - return err - } - - // Check that the resulting set will not be empty. - if numNewValidators == 0 && len(vals.Validators) == len(deletes) { - return fmt.Errorf("applying the validator changes would result in empty set") - } - - // Compute the priorities for updates. - computeNewPriorities(updates, vals, updatedTotalVotingPower) - - // Apply updates and removals. - vals.applyUpdates(updates) - vals.applyRemovals(deletes) - - if err := vals.UpdateTotalVotingPower(); err != nil { - return err - } - - // Scale and center. - vals.RescalePriorities(PriorityWindowSizeFactor * vals.TotalVotingPower()) - vals.shiftByAvgProposerPriority() - - return nil -} - -// UpdateWithChangeSet attempts to update the validator set with 'changes'. -// It performs the following steps: -// - validates the changes making sure there are no duplicates and splits them in updates and deletes -// - verifies that applying the changes will not result in errors -// - computes the total voting power BEFORE removals to ensure that in the next steps the priorities -// across old and newly added validators are fair -// - computes the priorities of new validators against the final set -// - applies the updates against the validator set -// - applies the removals against the validator set -// - performs scaling and centering of priority values -// -// If an error is detected during verification steps, it is returned and the validator set -// is not changed. -func (vals *ValidatorSet) UpdateWithChangeSet(changes []*valset.Validator) error { - return vals.updateWithChangeSet(changes, true) -} - -//----------------- -// ErrTooMuchChange - -func IsErrTooMuchChange(err error) bool { - switch err.(type) { - case errTooMuchChange: - return true - default: - return false - } -} - -type errTooMuchChange struct { - got int64 - needed int64 -} - -func (e errTooMuchChange) Error() string { - return fmt.Sprintf("Invalid commit -- insufficient old voting power: got %v, needed %v", e.got, e.needed) -} - -//---------------- - -func (vals *ValidatorSet) String() string { - return vals.StringIndented("") -} - -func (vals *ValidatorSet) StringIndented(indent string) string { - if vals == nil { - return "nil-ValidatorSet" - } - var valStrings []string - vals.Iterate(func(index int, val *valset.Validator) bool { - valStrings = append(valStrings, val.String()) - return false - }) - return fmt.Sprintf(`ValidatorSet{ -%s Proposer: %v -%s Validators: -%s %v -%s}`, - indent, vals.GetProposer().String(), - indent, - indent, strings.Join(valStrings, "\n"+indent+" "), - indent) - -} - -//------------------------------------- -// Implements sort for sorting validators by address. - -// Sort validators by address. -type ValidatorsByAddress []*valset.Validator - -func (valz ValidatorsByAddress) Len() int { - return len(valz) -} - -func (valz ValidatorsByAddress) Less(i, j int) bool { - return bytes.Compare(valz[i].Address.Bytes(), valz[j].Address.Bytes()) == -1 -} - -func (valz ValidatorsByAddress) Swap(i, j int) { - valz[i], valz[j] = valz[j], valz[i] -} - -/////////////////////////////////////////////////////////////////////////////// -// safe addition/subtraction - -func safeAdd(a, b int64) (int64, bool) { - if b > 0 && a > math.MaxInt64-b { - return -1, true - } else if b < 0 && a < math.MinInt64-b { - return -1, true - } - return a + b, false -} - -func safeSub(a, b int64) (int64, bool) { - if b > 0 && a < math.MinInt64+b { - return -1, true - } else if b < 0 && a > math.MaxInt64+b { - return -1, true - } - return a - b, false -} - -func safeAddClip(a, b int64) int64 { - c, overflow := safeAdd(a, b) - if overflow { - if b < 0 { - return math.MinInt64 - } - return math.MaxInt64 - } - return c -} - -func safeSubClip(a, b int64) int64 { - c, overflow := safeSub(a, b) - if overflow { - if b > 0 { - return math.MinInt64 - } - return math.MaxInt64 - } - return c -}