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 }