github.com/klaytn/klaytn@v1.12.1/consensus/istanbul/validator/weighted_random_test.go (about) 1 // Copyright 2019 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn 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 klaytn 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 klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package validator 18 19 import ( 20 "math/big" 21 "math/rand" 22 "reflect" 23 "sort" 24 "strconv" 25 "strings" 26 "testing" 27 "time" 28 29 "github.com/klaytn/klaytn/common" 30 "github.com/klaytn/klaytn/common/hexutil" 31 "github.com/klaytn/klaytn/consensus/istanbul" 32 "github.com/klaytn/klaytn/crypto" 33 "github.com/klaytn/klaytn/fork" 34 "github.com/klaytn/klaytn/params" 35 "github.com/stretchr/testify/assert" 36 ) 37 38 var ( 39 testAddrs = []common.Address{ 40 common.HexToAddress("0x0adBC7b05Da383157200a9Fa192285898aB2CaAc"), 41 common.HexToAddress("0x371F315BeBe961776AC84B29e044b01074b93E69"), 42 common.HexToAddress("0x5845EAa7ac251542Dc96fBaD09E3CAd3ec105a7a"), 43 common.HexToAddress("0x63805D23fC86Aa16EFB157C036F226f3aa93099d"), 44 common.HexToAddress("0x68E0DEf1e6beb308eF5FdF2e19dB2884571c465c"), 45 common.HexToAddress("0x72E23aAe2Cc6eE54682bD67B6093F7b7971f3D2F"), 46 common.HexToAddress("0x78B898e37A45069518775972AB8155493e69A2F0"), 47 common.HexToAddress("0x8704Ffb473a16638ea42c7704995d6505102a4Ca"), 48 common.HexToAddress("0x93d3Ce8940c7907b0C1c3898dF7Aa797C457cD0f"), 49 common.HexToAddress("0x9a049EefC01aAE911F2B6F19d724dF9d3ca5cAe6"), 50 common.HexToAddress("0xC14124d61fc940c7aF29F62438D1B54fD7FFB65B"), 51 common.HexToAddress("0xc4cB0B3c2682C15D96739f9a13fE26f17c893f8f"), 52 common.HexToAddress("0xd4aB68fcEC8Fa23856188163B131F3E443e09EF8"), 53 } 54 testRewardAddrs = []common.Address{ 55 common.HexToAddress("0x0a6e50a28f10CD9dba36DD9D3B95BaA32F9fe77a"), 56 common.HexToAddress("0x23FB6C77E069BD6456181f48a9c77f3a3812E7e7"), 57 common.HexToAddress("0x43d5e084D8A6c7FbCd0EbA9a517533fF384f0577"), 58 common.HexToAddress("0x4d180C12FB3B061f44E91D30d574F78D1DeCAD90"), 59 common.HexToAddress("0x53094cE69ea701bfb9D06239087d4CF09F127B78"), 60 common.HexToAddress("0x5F2152bf0C97f1d2c3Ffec8A98FEEB1e50798090"), 61 common.HexToAddress("0x653f42fb1F3474de222F7DDa2109250218989B19"), 62 common.HexToAddress("0x93eaEAa38D534B52E7DB3AB939330022330cD427"), 63 common.HexToAddress("0x96a0d7f6A82B860313FF8668b858aD4930d7B2d6"), 64 common.HexToAddress("0xB89ff800C21b3334f0e355A73242bB4363cf6e10"), 65 common.HexToAddress("0xDEeeF6fAC16f095Fa944E481F8e6c3b42ae3Cefa"), 66 common.HexToAddress("0xbDE3Ee8c01484dDBD59a425457Ab138cf3aa0E11"), 67 common.HexToAddress("0xdD5572A7aC7AB7407e8e4082dB442668C02924E3"), 68 } 69 testStakingAddrs = []common.Address{ 70 common.HexToAddress("0x3776A66698babFA24F0316e4363B2E6C95B09ceF"), 71 common.HexToAddress("0x4d086A88329233E00158FEcbe7b38Dd8667Dd9f9"), 72 common.HexToAddress("0x5d7d13278AEF56263B7d25d51E1B2519Ac0D656B"), 73 common.HexToAddress("0x60fA2326f6C1A7a90Bd1B3c31Bd1A7f9Aed61443"), 74 common.HexToAddress("0x681C55B2CD831D262C785e213a70e277D0226c79"), 75 common.HexToAddress("0x6EeA09FF2bB16F1cD075c748E1684f1100085541"), 76 common.HexToAddress("0x817617C3f09d08a5d475bf72b4723A755CD9b8c7"), 77 common.HexToAddress("0x83F28D3512dC32701F375b112d0CB0810Cb736e4"), 78 common.HexToAddress("0x92D03E4998fB3F91A1E24496EDCf625136037f9e"), 79 common.HexToAddress("0xA0360cDC935A9f3bFe7Ad03D1C34989427ad239f"), 80 common.HexToAddress("0xE2946677DcEEDDF36F1f6EA00421635804872D49"), 81 common.HexToAddress("0xF246283a57A8018085AF39bdadFCC4aaC682e6dD"), 82 common.HexToAddress("0xF3c6f39e231C7363F9B5F4d71b5EE7Eb1fB265d7"), 83 } 84 testVotingPowers = []uint64{ 85 1, 1, 1, 1, 1, 86 1, 1, 1, 1, 1, 87 1, 1, 1, 88 } 89 testZeroWeights = []uint64{ 90 0, 0, 0, 0, 0, 91 0, 0, 0, 0, 0, 92 0, 0, 0, 93 } 94 testPrevHash = common.HexToHash("0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a") 95 testMixHash = hexutil.MustDecode("0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a") 96 97 testExpectedProposers = []common.Address{ 98 common.HexToAddress("0x8704Ffb473a16638ea42c7704995d6505102a4Ca"), 99 common.HexToAddress("0xC14124d61fc940c7aF29F62438D1B54fD7FFB65B"), 100 common.HexToAddress("0x72E23aAe2Cc6eE54682bD67B6093F7b7971f3D2F"), 101 common.HexToAddress("0xc4cB0B3c2682C15D96739f9a13fE26f17c893f8f"), 102 common.HexToAddress("0x68E0DEf1e6beb308eF5FdF2e19dB2884571c465c"), 103 common.HexToAddress("0x371F315BeBe961776AC84B29e044b01074b93E69"), 104 common.HexToAddress("0x63805D23fC86Aa16EFB157C036F226f3aa93099d"), 105 common.HexToAddress("0x93d3Ce8940c7907b0C1c3898dF7Aa797C457cD0f"), 106 common.HexToAddress("0x5845EAa7ac251542Dc96fBaD09E3CAd3ec105a7a"), 107 common.HexToAddress("0x78B898e37A45069518775972AB8155493e69A2F0"), 108 common.HexToAddress("0x0adBC7b05Da383157200a9Fa192285898aB2CaAc"), 109 common.HexToAddress("0xd4aB68fcEC8Fa23856188163B131F3E443e09EF8"), 110 common.HexToAddress("0x9a049EefC01aAE911F2B6F19d724dF9d3ca5cAe6"), 111 } 112 113 testNonZeroWeights = []uint64{ 114 1, 1, 2, 1, 1, 115 1, 0, 3, 2, 1, 116 0, 1, 5, 117 } 118 ) 119 120 func makeTestValidators(weights []uint64) (validators istanbul.Validators) { 121 validators = make([]istanbul.Validator, len(testAddrs)) 122 for i := range testAddrs { 123 validators[i] = newWeightedValidator(testAddrs[i], testRewardAddrs[i], testVotingPowers[i], weights[i]) 124 } 125 sort.Sort(validators) 126 127 return 128 } 129 130 func makeTestWeightedCouncil(weights []uint64) (valSet *weightedCouncil) { 131 // prepare weighted council 132 valSet = NewWeightedCouncil(testAddrs, nil, testRewardAddrs, testVotingPowers, weights, istanbul.WeightedRandom, 21, 0, 0, nil) 133 return 134 } 135 136 func TestWeightedCouncil_List(t *testing.T) { 137 validators := makeTestValidators(testZeroWeights) 138 139 valSet := makeTestWeightedCouncil(testZeroWeights) 140 141 validators_in_valset := valSet.List() 142 143 if len(validators_in_valset) != len(validators) { 144 t.Errorf("len of validators in valSet is different from len of given test set %v, validators %v", len(validators_in_valset), len(validators)) 145 } 146 147 for i := 0; i < len(validators); i++ { 148 if validators[i].String() != validators_in_valset[i].String() { 149 t.Errorf("The element in validators in valset is different from given test set%v, validators %v", validators_in_valset[i], validators[i]) 150 } 151 } 152 } 153 154 func TestWeightedCouncil_GetByIndex(t *testing.T) { 155 validators := makeTestValidators(testZeroWeights) 156 valSet := makeTestWeightedCouncil(testZeroWeights) 157 158 for i := 0; i < len(validators); i++ { 159 validatorToCheck := valSet.GetByIndex(uint64(i)) 160 161 if validators[i].Address() != validatorToCheck.Address() { 162 t.Errorf("The validator with given index is different. index=%v, expected validator=%v, gotten validator %v", i, validators[i], valSet.GetByIndex(uint64(i))) 163 } 164 } 165 166 for errorIndex := len(validators) + 1; errorIndex < 100; errorIndex++ { 167 validatorToCheck := valSet.GetByIndex(uint64(errorIndex)) 168 169 if validatorToCheck != nil { 170 t.Errorf("The result should be nil with given index. index=%v", errorIndex) 171 } 172 } 173 174 for errorIndex := -1; errorIndex > -100; errorIndex-- { 175 validatorToCheck := valSet.GetByIndex(uint64(errorIndex)) 176 177 if validatorToCheck != nil { 178 t.Errorf("The result should be nil with given index. index=%v", errorIndex) 179 } 180 } 181 } 182 183 func TestWeightedCouncil_GetByAddress(t *testing.T) { 184 validators := makeTestValidators(testZeroWeights) 185 valSet := makeTestWeightedCouncil(testZeroWeights) 186 187 for i := 0; i < len(validators); i++ { 188 index, validatorToCheck := valSet.getByAddress(validators[i].Address()) 189 190 if validators[index].Address() != validatorToCheck.Address() { 191 t.Errorf("The validator with given address is different index=%v, expected validator=%v, gotten validator %v", i, validators[i], valSet.GetByIndex(uint64(i))) 192 } 193 } 194 195 _, errorValidator := valSet.getByAddress(common.Address{}) 196 if errorValidator != nil { 197 t.Errorf("The validator with given address should be nil.") 198 } 199 } 200 201 func TestWeightedCouncil_GetProposer(t *testing.T) { 202 validators := makeTestValidators(testZeroWeights) 203 valSet := makeTestWeightedCouncil(testZeroWeights) 204 205 // at the first, proposer is the first validator in the validator list 206 expectedProposer := validators[0] 207 proposerToCheck := valSet.GetProposer() 208 209 if expectedProposer.Address() != proposerToCheck.Address() { 210 t.Errorf("proposer should be same. Expected proposer: %v, gotten proposer %v", expectedProposer, proposerToCheck) 211 } 212 213 // random check. give random validator to valSet and check GetProposer() if it is same as the given validator 214 r := rand.New(rand.NewSource(time.Now().Unix())) 215 for i := 0; i < 100; i++ { 216 choosenIndex := r.Intn(len(validators)) 217 218 valSet.proposer.Store(validators[choosenIndex]) 219 220 expectedProposer := validators[choosenIndex] 221 proposerToCheck := valSet.GetProposer() 222 223 if expectedProposer.Address() != proposerToCheck.Address() { 224 t.Errorf("proposer should be same. Expected proposer: %v, gotten proposer %v", expectedProposer, proposerToCheck) 225 } 226 } 227 } 228 229 func TestDefaultSet_IsProposer(t *testing.T) { 230 validators := makeTestValidators(testZeroWeights) 231 valSet := makeTestWeightedCouncil(testZeroWeights) 232 233 currentProposer := valSet.GetProposer() 234 235 for i := 0; i < len(validators); i++ { 236 validatorToTest := validators[i] 237 238 expectedResult := validatorToTest.Address() == currentProposer.Address() 239 result := valSet.IsProposer(validatorToTest.Address()) 240 241 if result != expectedResult { 242 t.Errorf("The result is different from the expected result. Expected Result : %v, Gotten Result : %v, CurrentProposer Address : %v, TestValidator Address : %v", expectedResult, result, currentProposer.Address(), validatorToTest.Address()) 243 } 244 } 245 } 246 247 func TestWeightedCouncil_RefreshWithZeroWeight(t *testing.T) { 248 fork.SetHardForkBlockNumberConfig(¶ms.ChainConfig{ 249 IstanbulCompatibleBlock: big.NewInt(5), 250 }) 251 defer fork.ClearHardForkBlockNumberConfig() 252 253 validators := makeTestValidators(testZeroWeights) 254 255 valSet := makeTestWeightedCouncil(testZeroWeights) 256 runRefreshForTest(valSet) 257 258 // Run tests 259 260 // 1. check all validators are chosen for proposers 261 var sortedProposers istanbul.Validators 262 sortedProposers = make([]istanbul.Validator, len(testAddrs)) 263 copy(sortedProposers, valSet.proposers) 264 sort.Sort(sortedProposers) 265 if !reflect.DeepEqual(sortedProposers, validators) { 266 t.Errorf("All validators are not in proposers: sorted proposers %v, validators %v", sortedProposers, validators) 267 } 268 269 // 2. check proposers 270 for i, val := range valSet.proposers { 271 if !reflect.DeepEqual(val.Address(), testExpectedProposers[i]) { 272 t.Errorf("proposer mismatch: have %v, want %v", val.Address().String(), testExpectedProposers[i].String()) 273 } 274 } 275 276 // 3. test calculate proposer different round 277 checkCalcProposerWithRound(t, valSet, testAddrs[0], 0) 278 checkCalcProposerWithRound(t, valSet, testAddrs[0], 1) 279 checkCalcProposerWithRound(t, valSet, testAddrs[0], 5) 280 checkCalcProposerWithRound(t, valSet, testAddrs[0], 13) 281 checkCalcProposerWithRound(t, valSet, testAddrs[0], 1000) 282 283 // 4. test calculate proposer different block number 284 for i := 0; i < 100; i++ { 285 valSet.blockNum = uint64(i) 286 checkCalcProposerWithBlockNumber(t, valSet, testAddrs[0], 0) 287 } 288 289 // 5. test calculate proposer different block number and round 290 for i := 0; i < 100; i++ { 291 valSet.blockNum = uint64(i) 292 for j := 0; j < 100; j++ { 293 round := uint64(j) 294 checkCalcProposerWithBlockNumberAndRound(t, valSet, testAddrs[0], round) 295 } 296 } 297 } 298 299 func checkCalcProposerWithRound(t *testing.T, valSet *weightedCouncil, lastProposer common.Address, round uint64) { 300 valSet.CalcProposer(lastProposer, round) 301 _, expectedVal := valSet.GetByAddress(testExpectedProposers[round%uint64(len(valSet.proposers))]) 302 if val := valSet.GetProposer(); !reflect.DeepEqual(val, expectedVal) { 303 t.Errorf("proposer mismatch: have %v, want %v", val.String(), expectedVal.Address().String()) 304 } 305 } 306 307 func checkCalcProposerWithBlockNumber(t *testing.T, valSet *weightedCouncil, lastProposer common.Address, round uint64) { 308 valSet.CalcProposer(lastProposer, round) 309 _, expectedVal := valSet.GetByAddress(testExpectedProposers[valSet.blockNum%uint64(len(valSet.proposers))]) 310 if val := valSet.GetProposer(); !reflect.DeepEqual(val, expectedVal) { 311 t.Errorf("proposer mismatch: have %v, want %v", val.String(), expectedVal.Address().String()) 312 } 313 } 314 315 func checkCalcProposerWithBlockNumberAndRound(t *testing.T, valSet *weightedCouncil, lastProposer common.Address, round uint64) { 316 valSet.CalcProposer(lastProposer, round) 317 _, expectedVal := valSet.GetByAddress(testExpectedProposers[(valSet.blockNum+round)%uint64(len(valSet.proposers))]) 318 if val := valSet.GetProposer(); !reflect.DeepEqual(val, expectedVal) { 319 t.Errorf("proposer mismatch: have %v, want %v", val.String(), expectedVal.Address().String()) 320 } 321 } 322 323 func TestWeightedCouncil_RefreshWithNonZeroWeight(t *testing.T) { 324 validators := makeTestValidators(testNonZeroWeights) 325 326 valSet := makeTestWeightedCouncil(testNonZeroWeights) 327 runRefreshForTest(valSet) 328 329 // Run tests 330 331 // 1. number of proposers 332 totalWeights := uint64(0) 333 for _, v := range validators { 334 totalWeights += v.Weight() 335 } 336 assert.Equal(t, totalWeights, uint64(len(valSet.proposers))) 337 338 // 2. weight and appearance frequency 339 for _, v := range validators { 340 weight := v.Weight() 341 appearance := uint64(0) 342 for _, p := range valSet.proposers { 343 if v.Address() == p.Address() { 344 appearance++ 345 } 346 } 347 assert.Equal(t, weight, appearance) 348 } 349 } 350 351 func TestWeightedCouncil_RemoveValidator(t *testing.T) { 352 validators := makeTestValidators(testNonZeroWeights) 353 valSet := makeTestWeightedCouncil(testNonZeroWeights) 354 runRefreshForTest(valSet) 355 356 for _, val := range validators { 357 358 _, removedVal := valSet.GetByAddress(val.Address()) 359 if removedVal == nil { 360 t.Errorf("Fail to find validator with address %v", removedVal.Address().String()) 361 } 362 363 if !valSet.RemoveValidator(removedVal.Address()) { 364 t.Errorf("Fail to remove validator %v", removedVal.String()) 365 } 366 367 // check whether removedVal is really removed from validators 368 for _, v := range valSet.validators { 369 if removedVal.Address() == v.Address() { 370 t.Errorf("Validator(%v) does not removed from validators", removedVal.Address().String()) 371 } 372 } 373 374 // check whether removedVal is also removed from proposers immediately 375 for _, p := range valSet.proposers { 376 if removedVal.Address() == p.Address() { 377 t.Errorf("Validator(%v) does not removed from proposers", removedVal.Address().String()) 378 } 379 } 380 } 381 382 assert.Equal(t, uint64(0), valSet.Size()) 383 assert.Equal(t, 0, len(valSet.Proposers())) 384 } 385 386 func TestWeightedCouncil_RefreshAfterRemoveValidator(t *testing.T) { 387 validators := makeTestValidators(testNonZeroWeights) 388 valSet := makeTestWeightedCouncil(testNonZeroWeights) 389 runRefreshForTest(valSet) 390 391 for _, val := range validators { 392 393 _, removedVal := valSet.GetByAddress(val.Address()) 394 if removedVal == nil { 395 t.Errorf("Fail to find validator with address %v", removedVal.Address().String()) 396 } 397 398 if !valSet.RemoveValidator(removedVal.Address()) { 399 t.Errorf("Fail to remove validator %v", removedVal.String()) 400 } 401 402 // check whether removedVal is really removed from validators 403 for _, v := range valSet.validators { 404 if removedVal.Address() == v.Address() { 405 t.Errorf("Validator(%v) does not removed from validators", removedVal.Address().String()) 406 } 407 } 408 409 runRefreshForTest(valSet) 410 411 // check whether removedVal is excluded as expected when refreshing proposers 412 for _, p := range valSet.proposers { 413 if removedVal.Address() == p.Address() { 414 t.Errorf("Validator(%v) does not removed from proposers", removedVal.Address().String()) 415 } 416 } 417 } 418 419 assert.Equal(t, uint64(0), valSet.Size()) 420 assert.Equal(t, 0, len(valSet.Proposers())) 421 } 422 423 func runRefreshForTest(valSet *weightedCouncil) { 424 hashString := strings.TrimPrefix(testPrevHash.Hex(), "0x") 425 if len(hashString) > 15 { 426 hashString = hashString[:15] 427 } 428 seed, _ := strconv.ParseInt(hashString, 16, 64) 429 valSet.refreshProposers(seed, 0) 430 } 431 432 func TestWeightedCouncil_SetSubGroupSize(t *testing.T) { 433 validators := makeTestValidators(testNonZeroWeights) 434 valSet := makeTestWeightedCouncil(testNonZeroWeights) 435 436 validatorsLen := len(validators) 437 438 for i := 1; i < validatorsLen; i++ { 439 valSet.SetSubGroupSize(uint64(i)) 440 441 expectedSubGroupSize := uint64(i) 442 gottenSubGroupSize := valSet.SubGroupSize() 443 444 if expectedSubGroupSize != gottenSubGroupSize { 445 t.Errorf("SubGroupSize should be %v but gotten SubGroupSize is %v", expectedSubGroupSize, gottenSubGroupSize) 446 } 447 } 448 } 449 450 func TestWeightedCouncil_SubListWithProposer(t *testing.T) { 451 var ( 452 validators = makeTestValidators(testNonZeroWeights) 453 prevHash = crypto.Keccak256Hash([]byte("This is a test")) 454 valSet = makeTestWeightedCouncil(testNonZeroWeights) 455 456 BlockBeforeHF = big.NewInt(4) 457 HFBlock = big.NewInt(5) 458 BlockAfterHF = big.NewInt(6) 459 460 expectIndexOfSubsetLenTest = []int{1, 2, 7, 3, 11, 6, 9, 4, 0, 8, 12, 10} 461 expectIndexOfRoundTestBeforeIstanbulCompatible = [][]int{ 462 {1, 2, 7, 3, 11, 6, 9, 4, 0, 8, 12, 10}, 463 {2, 3, 7, 1, 11, 6, 9, 4, 0, 8, 12, 10}, 464 {3, 4, 7, 1, 11, 6, 9, 2, 0, 8, 12, 10}, 465 {4, 5, 7, 1, 11, 6, 9, 2, 0, 8, 12, 10}, 466 {5, 6, 7, 1, 11, 4, 9, 2, 0, 8, 12, 10}, 467 {6, 7, 5, 1, 11, 4, 9, 2, 0, 8, 12, 10}, 468 {7, 8, 5, 1, 11, 4, 9, 2, 0, 6, 12, 10}, 469 {8, 9, 5, 1, 11, 4, 7, 2, 0, 6, 12, 10}, 470 {9, 10, 5, 1, 11, 4, 7, 2, 0, 6, 12, 8}, 471 {10, 11, 5, 1, 9, 4, 7, 2, 0, 6, 12, 8}, 472 {11, 12, 5, 1, 9, 4, 7, 2, 0, 6, 10, 8}, 473 {12, 0, 6, 2, 10, 5, 8, 3, 1, 7, 11, 9}, 474 {0, 1, 7, 3, 11, 6, 9, 4, 2, 8, 12, 10}, 475 {1, 2, 7, 3, 11, 6, 9, 4, 0, 8, 12, 10}, 476 {2, 3, 7, 1, 11, 6, 9, 4, 0, 8, 12, 10}, 477 } 478 expectIndexOfRoundTestAfterIstanbulCompatible = [][]int{ 479 {1, 2, 7, 3, 11, 6, 9, 4, 0, 8, 12, 10}, 480 {2, 3, 6, 8, 10, 9, 1, 11, 5, 0, 4, 7}, 481 {3, 4, 10, 5, 8, 0, 7, 9, 12, 6, 1, 11}, 482 {4, 5, 6, 0, 7, 1, 3, 12, 2, 8, 9, 11}, 483 {5, 6, 4, 9, 12, 7, 0, 3, 8, 2, 1, 11}, 484 {6, 7, 2, 3, 8, 9, 11, 12, 5, 1, 4, 0}, 485 {7, 8, 3, 11, 5, 10, 0, 1, 2, 6, 9, 12}, 486 {8, 9, 5, 7, 11, 3, 1, 0, 10, 6, 4, 12}, 487 {9, 10, 3, 7, 5, 6, 2, 0, 12, 8, 11, 1}, 488 {10, 11, 7, 1, 0, 9, 8, 6, 12, 5, 2, 4}, 489 {11, 12, 4, 8, 1, 6, 0, 3, 9, 10, 2, 7}, 490 {12, 0, 7, 2, 4, 1, 6, 10, 9, 11, 8, 3}, 491 {0, 1, 9, 8, 2, 3, 10, 5, 7, 12, 4, 6}, 492 {1, 2, 11, 10, 6, 8, 7, 4, 9, 12, 0, 5}, 493 {2, 3, 4, 8, 6, 5, 11, 1, 12, 0, 9, 10}, 494 } 495 ) 496 497 getExpectSubList := func(indices []int) []istanbul.Validator { 498 var expectSubList []istanbul.Validator 499 for _, index := range indices { 500 expectSubList = append(expectSubList, validators[index]) 501 } 502 return expectSubList 503 } 504 505 fork.SetHardForkBlockNumberConfig(¶ms.ChainConfig{IstanbulCompatibleBlock: HFBlock}) 506 defer fork.ClearHardForkBlockNumberConfig() 507 508 // SubsetLen test: various subset length test 509 valSet.SetBlockNum(1) 510 for testSubsetLen := 2; testSubsetLen < len(validators); testSubsetLen++ { 511 // set committee size and calculate proposer 512 valSet.SetSubGroupSize(uint64(testSubsetLen)) 513 valSet.CalcProposer(valSet.GetProposer().Address(), uint64(0)) 514 515 // get committee list 516 expectSubList := getExpectSubList(expectIndexOfSubsetLenTest[0:testSubsetLen]) 517 518 // compare the subList of valSet with expected committee list 519 viewBeforeHF := &istanbul.View{Sequence: BlockBeforeHF, Round: big.NewInt(int64(0))} 520 viewAfterHF := &istanbul.View{Sequence: BlockAfterHF, Round: big.NewInt(int64(0))} 521 assert.Equal(t, expectSubList, valSet.SubList(prevHash, viewBeforeHF), "test Subset length: %d(before istanbulCompatible)", testSubsetLen) 522 assert.Equal(t, expectSubList, valSet.SubList(prevHash, viewAfterHF), "test subset length: %d(after istanbulCompatible)", testSubsetLen) 523 } 524 525 // Check: compare the size of the test data arrays 526 assert.Equal(t, len(expectIndexOfRoundTestBeforeIstanbulCompatible), len(expectIndexOfRoundTestAfterIstanbulCompatible)) 527 528 // Round test: various round test 529 valSet.SetBlockNum(1) 530 valSet.SetSubGroupSize(uint64(len(validators) - 1)) 531 for round := 0; round < len(expectIndexOfRoundTestBeforeIstanbulCompatible); round++ { 532 // calculate proposer and set view with test round value 533 valSet.CalcProposer(valSet.GetProposer().Address(), uint64(round)) 534 535 // get committee list 536 expectSubListBeforeHF := getExpectSubList(expectIndexOfRoundTestBeforeIstanbulCompatible[round]) 537 expectSubListAfterHF := getExpectSubList(expectIndexOfRoundTestAfterIstanbulCompatible[round]) 538 539 // compare the subList of valSet with expected committee list 540 viewBeforeHF := &istanbul.View{Sequence: BlockBeforeHF, Round: big.NewInt(int64(round))} 541 viewAfterHF := &istanbul.View{Sequence: BlockAfterHF, Round: big.NewInt(int64(round))} 542 assert.Equal(t, expectSubListBeforeHF, valSet.SubList(prevHash, viewBeforeHF), "test round: %d(before istanbulCompatible)", round) 543 assert.Equal(t, expectSubListAfterHF, valSet.SubList(prevHash, viewAfterHF), "test round: %d(after istanbulCompatible)", round) 544 } 545 } 546 547 func TestWeightedCouncil_Randao(t *testing.T) { 548 var ( 549 forkNum = uint64(5) 550 validators = makeTestWeightedCouncil(nil).List() 551 valSize = uint64(len(validators)) 552 ) 553 fork.SetHardForkBlockNumberConfig(¶ms.ChainConfig{ 554 RandaoCompatibleBlock: big.NewInt(int64(forkNum)), 555 }) 556 defer fork.ClearHardForkBlockNumberConfig() 557 valSet := makeTestWeightedCouncil(nil) 558 559 testcases := []struct { 560 blockNum uint64 561 round uint64 562 committeeSize uint64 563 mixHash []byte 564 expectedProposer istanbul.Validator 565 expectedCommittee []istanbul.Validator 566 }{ 567 { // Before fork 568 blockNum: forkNum - 2, 569 round: 0, 570 committeeSize: valSize + 1, 571 mixHash: testMixHash, 572 expectedProposer: validators[forkNum-2], 573 expectedCommittee: validators, 574 }, 575 { // After fork 576 blockNum: forkNum - 1, 577 round: 0, 578 committeeSize: valSize + 1, 579 mixHash: testMixHash, 580 expectedProposer: SelectRandaoCommittee(validators, valSize+1, testMixHash)[0], 581 expectedCommittee: validators, 582 }, 583 { // nil MixHash 584 blockNum: forkNum + 10, // expect log "no mixHash number=(forkNum+10)" 585 round: 0, 586 committeeSize: valSize - 1, 587 mixHash: nil, 588 expectedProposer: validators[0], // fall back to roundRobinProposer 589 expectedCommittee: nil, // SubList fails. 590 }, 591 { // IsSubset() == true 592 blockNum: forkNum, 593 round: 0, 594 committeeSize: valSize - 1, 595 mixHash: testMixHash, 596 expectedProposer: SelectRandaoCommittee(validators, valSize-1, testMixHash)[0], 597 expectedCommittee: SelectRandaoCommittee(validators, valSize-1, testMixHash), 598 }, 599 { // IsSubset() == false 600 blockNum: forkNum, 601 round: 0, 602 committeeSize: valSize + 1, 603 mixHash: testMixHash, 604 expectedProposer: SelectRandaoCommittee(validators, valSize+1, testMixHash)[0], 605 expectedCommittee: validators, 606 }, 607 { // Nonzero round 608 blockNum: forkNum, 609 round: 2, 610 committeeSize: valSize - 1, 611 mixHash: testMixHash, 612 expectedProposer: SelectRandaoCommittee(validators, valSize-1, testMixHash)[2], 613 expectedCommittee: SelectRandaoCommittee(validators, valSize-1, testMixHash), 614 }, 615 } 616 617 for i, tc := range testcases { 618 valSet.SetBlockNum(tc.blockNum) 619 valSet.SetSubGroupSize(tc.committeeSize) 620 valSet.SetMixHash(tc.mixHash) 621 622 view := &istanbul.View{ 623 Sequence: big.NewInt(int64(tc.blockNum)), 624 Round: big.NewInt(int64(tc.round)), 625 } 626 627 // The lastProposer is ignored by weightedRandomProposer 628 // but it is used by roundRobinProposer. If lastProposer = 0x0, 629 // then roundRobinProposer returns validators[round]. 630 valSet.CalcProposer(common.Address{}, uint64(tc.round)) 631 proposer := valSet.GetProposer() 632 assert.Equal(t, tc.expectedProposer, proposer, "tc[%d]", i) 633 634 committee := valSet.SubList(testPrevHash, view) 635 assert.Equal(t, tc.expectedCommittee, committee, "tc[%d]", i) 636 } 637 } 638 639 func TestWeightedCouncil_Copy(t *testing.T) { 640 a := makeTestWeightedCouncil(testNonZeroWeights) 641 a.SetSubGroupSize(21) 642 a.SetBlockNum(1234) 643 a.SetMixHash(testMixHash) 644 645 b := a.Copy().(*weightedCouncil) 646 647 assert.Equal(t, a.subSize, b.subSize) 648 assert.Equal(t, a.demotedValidators, b.demotedValidators) 649 assert.Equal(t, a.validators, b.validators) 650 assert.Equal(t, a.policy, b.policy) 651 652 assert.Equal(t, a.proposer, b.proposer) 653 assert.Equal(t, a.proposers, b.proposers) 654 assert.Equal(t, a.proposersBlockNum, b.proposersBlockNum) 655 assert.Equal(t, a.stakingInfo, b.stakingInfo) 656 assert.Equal(t, a.blockNum, b.blockNum) 657 assert.Equal(t, a.mixHash, b.mixHash) 658 659 assert.Equal(t, a.GetProposer(), b.GetProposer()) 660 }