github.com/klaytn/klaytn@v1.12.1/consensus/istanbul/validator/default.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2017 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from quorum/consensus/istanbul/validator/default.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package validator 22 23 import ( 24 "math" 25 "reflect" 26 "sort" 27 "sync" 28 "sync/atomic" 29 30 "github.com/klaytn/klaytn/common" 31 "github.com/klaytn/klaytn/consensus/istanbul" 32 "github.com/klaytn/klaytn/fork" 33 "github.com/klaytn/klaytn/params" 34 ) 35 36 const ( 37 defaultSubSetLength = 21 38 ) 39 40 type defaultValidator struct { 41 address common.Address 42 } 43 44 func (val *defaultValidator) Address() common.Address { 45 return val.address 46 } 47 48 func (val *defaultValidator) String() string { 49 return val.Address().String() 50 } 51 52 func (val *defaultValidator) Equal(val2 *defaultValidator) bool { 53 return val.address == val2.address 54 } 55 56 func (val *defaultValidator) Hash() int64 { 57 return val.address.Hash().Big().Int64() 58 } 59 60 func (val *defaultValidator) RewardAddress() common.Address { return common.Address{} } 61 func (val *defaultValidator) VotingPower() uint64 { return 1000 } 62 func (val *defaultValidator) Weight() uint64 { return 0 } 63 64 type defaultSet struct { 65 subSize uint64 66 67 validators istanbul.Validators 68 policy istanbul.ProposerPolicy 69 70 proposer atomic.Value 71 validatorMu sync.RWMutex 72 selector istanbul.ProposalSelector 73 } 74 75 func newDefaultSet(addrs []common.Address, policy istanbul.ProposerPolicy) *defaultSet { 76 valSet := &defaultSet{} 77 78 valSet.subSize = defaultSubSetLength 79 valSet.policy = policy 80 // init validators 81 valSet.validators = make([]istanbul.Validator, len(addrs)) 82 for i, addr := range addrs { 83 valSet.validators[i] = New(addr) 84 } 85 // sort validator 86 sort.Sort(valSet.validators) 87 // init proposer 88 if valSet.Size() > 0 { 89 valSet.proposer.Store(valSet.GetByIndex(0)) 90 } 91 valSet.selector = roundRobinProposer 92 if policy == istanbul.Sticky { 93 valSet.selector = stickyProposer 94 } 95 96 return valSet 97 } 98 99 func newDefaultSubSet(addrs []common.Address, policy istanbul.ProposerPolicy, subSize uint64) *defaultSet { 100 valSet := &defaultSet{} 101 102 valSet.subSize = subSize 103 valSet.policy = policy 104 // init validators 105 valSet.validators = make([]istanbul.Validator, len(addrs)) 106 for i, addr := range addrs { 107 valSet.validators[i] = New(addr) 108 } 109 // sort validator 110 sort.Sort(valSet.validators) 111 // init proposer 112 if valSet.Size() > 0 { 113 valSet.proposer.Store(valSet.GetByIndex(0)) 114 } 115 valSet.selector = roundRobinProposer 116 if policy == istanbul.Sticky { 117 valSet.selector = stickyProposer 118 } 119 120 return valSet 121 } 122 123 func (valSet *defaultSet) Size() uint64 { 124 valSet.validatorMu.RLock() 125 defer valSet.validatorMu.RUnlock() 126 return uint64(len(valSet.validators)) 127 } 128 129 func (valSet *defaultSet) SubGroupSize() uint64 { 130 return valSet.subSize 131 } 132 133 // SetSubGroupSize sets committee size of the valSet. 134 func (valSet *defaultSet) SetSubGroupSize(size uint64) { 135 if size == 0 { 136 logger.Error("cannot assign committee size to 0") 137 return 138 } 139 valSet.subSize = size 140 } 141 142 func (valSet *defaultSet) List() []istanbul.Validator { 143 valSet.validatorMu.RLock() 144 defer valSet.validatorMu.RUnlock() 145 return valSet.validators 146 } 147 148 func (valSet *defaultSet) DemotedList() []istanbul.Validator { 149 return nil 150 } 151 152 // SubList composes a committee after setting a proposer with a default value. 153 // This functions returns whole validators if it failed to compose a committee. 154 func (valSet *defaultSet) SubList(prevHash common.Hash, view *istanbul.View) []istanbul.Validator { 155 // TODO-Klaytn-Istanbul: investigate whether `valSet.GetProposer().Address()` is a proper value or the proposer should be calculated based on `view` 156 proposer := valSet.GetProposer() 157 if proposer == nil { 158 return valSet.List() 159 } 160 return valSet.SubListWithProposer(prevHash, proposer.Address(), view) 161 } 162 163 // SubListWithProposer composes a committee with given parameters. 164 // The first member of the committee is set to the given proposer without calculating proposer with the given `view`. 165 // The second member of the committee is calculated with a round number of the given view and `valSet.blockNum`. 166 // The reset of the committee is selected with a random seed derived from `prevHash`. 167 // This functions returns whole validators if it failed to compose a committee. 168 func (valSet *defaultSet) SubListWithProposer(prevHash common.Hash, proposerAddr common.Address, view *istanbul.View) []istanbul.Validator { 169 valSet.validatorMu.RLock() 170 defer valSet.validatorMu.RUnlock() 171 172 validators := valSet.validators 173 validatorSize := uint64(len(validators)) 174 committeeSize := valSet.subSize 175 176 // return early if the committee size is equal or larger than the validator size 177 if committeeSize >= validatorSize { 178 return validators 179 } 180 181 // find the proposer 182 proposerIdx, proposer := valSet.GetByAddress(proposerAddr) 183 if proposerIdx < 0 { 184 logger.Error("invalid index of the proposer", 185 "addr", proposerAddr.String(), "index", proposerIdx) 186 return validators 187 } 188 189 // return early if the committee size is 1 190 if committeeSize == 1 { 191 return []istanbul.Validator{proposer} 192 } 193 194 // find the next proposer 195 nextProposer := valSet.selector(valSet, proposer.Address(), view.Round.Uint64()) 196 nextProposerIdx, _ := valSet.GetByAddress(nextProposer.Address()) 197 if nextProposerIdx < 0 { 198 logger.Error("invalid index of the next proposer", 199 "addr", nextProposer.Address().String(), "index", nextProposerIdx) 200 return validators 201 } 202 203 // seed will be used to select a random committee 204 seed, err := ConvertHashToSeed(prevHash) 205 if fork.Rules(view.Sequence).IsIstanbul { 206 seed += view.Round.Int64() 207 } 208 if err != nil { 209 logger.Error("failed to convert hash to seed", "prevHash", prevHash, "err", err) 210 return validators 211 } 212 213 // select a random committee 214 committee := SelectRandomCommittee(validators, committeeSize, seed, proposerIdx, nextProposerIdx) 215 if committee == nil { 216 committee = validators 217 } 218 219 logger.Trace("composed committee", "prevHash", prevHash.Hex(), "proposerAddr", proposerAddr, 220 "committee", committee, "committee size", len(committee), "valSet.subSize", committeeSize) 221 222 return committee 223 } 224 225 func (valSet *defaultSet) CheckInSubList(prevHash common.Hash, view *istanbul.View, addr common.Address) bool { 226 for _, val := range valSet.SubList(prevHash, view) { 227 if val.Address() == addr { 228 return true 229 } 230 } 231 return false 232 } 233 234 func (valSet *defaultSet) IsSubSet() bool { 235 return valSet.Size() > valSet.subSize 236 } 237 238 func (valSet *defaultSet) GetByIndex(i uint64) istanbul.Validator { 239 valSet.validatorMu.RLock() 240 defer valSet.validatorMu.RUnlock() 241 if i < uint64(len(valSet.validators)) { 242 return valSet.validators[i] 243 } 244 return nil 245 } 246 247 func (valSet *defaultSet) GetByAddress(addr common.Address) (int, istanbul.Validator) { 248 for i, val := range valSet.List() { 249 if addr == val.Address() { 250 return i, val 251 } 252 } 253 // TODO-Klaytn-Istanbul: Enable this log when non-committee nodes don't call `core.startNewRound()` 254 // logger.Warn("failed to find an address in the validator list", 255 // "address", addr, "validatorAddrs", valSet.validators.AddressStringList()) 256 return -1, nil 257 } 258 259 func (valSet *defaultSet) GetDemotedByAddress(addr common.Address) (int, istanbul.Validator) { 260 return -1, nil 261 } 262 263 func (valSet *defaultSet) GetProposer() istanbul.Validator { 264 proposer := valSet.proposer.Load() 265 if proposer == nil { 266 logger.Error("Proposer is nil", "validators", valSet.validators) 267 return nil 268 } 269 return proposer.(istanbul.Validator) 270 } 271 272 func (valSet *defaultSet) IsProposer(address common.Address) bool { 273 _, val := valSet.GetByAddress(address) 274 return reflect.DeepEqual(valSet.GetProposer(), val) 275 } 276 277 func (valSet *defaultSet) CalcProposer(lastProposer common.Address, round uint64) { 278 valSet.validatorMu.RLock() 279 defer valSet.validatorMu.RUnlock() 280 281 if len(valSet.validators) == 0 { 282 logger.Error("List of validators is empty", "validators", len(valSet.validators)) 283 return 284 } 285 286 valSet.proposer.Store(valSet.selector(valSet, lastProposer, round)) 287 } 288 289 func calcSeed(valSet istanbul.ValidatorSet, proposer common.Address, round uint64) uint64 { 290 offset := 0 291 if idx, val := valSet.GetByAddress(proposer); val != nil { 292 offset = idx 293 } 294 return uint64(offset) + round 295 } 296 297 func emptyAddress(addr common.Address) bool { 298 return addr == common.Address{} 299 } 300 301 func roundRobinProposer(valSet istanbul.ValidatorSet, proposer common.Address, round uint64) istanbul.Validator { 302 seed := uint64(0) 303 if emptyAddress(proposer) { 304 seed = round 305 } else { 306 seed = calcSeed(valSet, proposer, round) + 1 307 } 308 pick := seed % uint64(valSet.Size()) 309 return valSet.GetByIndex(pick) 310 } 311 312 func stickyProposer(valSet istanbul.ValidatorSet, proposer common.Address, round uint64) istanbul.Validator { 313 seed := uint64(0) 314 if emptyAddress(proposer) { 315 seed = round 316 } else { 317 seed = calcSeed(valSet, proposer, round) 318 } 319 pick := seed % uint64(valSet.Size()) 320 return valSet.GetByIndex(pick) 321 } 322 323 func (valSet *defaultSet) AddValidator(address common.Address) bool { 324 valSet.validatorMu.Lock() 325 defer valSet.validatorMu.Unlock() 326 for _, v := range valSet.validators { 327 if v.Address() == address { 328 return false 329 } 330 } 331 valSet.validators = append(valSet.validators, New(address)) 332 // TODO: we may not need to re-sort it again 333 // sort validator 334 sort.Sort(valSet.validators) 335 return true 336 } 337 338 func (valSet *defaultSet) RemoveValidator(address common.Address) bool { 339 valSet.validatorMu.Lock() 340 defer valSet.validatorMu.Unlock() 341 342 for i, v := range valSet.validators { 343 if v.Address() == address { 344 valSet.validators = append(valSet.validators[:i], valSet.validators[i+1:]...) 345 return true 346 } 347 } 348 return false 349 } 350 351 func (valSet *defaultSet) Copy() istanbul.ValidatorSet { 352 valSet.validatorMu.RLock() 353 defer valSet.validatorMu.RUnlock() 354 355 addresses := make([]common.Address, 0, len(valSet.validators)) 356 for _, v := range valSet.validators { 357 addresses = append(addresses, v.Address()) 358 } 359 360 newValSet := NewSubSet(addresses, valSet.policy, valSet.subSize).(*defaultSet) 361 if proposer := valSet.GetProposer(); proposer != nil { 362 // Copy the proposer if exist 363 if idx, p := newValSet.GetByAddress(proposer.Address()); idx != -1 { 364 newValSet.proposer.Store(p) 365 } 366 } 367 return newValSet 368 } 369 370 func (valSet *defaultSet) F() int { 371 if valSet.Size() > valSet.subSize { 372 return int(math.Ceil(float64(valSet.subSize)/3)) - 1 373 } else { 374 return int(math.Ceil(float64(valSet.Size())/3)) - 1 375 } 376 } 377 378 func (valSet *defaultSet) Policy() istanbul.ProposerPolicy { return valSet.policy } 379 380 func (valSet *defaultSet) Refresh(hash common.Hash, blockNum uint64, config *params.ChainConfig, isSingle bool, governingNode common.Address, minStaking uint64) error { 381 return nil 382 } 383 func (valSet *defaultSet) SetBlockNum(blockNum uint64) { /* Do nothing */ } 384 func (valSet *defaultSet) SetMixHash(mixHash []byte) { /* Do nothing */ } 385 func (valSet *defaultSet) Proposers() []istanbul.Validator { return nil } 386 func (valSet *defaultSet) TotalVotingPower() uint64 { 387 sum := uint64(0) 388 for _, v := range valSet.List() { 389 sum += v.VotingPower() 390 } 391 return sum 392 } 393 394 func (valSet *defaultSet) Selector(valS istanbul.ValidatorSet, lastProposer common.Address, round uint64) istanbul.Validator { 395 return valSet.selector(valS, lastProposer, round) 396 }