github.com/evdatsion/aphelion-dpos-bft@v0.32.1/state/state_test.go (about) 1 package state_test 2 3 import ( 4 "bytes" 5 "fmt" 6 "math" 7 "math/big" 8 "os" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 abci "github.com/evdatsion/aphelion-dpos-bft/abci/types" 14 "github.com/evdatsion/aphelion-dpos-bft/crypto/ed25519" 15 cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common" 16 dbm "github.com/evdatsion/aphelion-dpos-bft/libs/db" 17 sm "github.com/evdatsion/aphelion-dpos-bft/state" 18 19 cfg "github.com/evdatsion/aphelion-dpos-bft/config" 20 "github.com/evdatsion/aphelion-dpos-bft/types" 21 ) 22 23 // setupTestCase does setup common to all test cases. 24 func setupTestCase(t *testing.T) (func(t *testing.T), dbm.DB, sm.State) { 25 config := cfg.ResetTestRoot("state_") 26 dbType := dbm.DBBackendType(config.DBBackend) 27 stateDB := dbm.NewDB("state", dbType, config.DBDir()) 28 state, err := sm.LoadStateFromDBOrGenesisFile(stateDB, config.GenesisFile()) 29 assert.NoError(t, err, "expected no error on LoadStateFromDBOrGenesisFile") 30 31 tearDown := func(t *testing.T) { os.RemoveAll(config.RootDir) } 32 33 return tearDown, stateDB, state 34 } 35 36 // TestStateCopy tests the correct copying behaviour of State. 37 func TestStateCopy(t *testing.T) { 38 tearDown, _, state := setupTestCase(t) 39 defer tearDown(t) 40 // nolint: vetshadow 41 assert := assert.New(t) 42 43 stateCopy := state.Copy() 44 45 assert.True(state.Equals(stateCopy), 46 fmt.Sprintf("expected state and its copy to be identical.\ngot: %v\nexpected: %v\n", 47 stateCopy, state)) 48 49 stateCopy.LastBlockHeight++ 50 assert.False(state.Equals(stateCopy), fmt.Sprintf(`expected states to be different. got same 51 %v`, state)) 52 } 53 54 //TestMakeGenesisStateNilValidators tests state's consistency when genesis file's validators field is nil. 55 func TestMakeGenesisStateNilValidators(t *testing.T) { 56 doc := types.GenesisDoc{ 57 ChainID: "dummy", 58 Validators: nil, 59 } 60 require.Nil(t, doc.ValidateAndComplete()) 61 state, err := sm.MakeGenesisState(&doc) 62 require.Nil(t, err) 63 require.Equal(t, 0, len(state.Validators.Validators)) 64 require.Equal(t, 0, len(state.NextValidators.Validators)) 65 } 66 67 // TestStateSaveLoad tests saving and loading State from a db. 68 func TestStateSaveLoad(t *testing.T) { 69 tearDown, stateDB, state := setupTestCase(t) 70 defer tearDown(t) 71 // nolint: vetshadow 72 assert := assert.New(t) 73 74 state.LastBlockHeight++ 75 sm.SaveState(stateDB, state) 76 77 loadedState := sm.LoadState(stateDB) 78 assert.True(state.Equals(loadedState), 79 fmt.Sprintf("expected state and its copy to be identical.\ngot: %v\nexpected: %v\n", 80 loadedState, state)) 81 } 82 83 // TestABCIResponsesSaveLoad tests saving and loading ABCIResponses. 84 func TestABCIResponsesSaveLoad1(t *testing.T) { 85 tearDown, stateDB, state := setupTestCase(t) 86 defer tearDown(t) 87 // nolint: vetshadow 88 assert := assert.New(t) 89 90 state.LastBlockHeight++ 91 92 // Build mock responses. 93 block := makeBlock(state, 2) 94 abciResponses := sm.NewABCIResponses(block) 95 abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Events: nil} 96 abciResponses.DeliverTx[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Events: nil} 97 abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{ 98 types.TM2PB.NewValidatorUpdate(ed25519.GenPrivKey().PubKey(), 10), 99 }} 100 101 sm.SaveABCIResponses(stateDB, block.Height, abciResponses) 102 loadedABCIResponses, err := sm.LoadABCIResponses(stateDB, block.Height) 103 assert.Nil(err) 104 assert.Equal(abciResponses, loadedABCIResponses, 105 fmt.Sprintf("ABCIResponses don't match:\ngot: %v\nexpected: %v\n", 106 loadedABCIResponses, abciResponses)) 107 } 108 109 // TestResultsSaveLoad tests saving and loading ABCI results. 110 func TestABCIResponsesSaveLoad2(t *testing.T) { 111 tearDown, stateDB, _ := setupTestCase(t) 112 defer tearDown(t) 113 // nolint: vetshadow 114 assert := assert.New(t) 115 116 cases := [...]struct { 117 // Height is implied to equal index+2, 118 // as block 1 is created from genesis. 119 added []*abci.ResponseDeliverTx 120 expected types.ABCIResults 121 }{ 122 0: { 123 nil, 124 nil, 125 }, 126 1: { 127 []*abci.ResponseDeliverTx{ 128 {Code: 32, Data: []byte("Hello"), Log: "Huh?"}, 129 }, 130 types.ABCIResults{ 131 {Code: 32, Data: []byte("Hello")}, 132 }}, 133 2: { 134 []*abci.ResponseDeliverTx{ 135 {Code: 383}, 136 { 137 Data: []byte("Gotcha!"), 138 Events: []abci.Event{ 139 {Type: "type1", Attributes: []cmn.KVPair{{Key: []byte("a"), Value: []byte("1")}}}, 140 {Type: "type2", Attributes: []cmn.KVPair{{Key: []byte("build"), Value: []byte("stuff")}}}, 141 }, 142 }, 143 }, 144 types.ABCIResults{ 145 {Code: 383, Data: nil}, 146 {Code: 0, Data: []byte("Gotcha!")}, 147 }}, 148 3: { 149 nil, 150 nil, 151 }, 152 } 153 154 // Query all before, this should return error. 155 for i := range cases { 156 h := int64(i + 1) 157 res, err := sm.LoadABCIResponses(stateDB, h) 158 assert.Error(err, "%d: %#v", i, res) 159 } 160 161 // Add all cases. 162 for i, tc := range cases { 163 h := int64(i + 1) // last block height, one below what we save 164 responses := &sm.ABCIResponses{ 165 DeliverTx: tc.added, 166 EndBlock: &abci.ResponseEndBlock{}, 167 } 168 sm.SaveABCIResponses(stateDB, h, responses) 169 } 170 171 // Query all before, should return expected value. 172 for i, tc := range cases { 173 h := int64(i + 1) 174 res, err := sm.LoadABCIResponses(stateDB, h) 175 assert.NoError(err, "%d", i) 176 assert.Equal(tc.expected.Hash(), res.ResultsHash(), "%d", i) 177 } 178 } 179 180 // TestValidatorSimpleSaveLoad tests saving and loading validators. 181 func TestValidatorSimpleSaveLoad(t *testing.T) { 182 tearDown, stateDB, state := setupTestCase(t) 183 defer tearDown(t) 184 // nolint: vetshadow 185 assert := assert.New(t) 186 187 // Can't load anything for height 0. 188 v, err := sm.LoadValidators(stateDB, 0) 189 assert.IsType(sm.ErrNoValSetForHeight{}, err, "expected err at height 0") 190 191 // Should be able to load for height 1. 192 v, err = sm.LoadValidators(stateDB, 1) 193 assert.Nil(err, "expected no err at height 1") 194 assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match") 195 196 // Should be able to load for height 2. 197 v, err = sm.LoadValidators(stateDB, 2) 198 assert.Nil(err, "expected no err at height 2") 199 assert.Equal(v.Hash(), state.NextValidators.Hash(), "expected validator hashes to match") 200 201 // Increment height, save; should be able to load for next & next next height. 202 state.LastBlockHeight++ 203 nextHeight := state.LastBlockHeight + 1 204 sm.SaveValidatorsInfo(stateDB, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators) 205 vp0, err := sm.LoadValidators(stateDB, nextHeight+0) 206 assert.Nil(err, "expected no err") 207 vp1, err := sm.LoadValidators(stateDB, nextHeight+1) 208 assert.Nil(err, "expected no err") 209 assert.Equal(vp0.Hash(), state.Validators.Hash(), "expected validator hashes to match") 210 assert.Equal(vp1.Hash(), state.NextValidators.Hash(), "expected next validator hashes to match") 211 } 212 213 // TestValidatorChangesSaveLoad tests saving and loading a validator set with changes. 214 func TestOneValidatorChangesSaveLoad(t *testing.T) { 215 tearDown, stateDB, state := setupTestCase(t) 216 defer tearDown(t) 217 218 // Change vals at these heights. 219 changeHeights := []int64{1, 2, 4, 5, 10, 15, 16, 17, 20} 220 N := len(changeHeights) 221 222 // Build the validator history by running updateState 223 // with the right validator set for each height. 224 highestHeight := changeHeights[N-1] + 5 225 changeIndex := 0 226 _, val := state.Validators.GetByIndex(0) 227 power := val.VotingPower 228 var err error 229 var validatorUpdates []*types.Validator 230 for i := int64(1); i < highestHeight; i++ { 231 // When we get to a change height, use the next pubkey. 232 if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] { 233 changeIndex++ 234 power++ 235 } 236 header, blockID, responses := makeHeaderPartsResponsesValPowerChange(state, power) 237 validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates) 238 require.NoError(t, err) 239 state, err = sm.UpdateState(state, blockID, &header, responses, validatorUpdates) 240 require.NoError(t, err) 241 nextHeight := state.LastBlockHeight + 1 242 sm.SaveValidatorsInfo(stateDB, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators) 243 } 244 245 // On each height change, increment the power by one. 246 testCases := make([]int64, highestHeight) 247 changeIndex = 0 248 power = val.VotingPower 249 for i := int64(1); i < highestHeight+1; i++ { 250 // We get to the height after a change height use the next pubkey (note 251 // our counter starts at 0 this time). 252 if changeIndex < len(changeHeights) && i == changeHeights[changeIndex]+1 { 253 changeIndex++ 254 power++ 255 } 256 testCases[i-1] = power 257 } 258 259 for i, power := range testCases { 260 v, err := sm.LoadValidators(stateDB, int64(i+1+1)) // +1 because vset changes delayed by 1 block. 261 assert.Nil(t, err, fmt.Sprintf("expected no err at height %d", i)) 262 assert.Equal(t, v.Size(), 1, "validator set size is greater than 1: %d", v.Size()) 263 _, val := v.GetByIndex(0) 264 265 assert.Equal(t, val.VotingPower, power, fmt.Sprintf(`unexpected powerat 266 height %d`, i)) 267 } 268 } 269 270 func TestProposerFrequency(t *testing.T) { 271 272 // some explicit test cases 273 testCases := []struct { 274 powers []int64 275 }{ 276 // 2 vals 277 {[]int64{1, 1}}, 278 {[]int64{1, 2}}, 279 {[]int64{1, 100}}, 280 {[]int64{5, 5}}, 281 {[]int64{5, 100}}, 282 {[]int64{50, 50}}, 283 {[]int64{50, 100}}, 284 {[]int64{1, 1000}}, 285 286 // 3 vals 287 {[]int64{1, 1, 1}}, 288 {[]int64{1, 2, 3}}, 289 {[]int64{1, 2, 3}}, 290 {[]int64{1, 1, 10}}, 291 {[]int64{1, 1, 100}}, 292 {[]int64{1, 10, 100}}, 293 {[]int64{1, 1, 1000}}, 294 {[]int64{1, 10, 1000}}, 295 {[]int64{1, 100, 1000}}, 296 297 // 4 vals 298 {[]int64{1, 1, 1, 1}}, 299 {[]int64{1, 2, 3, 4}}, 300 {[]int64{1, 1, 1, 10}}, 301 {[]int64{1, 1, 1, 100}}, 302 {[]int64{1, 1, 1, 1000}}, 303 {[]int64{1, 1, 10, 100}}, 304 {[]int64{1, 1, 10, 1000}}, 305 {[]int64{1, 1, 100, 1000}}, 306 {[]int64{1, 10, 100, 1000}}, 307 } 308 309 for caseNum, testCase := range testCases { 310 // run each case 5 times to sample different 311 // initial priorities 312 for i := 0; i < 5; i++ { 313 valSet := genValSetWithPowers(testCase.powers) 314 testProposerFreq(t, caseNum, valSet) 315 } 316 } 317 318 // some random test cases with up to 100 validators 319 maxVals := 100 320 maxPower := 1000 321 nTestCases := 5 322 for i := 0; i < nTestCases; i++ { 323 N := cmn.RandInt()%maxVals + 1 324 vals := make([]*types.Validator, N) 325 totalVotePower := int64(0) 326 for j := 0; j < N; j++ { 327 // make sure votePower > 0 328 votePower := int64(cmn.RandInt()%maxPower) + 1 329 totalVotePower += votePower 330 privVal := types.NewMockPV() 331 pubKey := privVal.GetPubKey() 332 val := types.NewValidator(pubKey, votePower) 333 val.ProposerPriority = cmn.RandInt64() 334 vals[j] = val 335 } 336 valSet := types.NewValidatorSet(vals) 337 valSet.RescalePriorities(totalVotePower) 338 testProposerFreq(t, i, valSet) 339 } 340 } 341 342 // new val set with given powers and random initial priorities 343 func genValSetWithPowers(powers []int64) *types.ValidatorSet { 344 size := len(powers) 345 vals := make([]*types.Validator, size) 346 totalVotePower := int64(0) 347 for i := 0; i < size; i++ { 348 totalVotePower += powers[i] 349 val := types.NewValidator(ed25519.GenPrivKey().PubKey(), powers[i]) 350 val.ProposerPriority = cmn.RandInt64() 351 vals[i] = val 352 } 353 valSet := types.NewValidatorSet(vals) 354 valSet.RescalePriorities(totalVotePower) 355 return valSet 356 } 357 358 // test a proposer appears as frequently as expected 359 func testProposerFreq(t *testing.T, caseNum int, valSet *types.ValidatorSet) { 360 N := valSet.Size() 361 totalPower := valSet.TotalVotingPower() 362 363 // run the proposer selection and track frequencies 364 runMult := 1 365 runs := int(totalPower) * runMult 366 freqs := make([]int, N) 367 for i := 0; i < runs; i++ { 368 prop := valSet.GetProposer() 369 idx, _ := valSet.GetByAddress(prop.Address) 370 freqs[idx] += 1 371 valSet.IncrementProposerPriority(1) 372 } 373 374 // assert frequencies match expected (max off by 1) 375 for i, freq := range freqs { 376 _, val := valSet.GetByIndex(i) 377 expectFreq := int(val.VotingPower) * runMult 378 gotFreq := freq 379 abs := int(math.Abs(float64(expectFreq - gotFreq))) 380 381 // max bound on expected vs seen freq was proven 382 // to be 1 for the 2 validator case in 383 // https://github.com/cwgoes/tm-proposer-idris 384 // and inferred to generalize to N-1 385 bound := N - 1 386 require.True(t, abs <= bound, fmt.Sprintf("Case %d val %d (%d): got %d, expected %d", caseNum, i, N, gotFreq, expectFreq)) 387 } 388 } 389 390 // TestProposerPriorityDoesNotGetResetToZero assert that we preserve accum when calling updateState 391 // see https://github.com/evdatsion/aphelion-dpos-bft/issues/2718 392 func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { 393 tearDown, _, state := setupTestCase(t) 394 defer tearDown(t) 395 val1VotingPower := int64(10) 396 val1PubKey := ed25519.GenPrivKey().PubKey() 397 val1 := &types.Validator{Address: val1PubKey.Address(), PubKey: val1PubKey, VotingPower: val1VotingPower} 398 399 state.Validators = types.NewValidatorSet([]*types.Validator{val1}) 400 state.NextValidators = state.Validators 401 402 // NewValidatorSet calls IncrementProposerPriority but uses on a copy of val1 403 assert.EqualValues(t, 0, val1.ProposerPriority) 404 405 block := makeBlock(state, state.LastBlockHeight+1) 406 blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} 407 abciResponses := &sm.ABCIResponses{ 408 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 409 } 410 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 411 require.NoError(t, err) 412 updatedState, err := sm.UpdateState(state, blockID, &block.Header, abciResponses, validatorUpdates) 413 assert.NoError(t, err) 414 curTotal := val1VotingPower 415 // one increment step and one validator: 0 + power - total_power == 0 416 assert.Equal(t, 0+val1VotingPower-curTotal, updatedState.NextValidators.Validators[0].ProposerPriority) 417 418 // add a validator 419 val2PubKey := ed25519.GenPrivKey().PubKey() 420 val2VotingPower := int64(100) 421 updateAddVal := abci.ValidatorUpdate{PubKey: types.TM2PB.PubKey(val2PubKey), Power: val2VotingPower} 422 validatorUpdates, err = types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{updateAddVal}) 423 assert.NoError(t, err) 424 updatedState2, err := sm.UpdateState(updatedState, blockID, &block.Header, abciResponses, validatorUpdates) 425 assert.NoError(t, err) 426 427 require.Equal(t, len(updatedState2.NextValidators.Validators), 2) 428 _, updatedVal1 := updatedState2.NextValidators.GetByAddress(val1PubKey.Address()) 429 _, addedVal2 := updatedState2.NextValidators.GetByAddress(val2PubKey.Address()) 430 431 // adding a validator should not lead to a ProposerPriority equal to zero (unless the combination of averaging and 432 // incrementing would cause so; which is not the case here) 433 // Steps from adding new validator: 434 // 0 - val1 prio is 0, TVP after add: 435 wantVal1Prio := int64(0) 436 totalPowerAfter := val1VotingPower + val2VotingPower 437 // 1. Add - Val2 should be initially added with (-123) => 438 wantVal2Prio := -(totalPowerAfter + (totalPowerAfter >> 3)) 439 // 2. Scale - noop 440 // 3. Center - with avg, resulting val2:-61, val1:62 441 avg := big.NewInt(0).Add(big.NewInt(wantVal1Prio), big.NewInt(wantVal2Prio)) 442 avg.Div(avg, big.NewInt(2)) 443 wantVal2Prio = wantVal2Prio - avg.Int64() // -61 444 wantVal1Prio = wantVal1Prio - avg.Int64() // 62 445 446 // 4. Steps from IncrementProposerPriority 447 wantVal1Prio = wantVal1Prio + val1VotingPower // 72 448 wantVal2Prio = wantVal2Prio + val2VotingPower // 39 449 wantVal1Prio = wantVal1Prio - totalPowerAfter // -38 as val1 is proposer 450 451 assert.Equal(t, wantVal1Prio, updatedVal1.ProposerPriority) 452 assert.Equal(t, wantVal2Prio, addedVal2.ProposerPriority) 453 454 // Updating a validator does not reset the ProposerPriority to zero: 455 // 1. Add - Val2 VotingPower change to 1 => 456 updatedVotingPowVal2 := int64(1) 457 updateVal := abci.ValidatorUpdate{PubKey: types.TM2PB.PubKey(val2PubKey), Power: updatedVotingPowVal2} 458 validatorUpdates, err = types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{updateVal}) 459 assert.NoError(t, err) 460 461 // this will cause the diff of priorities (77) 462 // to be larger than threshold == 2*totalVotingPower (22): 463 updatedState3, err := sm.UpdateState(updatedState2, blockID, &block.Header, abciResponses, validatorUpdates) 464 assert.NoError(t, err) 465 466 require.Equal(t, len(updatedState3.NextValidators.Validators), 2) 467 _, prevVal1 := updatedState3.Validators.GetByAddress(val1PubKey.Address()) 468 _, prevVal2 := updatedState3.Validators.GetByAddress(val2PubKey.Address()) 469 _, updatedVal1 = updatedState3.NextValidators.GetByAddress(val1PubKey.Address()) 470 _, updatedVal2 := updatedState3.NextValidators.GetByAddress(val2PubKey.Address()) 471 472 // 2. Scale 473 // old prios: v1(10):-38, v2(1):39 474 wantVal1Prio = prevVal1.ProposerPriority 475 wantVal2Prio = prevVal2.ProposerPriority 476 // scale to diffMax = 22 = 2 * tvp, diff=39-(-38)=77 477 // new totalPower 478 totalPower := updatedVal1.VotingPower + updatedVal2.VotingPower 479 dist := wantVal2Prio - wantVal1Prio 480 // ratio := (dist + 2*totalPower - 1) / 2*totalPower = 98/22 = 4 481 ratio := (dist + 2*totalPower - 1) / (2 * totalPower) 482 // v1(10):-38/4, v2(1):39/4 483 wantVal1Prio /= ratio // -9 484 wantVal2Prio /= ratio // 9 485 486 // 3. Center - noop 487 // 4. IncrementProposerPriority() -> 488 // v1(10):-9+10, v2(1):9+1 -> v2 proposer so subsract tvp(11) 489 // v1(10):1, v2(1):-1 490 wantVal2Prio += updatedVal2.VotingPower // 10 -> prop 491 wantVal1Prio += updatedVal1.VotingPower // 1 492 wantVal2Prio -= totalPower // -1 493 494 assert.Equal(t, wantVal2Prio, updatedVal2.ProposerPriority) 495 assert.Equal(t, wantVal1Prio, updatedVal1.ProposerPriority) 496 } 497 498 func TestProposerPriorityProposerAlternates(t *testing.T) { 499 // Regression test that would fail if the inner workings of 500 // IncrementProposerPriority change. 501 // Additionally, make sure that same power validators alternate if both 502 // have the same voting power (and the 2nd was added later). 503 tearDown, _, state := setupTestCase(t) 504 defer tearDown(t) 505 val1VotingPower := int64(10) 506 val1PubKey := ed25519.GenPrivKey().PubKey() 507 val1 := &types.Validator{Address: val1PubKey.Address(), PubKey: val1PubKey, VotingPower: val1VotingPower} 508 509 // reset state validators to above validator 510 state.Validators = types.NewValidatorSet([]*types.Validator{val1}) 511 state.NextValidators = state.Validators 512 // we only have one validator: 513 assert.Equal(t, val1PubKey.Address(), state.Validators.Proposer.Address) 514 515 block := makeBlock(state, state.LastBlockHeight+1) 516 blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} 517 // no updates: 518 abciResponses := &sm.ABCIResponses{ 519 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 520 } 521 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 522 require.NoError(t, err) 523 524 updatedState, err := sm.UpdateState(state, blockID, &block.Header, abciResponses, validatorUpdates) 525 assert.NoError(t, err) 526 527 // 0 + 10 (initial prio) - 10 (avg) - 10 (mostest - total) = -10 528 totalPower := val1VotingPower 529 wantVal1Prio := 0 + val1VotingPower - totalPower 530 assert.Equal(t, wantVal1Prio, updatedState.NextValidators.Validators[0].ProposerPriority) 531 assert.Equal(t, val1PubKey.Address(), updatedState.NextValidators.Proposer.Address) 532 533 // add a validator with the same voting power as the first 534 val2PubKey := ed25519.GenPrivKey().PubKey() 535 updateAddVal := abci.ValidatorUpdate{PubKey: types.TM2PB.PubKey(val2PubKey), Power: val1VotingPower} 536 validatorUpdates, err = types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{updateAddVal}) 537 assert.NoError(t, err) 538 539 updatedState2, err := sm.UpdateState(updatedState, blockID, &block.Header, abciResponses, validatorUpdates) 540 assert.NoError(t, err) 541 542 require.Equal(t, len(updatedState2.NextValidators.Validators), 2) 543 assert.Equal(t, updatedState2.Validators, updatedState.NextValidators) 544 545 // val1 will still be proposer as val2 just got added: 546 assert.Equal(t, val1PubKey.Address(), updatedState.NextValidators.Proposer.Address) 547 assert.Equal(t, updatedState2.Validators.Proposer.Address, updatedState2.NextValidators.Proposer.Address) 548 assert.Equal(t, updatedState2.Validators.Proposer.Address, val1PubKey.Address()) 549 assert.Equal(t, updatedState2.NextValidators.Proposer.Address, val1PubKey.Address()) 550 551 _, updatedVal1 := updatedState2.NextValidators.GetByAddress(val1PubKey.Address()) 552 _, oldVal1 := updatedState2.Validators.GetByAddress(val1PubKey.Address()) 553 _, updatedVal2 := updatedState2.NextValidators.GetByAddress(val2PubKey.Address()) 554 555 // 1. Add 556 val2VotingPower := val1VotingPower 557 totalPower = val1VotingPower + val2VotingPower // 20 558 v2PrioWhenAddedVal2 := -(totalPower + (totalPower >> 3)) // -22 559 // 2. Scale - noop 560 // 3. Center 561 avgSum := big.NewInt(0).Add(big.NewInt(v2PrioWhenAddedVal2), big.NewInt(oldVal1.ProposerPriority)) 562 avg := avgSum.Div(avgSum, big.NewInt(2)) // -11 563 expectedVal2Prio := v2PrioWhenAddedVal2 - avg.Int64() // -11 564 expectedVal1Prio := oldVal1.ProposerPriority - avg.Int64() // 11 565 // 4. Increment 566 expectedVal2Prio = expectedVal2Prio + val2VotingPower // -11 + 10 = -1 567 expectedVal1Prio = expectedVal1Prio + val1VotingPower // 11 + 10 == 21 568 expectedVal1Prio = expectedVal1Prio - totalPower // 1, val1 proposer 569 570 assert.EqualValues(t, expectedVal1Prio, updatedVal1.ProposerPriority) 571 assert.EqualValues(t, expectedVal2Prio, updatedVal2.ProposerPriority, "unexpected proposer priority for validator: %v", updatedVal2) 572 573 validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 574 require.NoError(t, err) 575 576 updatedState3, err := sm.UpdateState(updatedState2, blockID, &block.Header, abciResponses, validatorUpdates) 577 assert.NoError(t, err) 578 579 assert.Equal(t, updatedState3.Validators.Proposer.Address, updatedState3.NextValidators.Proposer.Address) 580 581 assert.Equal(t, updatedState3.Validators, updatedState2.NextValidators) 582 _, updatedVal1 = updatedState3.NextValidators.GetByAddress(val1PubKey.Address()) 583 _, updatedVal2 = updatedState3.NextValidators.GetByAddress(val2PubKey.Address()) 584 585 // val1 will still be proposer: 586 assert.Equal(t, val1PubKey.Address(), updatedState3.NextValidators.Proposer.Address) 587 588 // check if expected proposer prio is matched: 589 // Increment 590 expectedVal2Prio2 := expectedVal2Prio + val2VotingPower // -1 + 10 = 9 591 expectedVal1Prio2 := expectedVal1Prio + val1VotingPower // 1 + 10 == 11 592 expectedVal1Prio2 = expectedVal1Prio2 - totalPower // -9, val1 proposer 593 594 assert.EqualValues(t, expectedVal1Prio2, updatedVal1.ProposerPriority, "unexpected proposer priority for validator: %v", updatedVal2) 595 assert.EqualValues(t, expectedVal2Prio2, updatedVal2.ProposerPriority, "unexpected proposer priority for validator: %v", updatedVal2) 596 597 // no changes in voting power and both validators have same voting power 598 // -> proposers should alternate: 599 oldState := updatedState3 600 abciResponses = &sm.ABCIResponses{ 601 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 602 } 603 validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 604 require.NoError(t, err) 605 606 oldState, err = sm.UpdateState(oldState, blockID, &block.Header, abciResponses, validatorUpdates) 607 assert.NoError(t, err) 608 expectedVal1Prio2 = 1 609 expectedVal2Prio2 = -1 610 expectedVal1Prio = -9 611 expectedVal2Prio = 9 612 613 for i := 0; i < 1000; i++ { 614 // no validator updates: 615 abciResponses := &sm.ABCIResponses{ 616 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 617 } 618 validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 619 require.NoError(t, err) 620 621 updatedState, err := sm.UpdateState(oldState, blockID, &block.Header, abciResponses, validatorUpdates) 622 assert.NoError(t, err) 623 // alternate (and cyclic priorities): 624 assert.NotEqual(t, updatedState.Validators.Proposer.Address, updatedState.NextValidators.Proposer.Address, "iter: %v", i) 625 assert.Equal(t, oldState.Validators.Proposer.Address, updatedState.NextValidators.Proposer.Address, "iter: %v", i) 626 627 _, updatedVal1 = updatedState.NextValidators.GetByAddress(val1PubKey.Address()) 628 _, updatedVal2 = updatedState.NextValidators.GetByAddress(val2PubKey.Address()) 629 630 if i%2 == 0 { 631 assert.Equal(t, updatedState.Validators.Proposer.Address, val2PubKey.Address()) 632 assert.Equal(t, expectedVal1Prio, updatedVal1.ProposerPriority) // -19 633 assert.Equal(t, expectedVal2Prio, updatedVal2.ProposerPriority) // 0 634 } else { 635 assert.Equal(t, updatedState.Validators.Proposer.Address, val1PubKey.Address()) 636 assert.Equal(t, expectedVal1Prio2, updatedVal1.ProposerPriority) // -9 637 assert.Equal(t, expectedVal2Prio2, updatedVal2.ProposerPriority) // -10 638 } 639 // update for next iteration: 640 oldState = updatedState 641 } 642 } 643 644 func TestLargeGenesisValidator(t *testing.T) { 645 tearDown, _, state := setupTestCase(t) 646 defer tearDown(t) 647 648 genesisVotingPower := int64(types.MaxTotalVotingPower / 1000) 649 genesisPubKey := ed25519.GenPrivKey().PubKey() 650 // fmt.Println("genesis addr: ", genesisPubKey.Address()) 651 genesisVal := &types.Validator{Address: genesisPubKey.Address(), PubKey: genesisPubKey, VotingPower: genesisVotingPower} 652 // reset state validators to above validator 653 state.Validators = types.NewValidatorSet([]*types.Validator{genesisVal}) 654 state.NextValidators = state.Validators 655 require.True(t, len(state.Validators.Validators) == 1) 656 657 // update state a few times with no validator updates 658 // asserts that the single validator's ProposerPrio stays the same 659 oldState := state 660 for i := 0; i < 10; i++ { 661 // no updates: 662 abciResponses := &sm.ABCIResponses{ 663 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 664 } 665 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 666 require.NoError(t, err) 667 668 block := makeBlock(oldState, oldState.LastBlockHeight+1) 669 blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} 670 671 updatedState, err := sm.UpdateState(oldState, blockID, &block.Header, abciResponses, validatorUpdates) 672 require.NoError(t, err) 673 // no changes in voting power (ProposerPrio += VotingPower == Voting in 1st round; than shiftByAvg == 0, 674 // than -Total == -Voting) 675 // -> no change in ProposerPrio (stays zero): 676 assert.EqualValues(t, oldState.NextValidators, updatedState.NextValidators) 677 assert.EqualValues(t, 0, updatedState.NextValidators.Proposer.ProposerPriority) 678 679 oldState = updatedState 680 } 681 // add another validator, do a few iterations (create blocks), 682 // add more validators with same voting power as the 2nd 683 // let the genesis validator "unbond", 684 // see how long it takes until the effect wears off and both begin to alternate 685 // see: https://github.com/evdatsion/aphelion-dpos-bft/issues/2960 686 firstAddedValPubKey := ed25519.GenPrivKey().PubKey() 687 firstAddedValVotingPower := int64(10) 688 firstAddedVal := abci.ValidatorUpdate{PubKey: types.TM2PB.PubKey(firstAddedValPubKey), Power: firstAddedValVotingPower} 689 validatorUpdates, err := types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{firstAddedVal}) 690 assert.NoError(t, err) 691 abciResponses := &sm.ABCIResponses{ 692 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}}, 693 } 694 block := makeBlock(oldState, oldState.LastBlockHeight+1) 695 blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} 696 updatedState, err := sm.UpdateState(oldState, blockID, &block.Header, abciResponses, validatorUpdates) 697 require.NoError(t, err) 698 699 lastState := updatedState 700 for i := 0; i < 200; i++ { 701 // no updates: 702 abciResponses := &sm.ABCIResponses{ 703 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 704 } 705 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 706 require.NoError(t, err) 707 708 block := makeBlock(lastState, lastState.LastBlockHeight+1) 709 blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} 710 711 updatedStateInner, err := sm.UpdateState(lastState, blockID, &block.Header, abciResponses, validatorUpdates) 712 require.NoError(t, err) 713 lastState = updatedStateInner 714 } 715 // set state to last state of above iteration 716 state = lastState 717 718 // set oldState to state before above iteration 719 oldState = updatedState 720 _, oldGenesisVal := oldState.NextValidators.GetByAddress(genesisVal.Address) 721 _, newGenesisVal := state.NextValidators.GetByAddress(genesisVal.Address) 722 _, addedOldVal := oldState.NextValidators.GetByAddress(firstAddedValPubKey.Address()) 723 _, addedNewVal := state.NextValidators.GetByAddress(firstAddedValPubKey.Address()) 724 // expect large negative proposer priority for both (genesis validator decreased, 2nd validator increased): 725 assert.True(t, oldGenesisVal.ProposerPriority > newGenesisVal.ProposerPriority) 726 assert.True(t, addedOldVal.ProposerPriority < addedNewVal.ProposerPriority) 727 728 // add 10 validators with the same voting power as the one added directly after genesis: 729 for i := 0; i < 10; i++ { 730 addedPubKey := ed25519.GenPrivKey().PubKey() 731 732 addedVal := abci.ValidatorUpdate{PubKey: types.TM2PB.PubKey(addedPubKey), Power: firstAddedValVotingPower} 733 validatorUpdates, err := types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{addedVal}) 734 assert.NoError(t, err) 735 736 abciResponses := &sm.ABCIResponses{ 737 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{addedVal}}, 738 } 739 block := makeBlock(oldState, oldState.LastBlockHeight+1) 740 blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} 741 state, err = sm.UpdateState(state, blockID, &block.Header, abciResponses, validatorUpdates) 742 require.NoError(t, err) 743 } 744 require.Equal(t, 10+2, len(state.NextValidators.Validators)) 745 746 // remove genesis validator: 747 removeGenesisVal := abci.ValidatorUpdate{PubKey: types.TM2PB.PubKey(genesisPubKey), Power: 0} 748 abciResponses = &sm.ABCIResponses{ 749 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}}, 750 } 751 block = makeBlock(oldState, oldState.LastBlockHeight+1) 752 blockID = types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} 753 validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 754 require.NoError(t, err) 755 updatedState, err = sm.UpdateState(state, blockID, &block.Header, abciResponses, validatorUpdates) 756 require.NoError(t, err) 757 // only the first added val (not the genesis val) should be left 758 assert.Equal(t, 11, len(updatedState.NextValidators.Validators)) 759 760 // call update state until the effect for the 3rd added validator 761 // being proposer for a long time after the genesis validator left wears off: 762 curState := updatedState 763 count := 0 764 isProposerUnchanged := true 765 for isProposerUnchanged { 766 abciResponses := &sm.ABCIResponses{ 767 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 768 } 769 validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 770 require.NoError(t, err) 771 block = makeBlock(curState, curState.LastBlockHeight+1) 772 blockID = types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} 773 curState, err = sm.UpdateState(curState, blockID, &block.Header, abciResponses, validatorUpdates) 774 require.NoError(t, err) 775 if !bytes.Equal(curState.Validators.Proposer.Address, curState.NextValidators.Proposer.Address) { 776 isProposerUnchanged = false 777 } 778 count++ 779 } 780 updatedState = curState 781 // the proposer changes after this number of blocks 782 firstProposerChangeExpectedAfter := 1 783 assert.Equal(t, firstProposerChangeExpectedAfter, count) 784 // store proposers here to see if we see them again in the same order: 785 numVals := len(updatedState.Validators.Validators) 786 proposers := make([]*types.Validator, numVals) 787 for i := 0; i < 100; i++ { 788 // no updates: 789 abciResponses := &sm.ABCIResponses{ 790 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 791 } 792 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 793 require.NoError(t, err) 794 795 block := makeBlock(updatedState, updatedState.LastBlockHeight+1) 796 blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} 797 798 updatedState, err = sm.UpdateState(updatedState, blockID, &block.Header, abciResponses, validatorUpdates) 799 require.NoError(t, err) 800 if i > numVals { // expect proposers to cycle through after the first iteration (of numVals blocks): 801 if proposers[i%numVals] == nil { 802 proposers[i%numVals] = updatedState.NextValidators.Proposer 803 } else { 804 assert.Equal(t, proposers[i%numVals], updatedState.NextValidators.Proposer) 805 } 806 } 807 } 808 } 809 810 func TestStoreLoadValidatorsIncrementsProposerPriority(t *testing.T) { 811 const valSetSize = 2 812 tearDown, stateDB, state := setupTestCase(t) 813 defer tearDown(t) 814 state.Validators = genValSet(valSetSize) 815 state.NextValidators = state.Validators.CopyIncrementProposerPriority(1) 816 sm.SaveState(stateDB, state) 817 818 nextHeight := state.LastBlockHeight + 1 819 820 v0, err := sm.LoadValidators(stateDB, nextHeight) 821 assert.Nil(t, err) 822 acc0 := v0.Validators[0].ProposerPriority 823 824 v1, err := sm.LoadValidators(stateDB, nextHeight+1) 825 assert.Nil(t, err) 826 acc1 := v1.Validators[0].ProposerPriority 827 828 assert.NotEqual(t, acc1, acc0, "expected ProposerPriority value to change between heights") 829 } 830 831 // TestValidatorChangesSaveLoad tests saving and loading a validator set with 832 // changes. 833 func TestManyValidatorChangesSaveLoad(t *testing.T) { 834 const valSetSize = 7 835 tearDown, stateDB, state := setupTestCase(t) 836 defer tearDown(t) 837 require.Equal(t, int64(0), state.LastBlockHeight) 838 state.Validators = genValSet(valSetSize) 839 state.NextValidators = state.Validators.CopyIncrementProposerPriority(1) 840 sm.SaveState(stateDB, state) 841 842 _, valOld := state.Validators.GetByIndex(0) 843 var pubkeyOld = valOld.PubKey 844 pubkey := ed25519.GenPrivKey().PubKey() 845 846 // Swap the first validator with a new one (validator set size stays the same). 847 header, blockID, responses := makeHeaderPartsResponsesValPubKeyChange(state, pubkey) 848 849 // Save state etc. 850 var err error 851 var validatorUpdates []*types.Validator 852 validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates) 853 require.NoError(t, err) 854 state, err = sm.UpdateState(state, blockID, &header, responses, validatorUpdates) 855 require.Nil(t, err) 856 nextHeight := state.LastBlockHeight + 1 857 sm.SaveValidatorsInfo(stateDB, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators) 858 859 // Load nextheight, it should be the oldpubkey. 860 v0, err := sm.LoadValidators(stateDB, nextHeight) 861 assert.Nil(t, err) 862 assert.Equal(t, valSetSize, v0.Size()) 863 index, val := v0.GetByAddress(pubkeyOld.Address()) 864 assert.NotNil(t, val) 865 if index < 0 { 866 t.Fatal("expected to find old validator") 867 } 868 869 // Load nextheight+1, it should be the new pubkey. 870 v1, err := sm.LoadValidators(stateDB, nextHeight+1) 871 assert.Nil(t, err) 872 assert.Equal(t, valSetSize, v1.Size()) 873 index, val = v1.GetByAddress(pubkey.Address()) 874 assert.NotNil(t, val) 875 if index < 0 { 876 t.Fatal("expected to find newly added validator") 877 } 878 } 879 880 func TestStateMakeBlock(t *testing.T) { 881 tearDown, _, state := setupTestCase(t) 882 defer tearDown(t) 883 884 proposerAddress := state.Validators.GetProposer().Address 885 stateVersion := state.Version.Consensus 886 block := makeBlock(state, 2) 887 888 // test we set some fields 889 assert.Equal(t, stateVersion, block.Version) 890 assert.Equal(t, proposerAddress, block.ProposerAddress) 891 } 892 893 // TestConsensusParamsChangesSaveLoad tests saving and loading consensus params 894 // with changes. 895 func TestConsensusParamsChangesSaveLoad(t *testing.T) { 896 tearDown, stateDB, state := setupTestCase(t) 897 defer tearDown(t) 898 899 // Change vals at these heights. 900 changeHeights := []int64{1, 2, 4, 5, 10, 15, 16, 17, 20} 901 N := len(changeHeights) 902 903 // Each valset is just one validator. 904 // create list of them. 905 params := make([]types.ConsensusParams, N+1) 906 params[0] = state.ConsensusParams 907 for i := 1; i < N+1; i++ { 908 params[i] = *types.DefaultConsensusParams() 909 params[i].Block.MaxBytes += int64(i) 910 } 911 912 // Build the params history by running updateState 913 // with the right params set for each height. 914 highestHeight := changeHeights[N-1] + 5 915 changeIndex := 0 916 cp := params[changeIndex] 917 var err error 918 var validatorUpdates []*types.Validator 919 for i := int64(1); i < highestHeight; i++ { 920 // When we get to a change height, use the next params. 921 if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] { 922 changeIndex++ 923 cp = params[changeIndex] 924 } 925 header, blockID, responses := makeHeaderPartsResponsesParams(state, cp) 926 validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates) 927 require.NoError(t, err) 928 state, err = sm.UpdateState(state, blockID, &header, responses, validatorUpdates) 929 930 require.Nil(t, err) 931 nextHeight := state.LastBlockHeight + 1 932 sm.SaveConsensusParamsInfo(stateDB, nextHeight, state.LastHeightConsensusParamsChanged, state.ConsensusParams) 933 } 934 935 // Make all the test cases by using the same params until after the change. 936 testCases := make([]paramsChangeTestCase, highestHeight) 937 changeIndex = 0 938 cp = params[changeIndex] 939 for i := int64(1); i < highestHeight+1; i++ { 940 // We get to the height after a change height use the next pubkey (note 941 // our counter starts at 0 this time). 942 if changeIndex < len(changeHeights) && i == changeHeights[changeIndex]+1 { 943 changeIndex++ 944 cp = params[changeIndex] 945 } 946 testCases[i-1] = paramsChangeTestCase{i, cp} 947 } 948 949 for _, testCase := range testCases { 950 p, err := sm.LoadConsensusParams(stateDB, testCase.height) 951 assert.Nil(t, err, fmt.Sprintf("expected no err at height %d", testCase.height)) 952 assert.Equal(t, testCase.params, p, fmt.Sprintf(`unexpected consensus params at 953 height %d`, testCase.height)) 954 } 955 } 956 957 func TestApplyUpdates(t *testing.T) { 958 initParams := makeConsensusParams(1, 2, 3, 4) 959 960 cases := [...]struct { 961 init types.ConsensusParams 962 updates abci.ConsensusParams 963 expected types.ConsensusParams 964 }{ 965 0: {initParams, abci.ConsensusParams{}, initParams}, 966 1: {initParams, abci.ConsensusParams{}, initParams}, 967 2: {initParams, 968 abci.ConsensusParams{ 969 Block: &abci.BlockParams{ 970 MaxBytes: 44, 971 MaxGas: 55, 972 }, 973 }, 974 makeConsensusParams(44, 55, 3, 4)}, 975 3: {initParams, 976 abci.ConsensusParams{ 977 Evidence: &abci.EvidenceParams{ 978 MaxAge: 66, 979 }, 980 }, 981 makeConsensusParams(1, 2, 3, 66)}, 982 } 983 984 for i, tc := range cases { 985 res := tc.init.Update(&(tc.updates)) 986 assert.Equal(t, tc.expected, res, "case %d", i) 987 } 988 }