github.com/ConsenSys/Quorum@v20.10.0+incompatible/consensus/istanbul/validator/default.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package validator
    18  
    19  import (
    20  	"math"
    21  	"reflect"
    22  	"sort"
    23  	"sync"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/consensus/istanbul"
    27  )
    28  
    29  type defaultValidator struct {
    30  	address common.Address
    31  }
    32  
    33  func (val *defaultValidator) Address() common.Address {
    34  	return val.address
    35  }
    36  
    37  func (val *defaultValidator) String() string {
    38  	return val.Address().String()
    39  }
    40  
    41  // ----------------------------------------------------------------------------
    42  
    43  type defaultSet struct {
    44  	validators istanbul.Validators
    45  	policy     istanbul.ProposerPolicy
    46  
    47  	proposer    istanbul.Validator
    48  	validatorMu sync.RWMutex
    49  	selector    istanbul.ProposalSelector
    50  }
    51  
    52  func newDefaultSet(addrs []common.Address, policy istanbul.ProposerPolicy) *defaultSet {
    53  	valSet := &defaultSet{}
    54  
    55  	valSet.policy = policy
    56  	// init validators
    57  	valSet.validators = make([]istanbul.Validator, len(addrs))
    58  	for i, addr := range addrs {
    59  		valSet.validators[i] = New(addr)
    60  	}
    61  	// sort validator
    62  	sort.Sort(valSet.validators)
    63  	// init proposer
    64  	if valSet.Size() > 0 {
    65  		valSet.proposer = valSet.GetByIndex(0)
    66  	}
    67  	valSet.selector = roundRobinProposer
    68  	if policy == istanbul.Sticky {
    69  		valSet.selector = stickyProposer
    70  	}
    71  
    72  	return valSet
    73  }
    74  
    75  func (valSet *defaultSet) Size() int {
    76  	valSet.validatorMu.RLock()
    77  	defer valSet.validatorMu.RUnlock()
    78  	return len(valSet.validators)
    79  }
    80  
    81  func (valSet *defaultSet) List() []istanbul.Validator {
    82  	valSet.validatorMu.RLock()
    83  	defer valSet.validatorMu.RUnlock()
    84  	return valSet.validators
    85  }
    86  
    87  func (valSet *defaultSet) GetByIndex(i uint64) istanbul.Validator {
    88  	valSet.validatorMu.RLock()
    89  	defer valSet.validatorMu.RUnlock()
    90  	if i < uint64(valSet.Size()) {
    91  		return valSet.validators[i]
    92  	}
    93  	return nil
    94  }
    95  
    96  func (valSet *defaultSet) GetByAddress(addr common.Address) (int, istanbul.Validator) {
    97  	for i, val := range valSet.List() {
    98  		if addr == val.Address() {
    99  			return i, val
   100  		}
   101  	}
   102  	return -1, nil
   103  }
   104  
   105  func (valSet *defaultSet) GetProposer() istanbul.Validator {
   106  	return valSet.proposer
   107  }
   108  
   109  func (valSet *defaultSet) IsProposer(address common.Address) bool {
   110  	_, val := valSet.GetByAddress(address)
   111  	return reflect.DeepEqual(valSet.GetProposer(), val)
   112  }
   113  
   114  func (valSet *defaultSet) CalcProposer(lastProposer common.Address, round uint64) {
   115  	valSet.validatorMu.RLock()
   116  	defer valSet.validatorMu.RUnlock()
   117  	valSet.proposer = valSet.selector(valSet, lastProposer, round)
   118  }
   119  
   120  func calcSeed(valSet istanbul.ValidatorSet, proposer common.Address, round uint64) uint64 {
   121  	offset := 0
   122  	if idx, val := valSet.GetByAddress(proposer); val != nil {
   123  		offset = idx
   124  	}
   125  	return uint64(offset) + round
   126  }
   127  
   128  func emptyAddress(addr common.Address) bool {
   129  	return addr == common.Address{}
   130  }
   131  
   132  func roundRobinProposer(valSet istanbul.ValidatorSet, proposer common.Address, round uint64) istanbul.Validator {
   133  	if valSet.Size() == 0 {
   134  		return nil
   135  	}
   136  	seed := uint64(0)
   137  	if emptyAddress(proposer) {
   138  		seed = round
   139  	} else {
   140  		seed = calcSeed(valSet, proposer, round) + 1
   141  	}
   142  	pick := seed % uint64(valSet.Size())
   143  	return valSet.GetByIndex(pick)
   144  }
   145  
   146  func stickyProposer(valSet istanbul.ValidatorSet, proposer common.Address, round uint64) istanbul.Validator {
   147  	if valSet.Size() == 0 {
   148  		return nil
   149  	}
   150  	seed := uint64(0)
   151  	if emptyAddress(proposer) {
   152  		seed = round
   153  	} else {
   154  		seed = calcSeed(valSet, proposer, round)
   155  	}
   156  	pick := seed % uint64(valSet.Size())
   157  	return valSet.GetByIndex(pick)
   158  }
   159  
   160  func (valSet *defaultSet) AddValidator(address common.Address) bool {
   161  	valSet.validatorMu.Lock()
   162  	defer valSet.validatorMu.Unlock()
   163  	for _, v := range valSet.validators {
   164  		if v.Address() == address {
   165  			return false
   166  		}
   167  	}
   168  	valSet.validators = append(valSet.validators, New(address))
   169  	// TODO: we may not need to re-sort it again
   170  	// sort validator
   171  	sort.Sort(valSet.validators)
   172  	return true
   173  }
   174  
   175  func (valSet *defaultSet) RemoveValidator(address common.Address) bool {
   176  	valSet.validatorMu.Lock()
   177  	defer valSet.validatorMu.Unlock()
   178  
   179  	for i, v := range valSet.validators {
   180  		if v.Address() == address {
   181  			valSet.validators = append(valSet.validators[:i], valSet.validators[i+1:]...)
   182  			return true
   183  		}
   184  	}
   185  	return false
   186  }
   187  
   188  func (valSet *defaultSet) Copy() istanbul.ValidatorSet {
   189  	valSet.validatorMu.RLock()
   190  	defer valSet.validatorMu.RUnlock()
   191  
   192  	addresses := make([]common.Address, 0, len(valSet.validators))
   193  	for _, v := range valSet.validators {
   194  		addresses = append(addresses, v.Address())
   195  	}
   196  	return NewSet(addresses, valSet.policy)
   197  }
   198  
   199  func (valSet *defaultSet) F() int { return int(math.Ceil(float64(valSet.Size())/3)) - 1 }
   200  
   201  func (valSet *defaultSet) Policy() istanbul.ProposerPolicy { return valSet.policy }