Skip to content

Commit

Permalink
Merge pull request #71 from ClarkChenc/opt-validator-set-with-map
Browse files Browse the repository at this point in the history
Optimize validatorset with map
  • Loading branch information
bladehan1 authored Mar 6, 2024
2 parents d28b8bc + e8e709a commit f2a5e32
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 29 deletions.
4 changes: 2 additions & 2 deletions consensus/bor/bor.go
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header
if err != nil {
return err
}
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
if !snap.ValidatorSet.HasAddress(signer) {
// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
return &UnauthorizedSignerError{number - 1, signer.Bytes()}
}
Expand Down Expand Up @@ -835,7 +835,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
}

// Bail out if we're unauthorized to sign a block
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
if !snap.ValidatorSet.HasAddress(signer) {
// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
return &UnauthorizedSignerError{number - 1, signer.Bytes()}
}
Expand Down
6 changes: 4 additions & 2 deletions consensus/bor/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,14 @@ func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Dat
if err := json.Unmarshal(blob, snap); err != nil {
return nil, err
}

snap.ValidatorSet.UpdateValidatorMap()
snap.config = config
snap.sigcache = sigcache
snap.ethAPI = ethAPI

// update total voting power
if err := snap.ValidatorSet.updateTotalVotingPower(); err != nil {
if err := snap.ValidatorSet.UpdateTotalVotingPower(); err != nil {
return nil, err
}

Expand Down Expand Up @@ -137,7 +139,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, &UnauthorizedSignerError{number, signer.Bytes()}
}

Expand Down
82 changes: 57 additions & 25 deletions consensus/bor/validator_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type ValidatorSet struct {

// cached (unexported)
totalVotingPower int64
validatorsMap map[common.Address]int // address -> index
}

// NewValidatorSet initializes a ValidatorSet by copying over the
Expand All @@ -54,7 +55,7 @@ type ValidatorSet struct {
// The addresses of validators in `valz` must be unique otherwise the
// function panics.
func NewValidatorSet(valz []*Validator) *ValidatorSet {
vals := &ValidatorSet{}
vals := &ValidatorSet{validatorsMap: make(map[common.Address]int)}
err := vals.updateWithChangeSet(valz, false)
if err != nil {
panic(fmt.Sprintf("cannot create validator set: %s", err))
Expand Down Expand Up @@ -212,43 +213,50 @@ func validatorListCopy(valsList []*Validator) []*Validator {

// Copy each validator into a new ValidatorSet.
func (vals *ValidatorSet) Copy() *ValidatorSet {
valCopy := validatorListCopy(vals.Validators)
validatorsMap := make(map[common.Address]int, len(vals.Validators))

for i, val := range valCopy {
validatorsMap[val.Address] = i
}

return &ValidatorSet{
Validators: validatorListCopy(vals.Validators),
Proposer: vals.Proposer,
totalVotingPower: vals.totalVotingPower,
validatorsMap: validatorsMap,
}
}

// 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)
func (vals *ValidatorSet) HasAddress(address common.Address) bool {
_, ok := vals.validatorsMap[address]

return ok
}

// 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 common.Address) (index int, val *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()) {
idx, ok := vals.validatorsMap[address]
if ok {
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 *Validator) {
func (vals *ValidatorSet) GetByIndex(index int) (address common.Address, val *Validator) {
if index < 0 || index >= len(vals.Validators) {
return nil, nil
return common.Address{}, nil
}
val = vals.Validators[index]
return val.Address.Bytes(), val.Copy()

return val.Address, val.Copy()
}

// Size returns the length of the validator set.
Expand All @@ -257,7 +265,7 @@ func (vals *ValidatorSet) Size() int {
}

// Force recalculation of the set's total voting power.
func (vals *ValidatorSet) updateTotalVotingPower() error {
func (vals *ValidatorSet) UpdateTotalVotingPower() error {

sum := int64(0)
for _, val := range vals.Validators {
Expand All @@ -276,7 +284,7 @@ func (vals *ValidatorSet) updateTotalVotingPower() error {
func (vals *ValidatorSet) TotalVotingPower() int64 {
if vals.totalVotingPower == 0 {
log.Info("invoking updateTotalVotingPower before returning it")
if err := vals.updateTotalVotingPower(); err != nil {
if err := vals.UpdateTotalVotingPower(); err != nil {
// Can/should we do better?
panic(err)
}
Expand All @@ -299,7 +307,7 @@ func (vals *ValidatorSet) GetProposer() (proposer *Validator) {
func (vals *ValidatorSet) findProposer() *Validator {
var proposer *Validator
for _, val := range vals.Validators {
if proposer == nil || !bytes.Equal(val.Address.Bytes(), proposer.Address.Bytes()) {
if proposer == nil || val.Address != proposer.Address {
proposer = proposer.Cmp(val)
}
}
Expand Down Expand Up @@ -341,13 +349,19 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e
changes := validatorListCopy(origChanges)
sort.Sort(ValidatorsByAddress(changes))

removals = make([]*Validator, 0, len(changes))
updates = make([]*Validator, 0, len(changes))
sliceCap := len(changes) / 2
if sliceCap == 0 {
sliceCap = 1
}

removals = make([]*Validator, 0, sliceCap)
updates = make([]*Validator, 0, sliceCap)

var prevAddr common.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()) {
if valUpdate.Address == prevAddr {
err = fmt.Errorf("duplicate entry %v in %v", valUpdate, changes)
return nil, nil, err
}
Expand Down Expand Up @@ -452,7 +466,7 @@ func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
} else {
// Apply add or update.
merged[i] = updates[0]
if bytes.Equal(existing[0].Address.Bytes(), updates[0].Address.Bytes()) {
if existing[0].Address == updates[0].Address {
// Validator is present in both, advance existing.
existing = existing[1:]
}
Expand Down Expand Up @@ -503,7 +517,7 @@ func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {

// Loop over deletes until we removed all of them.
for len(deletes) > 0 {
if bytes.Equal(existing[0].Address.Bytes(), deletes[0].Address.Bytes()) {
if existing[0].Address == deletes[0].Address {
deletes = deletes[1:]
} else { // Leave it in the resulting slice.
merged[i] = existing[0]
Expand Down Expand Up @@ -561,10 +575,9 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes
computeNewPriorities(updates, vals, updatedTotalVotingPower)

// Apply updates and removals.
vals.applyUpdates(updates)
vals.applyRemovals(deletes)
vals.updateValidators(updates, deletes)

if err := vals.updateTotalVotingPower(); err != nil {
if err := vals.UpdateTotalVotingPower(); err != nil {
return err
}

Expand All @@ -575,6 +588,21 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes
return nil
}

func (vals *ValidatorSet) updateValidators(updates []*Validator, deletes []*Validator) {
vals.applyUpdates(updates)
vals.applyRemovals(deletes)

vals.UpdateValidatorMap()
}

func (vals *ValidatorSet) UpdateValidatorMap() {
vals.validatorsMap = make(map[common.Address]int, len(vals.Validators))

for i, val := range vals.Validators {
vals.validatorsMap[val.Address] = i
}
}

// 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
Expand Down Expand Up @@ -622,7 +650,7 @@ func (vals *ValidatorSet) StringIndented(indent string) string {
if vals == nil {
return "nil-ValidatorSet"
}
var valStrings []string
valStrings := make([]string, 0, len(vals.Validators))
vals.Iterate(func(index int, val *Validator) bool {
valStrings = append(valStrings, val.String())
return false
Expand All @@ -639,6 +667,10 @@ func (vals *ValidatorSet) StringIndented(indent string) string {

}

func (vals *ValidatorSet) SetMap(validatorsMap map[common.Address]int) {
vals.validatorsMap = validatorsMap
}

//-------------------------------------
// Implements sort for sorting validators by address.

Expand Down

0 comments on commit f2a5e32

Please sign in to comment.