123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- // Copyright 2017 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 validator
- import (
- "math"
- "reflect"
- "sync"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/consensus/istanbul"
- )
- type defaultValidator struct {
- address common.Address
- }
- func (val *defaultValidator) Address() common.Address {
- return val.address
- }
- func (val *defaultValidator) String() string {
- return val.Address().String()
- }
- // ----------------------------------------------------------------------------
- type defaultSet struct {
- validators istanbul.Validators
- policy *istanbul.ProposerPolicy
- proposer istanbul.Validator
- validatorMu sync.RWMutex
- selector istanbul.ProposalSelector
- }
- func newDefaultSet(addrs []common.Address, policy *istanbul.ProposerPolicy) *defaultSet {
- valSet := &defaultSet{}
- valSet.policy = policy
- // init validators
- valSet.validators = make([]istanbul.Validator, len(addrs))
- for i, addr := range addrs {
- valSet.validators[i] = New(addr)
- }
- valSet.SortValidators()
- // init proposer
- if valSet.Size() > 0 {
- valSet.proposer = valSet.GetByIndex(0)
- }
- valSet.selector = roundRobinProposer
- if policy.Id == istanbul.Sticky {
- valSet.selector = stickyProposer
- }
- policy.RegisterValidatorSet(valSet)
- return valSet
- }
- func (valSet *defaultSet) Size() int {
- valSet.validatorMu.RLock()
- defer valSet.validatorMu.RUnlock()
- return len(valSet.validators)
- }
- func (valSet *defaultSet) List() []istanbul.Validator {
- valSet.validatorMu.RLock()
- defer valSet.validatorMu.RUnlock()
- return valSet.validators
- }
- func (valSet *defaultSet) GetByIndex(i uint64) istanbul.Validator {
- valSet.validatorMu.RLock()
- defer valSet.validatorMu.RUnlock()
- if i < uint64(valSet.Size()) {
- return valSet.validators[i]
- }
- return nil
- }
- func (valSet *defaultSet) GetByAddress(addr common.Address) (int, istanbul.Validator) {
- for i, val := range valSet.List() {
- if addr == val.Address() {
- return i, val
- }
- }
- return -1, nil
- }
- func (valSet *defaultSet) GetProposer() istanbul.Validator {
- return valSet.proposer
- }
- func (valSet *defaultSet) IsProposer(address common.Address) bool {
- _, val := valSet.GetByAddress(address)
- return reflect.DeepEqual(valSet.GetProposer(), val)
- }
- func (valSet *defaultSet) CalcProposer(lastProposer common.Address, round uint64) {
- valSet.validatorMu.RLock()
- defer valSet.validatorMu.RUnlock()
- valSet.proposer = valSet.selector(valSet, lastProposer, round)
- }
- // ValidatorSetSorter sorts the validators based on the configured By function
- func (valSet *defaultSet) SortValidators() {
- valSet.Policy().By.Sort(valSet.validators)
- }
- func calcSeed(valSet istanbul.ValidatorSet, proposer common.Address, round uint64) uint64 {
- offset := 0
- if idx, val := valSet.GetByAddress(proposer); val != nil {
- offset = idx
- }
- return uint64(offset) + round
- }
- func emptyAddress(addr common.Address) bool {
- return addr == common.Address{}
- }
- func roundRobinProposer(valSet istanbul.ValidatorSet, proposer common.Address, round uint64) istanbul.Validator {
- if valSet.Size() == 0 {
- return nil
- }
- seed := uint64(0)
- if emptyAddress(proposer) {
- seed = round
- } else {
- seed = calcSeed(valSet, proposer, round) + 1
- }
- pick := seed % uint64(valSet.Size())
- return valSet.GetByIndex(pick)
- }
- func stickyProposer(valSet istanbul.ValidatorSet, proposer common.Address, round uint64) istanbul.Validator {
- if valSet.Size() == 0 {
- return nil
- }
- seed := uint64(0)
- if emptyAddress(proposer) {
- seed = round
- } else {
- seed = calcSeed(valSet, proposer, round)
- }
- pick := seed % uint64(valSet.Size())
- return valSet.GetByIndex(pick)
- }
- func (valSet *defaultSet) AddValidator(address common.Address) bool {
- valSet.validatorMu.Lock()
- defer valSet.validatorMu.Unlock()
- for _, v := range valSet.validators {
- if v.Address() == address {
- return false
- }
- }
- valSet.validators = append(valSet.validators, New(address))
- // TODO: we may not need to re-sort it again
- // sort validator
- valSet.SortValidators()
- return true
- }
- func (valSet *defaultSet) RemoveValidator(address common.Address) bool {
- valSet.validatorMu.Lock()
- defer valSet.validatorMu.Unlock()
- for i, v := range valSet.validators {
- if v.Address() == address {
- valSet.validators = append(valSet.validators[:i], valSet.validators[i+1:]...)
- return true
- }
- }
- return false
- }
- func (valSet *defaultSet) Copy() istanbul.ValidatorSet {
- valSet.validatorMu.RLock()
- defer valSet.validatorMu.RUnlock()
- addresses := make([]common.Address, 0, len(valSet.validators))
- for _, v := range valSet.validators {
- addresses = append(addresses, v.Address())
- }
- return NewSet(addresses, valSet.policy)
- }
- func (valSet *defaultSet) F() int { return int(math.Ceil(float64(valSet.Size())/3)) - 1 }
- func (valSet *defaultSet) Policy() istanbul.ProposerPolicy { return *valSet.policy }
|