github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/state/state_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package state 5 6 import ( 7 "context" 8 "fmt" 9 "math" 10 "sync" 11 "testing" 12 "time" 13 14 "github.com/prometheus/client_golang/prometheus" 15 "github.com/stretchr/testify/require" 16 "go.uber.org/mock/gomock" 17 18 "github.com/MetalBlockchain/metalgo/database" 19 "github.com/MetalBlockchain/metalgo/database/memdb" 20 "github.com/MetalBlockchain/metalgo/ids" 21 "github.com/MetalBlockchain/metalgo/snow" 22 "github.com/MetalBlockchain/metalgo/snow/choices" 23 "github.com/MetalBlockchain/metalgo/snow/validators" 24 "github.com/MetalBlockchain/metalgo/utils/constants" 25 "github.com/MetalBlockchain/metalgo/utils/crypto/bls" 26 "github.com/MetalBlockchain/metalgo/utils/logging" 27 "github.com/MetalBlockchain/metalgo/utils/units" 28 "github.com/MetalBlockchain/metalgo/utils/wrappers" 29 "github.com/MetalBlockchain/metalgo/vms/components/avax" 30 "github.com/MetalBlockchain/metalgo/vms/platformvm/block" 31 "github.com/MetalBlockchain/metalgo/vms/platformvm/config" 32 "github.com/MetalBlockchain/metalgo/vms/platformvm/fx" 33 "github.com/MetalBlockchain/metalgo/vms/platformvm/genesis" 34 "github.com/MetalBlockchain/metalgo/vms/platformvm/metrics" 35 "github.com/MetalBlockchain/metalgo/vms/platformvm/reward" 36 "github.com/MetalBlockchain/metalgo/vms/platformvm/signer" 37 "github.com/MetalBlockchain/metalgo/vms/platformvm/status" 38 "github.com/MetalBlockchain/metalgo/vms/platformvm/txs" 39 "github.com/MetalBlockchain/metalgo/vms/secp256k1fx" 40 "github.com/MetalBlockchain/metalgo/vms/types" 41 42 safemath "github.com/MetalBlockchain/metalgo/utils/math" 43 ) 44 45 var ( 46 initialTxID = ids.GenerateTestID() 47 initialNodeID = ids.GenerateTestNodeID() 48 initialTime = time.Now().Round(time.Second) 49 initialValidatorEndTime = initialTime.Add(28 * 24 * time.Hour) 50 ) 51 52 func TestStateInitialization(t *testing.T) { 53 require := require.New(t) 54 s, db := newUninitializedState(require) 55 56 shouldInit, err := s.shouldInit() 57 require.NoError(err) 58 require.True(shouldInit) 59 60 require.NoError(s.doneInit()) 61 require.NoError(s.Commit()) 62 63 s = newStateFromDB(require, db) 64 65 shouldInit, err = s.shouldInit() 66 require.NoError(err) 67 require.False(shouldInit) 68 } 69 70 func TestStateSyncGenesis(t *testing.T) { 71 require := require.New(t) 72 state := newInitializedState(require) 73 74 staker, err := state.GetCurrentValidator(constants.PrimaryNetworkID, initialNodeID) 75 require.NoError(err) 76 require.NotNil(staker) 77 require.Equal(initialNodeID, staker.NodeID) 78 79 delegatorIterator, err := state.GetCurrentDelegatorIterator(constants.PrimaryNetworkID, initialNodeID) 80 require.NoError(err) 81 assertIteratorsEqual(t, EmptyIterator, delegatorIterator) 82 83 stakerIterator, err := state.GetCurrentStakerIterator() 84 require.NoError(err) 85 assertIteratorsEqual(t, NewSliceIterator(staker), stakerIterator) 86 87 _, err = state.GetPendingValidator(constants.PrimaryNetworkID, initialNodeID) 88 require.ErrorIs(err, database.ErrNotFound) 89 90 delegatorIterator, err = state.GetPendingDelegatorIterator(constants.PrimaryNetworkID, initialNodeID) 91 require.NoError(err) 92 assertIteratorsEqual(t, EmptyIterator, delegatorIterator) 93 } 94 95 // Whenever we store a staker, a whole bunch a data structures are updated 96 // This test is meant to capture which updates are carried out 97 func TestPersistStakers(t *testing.T) { 98 tests := map[string]struct { 99 // Insert or delete a staker to state and store it 100 storeStaker func(*require.Assertions, ids.ID /*=subnetID*/, *state) *Staker 101 102 // Check that the staker is duly stored/removed in P-chain state 103 checkStakerInState func(*require.Assertions, *state, *Staker) 104 105 // Check whether validators are duly reported in the validator set, 106 // with the right weight and showing the BLS key 107 checkValidatorsSet func(*require.Assertions, *state, *Staker) 108 109 // Check that node duly track stakers uptimes 110 checkValidatorUptimes func(*require.Assertions, *state, *Staker) 111 112 // Check whether weight/bls keys diffs are duly stored 113 checkDiffs func(*require.Assertions, *state, *Staker, uint64) 114 }{ 115 "add current validator": { 116 storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker { 117 var ( 118 startTime = time.Now().Unix() 119 endTime = time.Now().Add(14 * 24 * time.Hour).Unix() 120 121 validatorsData = txs.Validator{ 122 NodeID: ids.GenerateTestNodeID(), 123 End: uint64(endTime), 124 Wght: 1234, 125 } 126 validatorReward uint64 = 5678 127 ) 128 129 utx := createPermissionlessValidatorTx(r, subnetID, validatorsData) 130 addPermValTx := &txs.Tx{Unsigned: utx} 131 r.NoError(addPermValTx.Initialize(txs.Codec)) 132 133 staker, err := NewCurrentStaker( 134 addPermValTx.ID(), 135 utx, 136 time.Unix(startTime, 0), 137 validatorReward, 138 ) 139 r.NoError(err) 140 141 s.PutCurrentValidator(staker) 142 s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker 143 r.NoError(s.Commit()) 144 return staker 145 }, 146 checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) { 147 retrievedStaker, err := s.GetCurrentValidator(staker.SubnetID, staker.NodeID) 148 r.NoError(err) 149 r.Equal(staker, retrievedStaker) 150 }, 151 checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) { 152 valsMap := s.cfg.Validators.GetMap(staker.SubnetID) 153 r.Len(valsMap, 1) 154 valOut, found := valsMap[staker.NodeID] 155 r.True(found) 156 r.Equal(&validators.GetValidatorOutput{ 157 NodeID: staker.NodeID, 158 PublicKey: staker.PublicKey, 159 Weight: staker.Weight, 160 }, valOut) 161 }, 162 checkValidatorUptimes: func(r *require.Assertions, s *state, staker *Staker) { 163 upDuration, lastUpdated, err := s.GetUptime(staker.NodeID, staker.SubnetID) 164 r.NoError(err) 165 r.Equal(upDuration, time.Duration(0)) 166 r.Equal(lastUpdated, staker.StartTime) 167 }, 168 checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) { 169 weightDiffBytes, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) 170 r.NoError(err) 171 weightDiff, err := unmarshalWeightDiff(weightDiffBytes) 172 r.NoError(err) 173 r.Equal(&ValidatorWeightDiff{ 174 Decrease: false, 175 Amount: staker.Weight, 176 }, weightDiff) 177 178 blsDiffBytes, err := s.validatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) 179 if staker.SubnetID == constants.PrimaryNetworkID { 180 r.NoError(err) 181 r.Nil(blsDiffBytes) 182 } else { 183 r.ErrorIs(err, database.ErrNotFound) 184 } 185 }, 186 }, 187 "add current delegator": { 188 storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker { 189 // insert the delegator and its validator 190 var ( 191 valStartTime = time.Now().Truncate(time.Second).Unix() 192 delStartTime = time.Unix(valStartTime, 0).Add(time.Hour).Unix() 193 delEndTime = time.Unix(delStartTime, 0).Add(30 * 24 * time.Hour).Unix() 194 valEndTime = time.Unix(valStartTime, 0).Add(365 * 24 * time.Hour).Unix() 195 196 validatorsData = txs.Validator{ 197 NodeID: ids.GenerateTestNodeID(), 198 End: uint64(valEndTime), 199 Wght: 1234, 200 } 201 validatorReward uint64 = 5678 202 203 delegatorData = txs.Validator{ 204 NodeID: validatorsData.NodeID, 205 End: uint64(delEndTime), 206 Wght: validatorsData.Wght / 2, 207 } 208 delegatorReward uint64 = 5432 209 ) 210 211 utxVal := createPermissionlessValidatorTx(r, subnetID, validatorsData) 212 addPermValTx := &txs.Tx{Unsigned: utxVal} 213 r.NoError(addPermValTx.Initialize(txs.Codec)) 214 215 val, err := NewCurrentStaker( 216 addPermValTx.ID(), 217 utxVal, 218 time.Unix(valStartTime, 0), 219 validatorReward, 220 ) 221 r.NoError(err) 222 223 utxDel := createPermissionlessDelegatorTx(subnetID, delegatorData) 224 addPermDelTx := &txs.Tx{Unsigned: utxDel} 225 r.NoError(addPermDelTx.Initialize(txs.Codec)) 226 227 del, err := NewCurrentStaker( 228 addPermDelTx.ID(), 229 utxDel, 230 time.Unix(delStartTime, 0), 231 delegatorReward, 232 ) 233 r.NoError(err) 234 235 s.PutCurrentValidator(val) 236 s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker 237 r.NoError(s.Commit()) 238 239 s.PutCurrentDelegator(del) 240 s.AddTx(addPermDelTx, status.Committed) // this is currently needed to reload the staker 241 r.NoError(s.Commit()) 242 return del 243 }, 244 checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) { 245 delIt, err := s.GetCurrentDelegatorIterator(staker.SubnetID, staker.NodeID) 246 r.NoError(err) 247 r.True(delIt.Next()) 248 retrievedDelegator := delIt.Value() 249 r.False(delIt.Next()) 250 delIt.Release() 251 r.Equal(staker, retrievedDelegator) 252 }, 253 checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) { 254 val, err := s.GetCurrentValidator(staker.SubnetID, staker.NodeID) 255 r.NoError(err) 256 257 valsMap := s.cfg.Validators.GetMap(staker.SubnetID) 258 r.Len(valsMap, 1) 259 valOut, found := valsMap[staker.NodeID] 260 r.True(found) 261 r.Equal(valOut.NodeID, staker.NodeID) 262 r.Equal(valOut.Weight, val.Weight+staker.Weight) 263 }, 264 checkValidatorUptimes: func(*require.Assertions, *state, *Staker) {}, 265 checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) { 266 // validator's weight must increase of delegator's weight amount 267 weightDiffBytes, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) 268 r.NoError(err) 269 weightDiff, err := unmarshalWeightDiff(weightDiffBytes) 270 r.NoError(err) 271 r.Equal(&ValidatorWeightDiff{ 272 Decrease: false, 273 Amount: staker.Weight, 274 }, weightDiff) 275 }, 276 }, 277 "add pending validator": { 278 storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker { 279 var ( 280 startTime = time.Now().Unix() 281 endTime = time.Now().Add(14 * 24 * time.Hour).Unix() 282 283 validatorsData = txs.Validator{ 284 NodeID: ids.GenerateTestNodeID(), 285 Start: uint64(startTime), 286 End: uint64(endTime), 287 Wght: 1234, 288 } 289 ) 290 291 utx := createPermissionlessValidatorTx(r, subnetID, validatorsData) 292 addPermValTx := &txs.Tx{Unsigned: utx} 293 r.NoError(addPermValTx.Initialize(txs.Codec)) 294 295 staker, err := NewPendingStaker( 296 addPermValTx.ID(), 297 utx, 298 ) 299 r.NoError(err) 300 301 s.PutPendingValidator(staker) 302 s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker 303 r.NoError(s.Commit()) 304 return staker 305 }, 306 checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) { 307 retrievedStaker, err := s.GetPendingValidator(staker.SubnetID, staker.NodeID) 308 r.NoError(err) 309 r.Equal(staker, retrievedStaker) 310 }, 311 checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) { 312 // pending validators are not showed in validators set 313 valsMap := s.cfg.Validators.GetMap(staker.SubnetID) 314 r.Empty(valsMap) 315 }, 316 checkValidatorUptimes: func(r *require.Assertions, s *state, staker *Staker) { 317 // pending validators uptime is not tracked 318 _, _, err := s.GetUptime(staker.NodeID, staker.SubnetID) 319 r.ErrorIs(err, database.ErrNotFound) 320 }, 321 checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) { 322 // pending validators weight diff and bls diffs are not stored 323 _, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) 324 r.ErrorIs(err, database.ErrNotFound) 325 326 _, err = s.validatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) 327 r.ErrorIs(err, database.ErrNotFound) 328 }, 329 }, 330 "add pending delegator": { 331 storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker { 332 // insert the delegator and its validator 333 var ( 334 valStartTime = time.Now().Truncate(time.Second).Unix() 335 delStartTime = time.Unix(valStartTime, 0).Add(time.Hour).Unix() 336 delEndTime = time.Unix(delStartTime, 0).Add(30 * 24 * time.Hour).Unix() 337 valEndTime = time.Unix(valStartTime, 0).Add(365 * 24 * time.Hour).Unix() 338 339 validatorsData = txs.Validator{ 340 NodeID: ids.GenerateTestNodeID(), 341 Start: uint64(valStartTime), 342 End: uint64(valEndTime), 343 Wght: 1234, 344 } 345 346 delegatorData = txs.Validator{ 347 NodeID: validatorsData.NodeID, 348 Start: uint64(delStartTime), 349 End: uint64(delEndTime), 350 Wght: validatorsData.Wght / 2, 351 } 352 ) 353 354 utxVal := createPermissionlessValidatorTx(r, subnetID, validatorsData) 355 addPermValTx := &txs.Tx{Unsigned: utxVal} 356 r.NoError(addPermValTx.Initialize(txs.Codec)) 357 358 val, err := NewPendingStaker(addPermValTx.ID(), utxVal) 359 r.NoError(err) 360 361 utxDel := createPermissionlessDelegatorTx(subnetID, delegatorData) 362 addPermDelTx := &txs.Tx{Unsigned: utxDel} 363 r.NoError(addPermDelTx.Initialize(txs.Codec)) 364 365 del, err := NewPendingStaker(addPermDelTx.ID(), utxDel) 366 r.NoError(err) 367 368 s.PutPendingValidator(val) 369 s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker 370 r.NoError(s.Commit()) 371 372 s.PutPendingDelegator(del) 373 s.AddTx(addPermDelTx, status.Committed) // this is currently needed to reload the staker 374 r.NoError(s.Commit()) 375 376 return del 377 }, 378 checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) { 379 delIt, err := s.GetPendingDelegatorIterator(staker.SubnetID, staker.NodeID) 380 r.NoError(err) 381 r.True(delIt.Next()) 382 retrievedDelegator := delIt.Value() 383 r.False(delIt.Next()) 384 delIt.Release() 385 r.Equal(staker, retrievedDelegator) 386 }, 387 checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) { 388 valsMap := s.cfg.Validators.GetMap(staker.SubnetID) 389 r.Empty(valsMap) 390 }, 391 checkValidatorUptimes: func(*require.Assertions, *state, *Staker) {}, 392 checkDiffs: func(*require.Assertions, *state, *Staker, uint64) {}, 393 }, 394 "delete current validator": { 395 storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker { 396 // add them remove the validator 397 var ( 398 startTime = time.Now().Unix() 399 endTime = time.Now().Add(14 * 24 * time.Hour).Unix() 400 401 validatorsData = txs.Validator{ 402 NodeID: ids.GenerateTestNodeID(), 403 End: uint64(endTime), 404 Wght: 1234, 405 } 406 validatorReward uint64 = 5678 407 ) 408 409 utx := createPermissionlessValidatorTx(r, subnetID, validatorsData) 410 addPermValTx := &txs.Tx{Unsigned: utx} 411 r.NoError(addPermValTx.Initialize(txs.Codec)) 412 413 staker, err := NewCurrentStaker( 414 addPermValTx.ID(), 415 utx, 416 time.Unix(startTime, 0), 417 validatorReward, 418 ) 419 r.NoError(err) 420 421 s.PutCurrentValidator(staker) 422 s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker 423 r.NoError(s.Commit()) 424 425 s.DeleteCurrentValidator(staker) 426 r.NoError(s.Commit()) 427 return staker 428 }, 429 checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) { 430 _, err := s.GetCurrentValidator(staker.SubnetID, staker.NodeID) 431 r.ErrorIs(err, database.ErrNotFound) 432 }, 433 checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) { 434 // deleted validators are not showed in the validators set anymore 435 valsMap := s.cfg.Validators.GetMap(staker.SubnetID) 436 r.Empty(valsMap) 437 }, 438 checkValidatorUptimes: func(r *require.Assertions, s *state, staker *Staker) { 439 // uptimes of delete validators are dropped 440 _, _, err := s.GetUptime(staker.NodeID, staker.SubnetID) 441 r.ErrorIs(err, database.ErrNotFound) 442 }, 443 checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) { 444 weightDiffBytes, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) 445 r.NoError(err) 446 weightDiff, err := unmarshalWeightDiff(weightDiffBytes) 447 r.NoError(err) 448 r.Equal(&ValidatorWeightDiff{ 449 Decrease: true, 450 Amount: staker.Weight, 451 }, weightDiff) 452 453 blsDiffBytes, err := s.validatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) 454 if staker.SubnetID == constants.PrimaryNetworkID { 455 r.NoError(err) 456 r.Equal(bls.PublicKeyFromValidUncompressedBytes(blsDiffBytes), staker.PublicKey) 457 } else { 458 r.ErrorIs(err, database.ErrNotFound) 459 } 460 }, 461 }, 462 "delete current delegator": { 463 storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker { 464 // insert validator and delegator, then remove the delegator 465 var ( 466 valStartTime = time.Now().Truncate(time.Second).Unix() 467 delStartTime = time.Unix(valStartTime, 0).Add(time.Hour).Unix() 468 delEndTime = time.Unix(delStartTime, 0).Add(30 * 24 * time.Hour).Unix() 469 valEndTime = time.Unix(valStartTime, 0).Add(365 * 24 * time.Hour).Unix() 470 471 validatorsData = txs.Validator{ 472 NodeID: ids.GenerateTestNodeID(), 473 End: uint64(valEndTime), 474 Wght: 1234, 475 } 476 validatorReward uint64 = 5678 477 478 delegatorData = txs.Validator{ 479 NodeID: validatorsData.NodeID, 480 End: uint64(delEndTime), 481 Wght: validatorsData.Wght / 2, 482 } 483 delegatorReward uint64 = 5432 484 ) 485 486 utxVal := createPermissionlessValidatorTx(r, subnetID, validatorsData) 487 addPermValTx := &txs.Tx{Unsigned: utxVal} 488 r.NoError(addPermValTx.Initialize(txs.Codec)) 489 490 val, err := NewCurrentStaker( 491 addPermValTx.ID(), 492 utxVal, 493 time.Unix(valStartTime, 0), 494 validatorReward, 495 ) 496 r.NoError(err) 497 498 utxDel := createPermissionlessDelegatorTx(subnetID, delegatorData) 499 addPermDelTx := &txs.Tx{Unsigned: utxDel} 500 r.NoError(addPermDelTx.Initialize(txs.Codec)) 501 502 del, err := NewCurrentStaker( 503 addPermDelTx.ID(), 504 utxDel, 505 time.Unix(delStartTime, 0), 506 delegatorReward, 507 ) 508 r.NoError(err) 509 510 s.PutCurrentValidator(val) 511 s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker 512 513 s.PutCurrentDelegator(del) 514 s.AddTx(addPermDelTx, status.Committed) // this is currently needed to reload the staker 515 r.NoError(s.Commit()) 516 517 s.DeleteCurrentDelegator(del) 518 r.NoError(s.Commit()) 519 520 return del 521 }, 522 checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) { 523 delIt, err := s.GetCurrentDelegatorIterator(staker.SubnetID, staker.NodeID) 524 r.NoError(err) 525 r.False(delIt.Next()) 526 delIt.Release() 527 }, 528 checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) { 529 val, err := s.GetCurrentValidator(staker.SubnetID, staker.NodeID) 530 r.NoError(err) 531 532 valsMap := s.cfg.Validators.GetMap(staker.SubnetID) 533 r.Len(valsMap, 1) 534 valOut, found := valsMap[staker.NodeID] 535 r.True(found) 536 r.Equal(valOut.NodeID, staker.NodeID) 537 r.Equal(valOut.Weight, val.Weight) 538 }, 539 checkValidatorUptimes: func(*require.Assertions, *state, *Staker) {}, 540 checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) { 541 // validator's weight must decrease of delegator's weight amount 542 weightDiffBytes, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) 543 r.NoError(err) 544 weightDiff, err := unmarshalWeightDiff(weightDiffBytes) 545 r.NoError(err) 546 r.Equal(&ValidatorWeightDiff{ 547 Decrease: true, 548 Amount: staker.Weight, 549 }, weightDiff) 550 }, 551 }, 552 "delete pending validator": { 553 storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker { 554 var ( 555 startTime = time.Now().Unix() 556 endTime = time.Now().Add(14 * 24 * time.Hour).Unix() 557 558 validatorsData = txs.Validator{ 559 NodeID: ids.GenerateTestNodeID(), 560 Start: uint64(startTime), 561 End: uint64(endTime), 562 Wght: 1234, 563 } 564 ) 565 566 utx := createPermissionlessValidatorTx(r, subnetID, validatorsData) 567 addPermValTx := &txs.Tx{Unsigned: utx} 568 r.NoError(addPermValTx.Initialize(txs.Codec)) 569 570 staker, err := NewPendingStaker( 571 addPermValTx.ID(), 572 utx, 573 ) 574 r.NoError(err) 575 576 s.PutPendingValidator(staker) 577 s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker 578 r.NoError(s.Commit()) 579 580 s.DeletePendingValidator(staker) 581 r.NoError(s.Commit()) 582 583 return staker 584 }, 585 checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) { 586 _, err := s.GetPendingValidator(staker.SubnetID, staker.NodeID) 587 r.ErrorIs(err, database.ErrNotFound) 588 }, 589 checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) { 590 valsMap := s.cfg.Validators.GetMap(staker.SubnetID) 591 r.Empty(valsMap) 592 }, 593 checkValidatorUptimes: func(r *require.Assertions, s *state, staker *Staker) { 594 _, _, err := s.GetUptime(staker.NodeID, staker.SubnetID) 595 r.ErrorIs(err, database.ErrNotFound) 596 }, 597 checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) { 598 _, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) 599 r.ErrorIs(err, database.ErrNotFound) 600 601 _, err = s.validatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) 602 r.ErrorIs(err, database.ErrNotFound) 603 }, 604 }, 605 "delete pending delegator": { 606 storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker { 607 // insert validator and delegator the remove the validator 608 var ( 609 valStartTime = time.Now().Truncate(time.Second).Unix() 610 delStartTime = time.Unix(valStartTime, 0).Add(time.Hour).Unix() 611 delEndTime = time.Unix(delStartTime, 0).Add(30 * 24 * time.Hour).Unix() 612 valEndTime = time.Unix(valStartTime, 0).Add(365 * 24 * time.Hour).Unix() 613 614 validatorsData = txs.Validator{ 615 NodeID: ids.GenerateTestNodeID(), 616 Start: uint64(valStartTime), 617 End: uint64(valEndTime), 618 Wght: 1234, 619 } 620 621 delegatorData = txs.Validator{ 622 NodeID: validatorsData.NodeID, 623 Start: uint64(delStartTime), 624 End: uint64(delEndTime), 625 Wght: validatorsData.Wght / 2, 626 } 627 ) 628 629 utxVal := createPermissionlessValidatorTx(r, subnetID, validatorsData) 630 addPermValTx := &txs.Tx{Unsigned: utxVal} 631 r.NoError(addPermValTx.Initialize(txs.Codec)) 632 633 val, err := NewPendingStaker(addPermValTx.ID(), utxVal) 634 r.NoError(err) 635 636 utxDel := createPermissionlessDelegatorTx(subnetID, delegatorData) 637 addPermDelTx := &txs.Tx{Unsigned: utxDel} 638 r.NoError(addPermDelTx.Initialize(txs.Codec)) 639 640 del, err := NewPendingStaker(addPermDelTx.ID(), utxDel) 641 r.NoError(err) 642 643 s.PutPendingValidator(val) 644 s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker 645 646 s.PutPendingDelegator(del) 647 s.AddTx(addPermDelTx, status.Committed) // this is currently needed to reload the staker 648 r.NoError(s.Commit()) 649 650 s.DeletePendingDelegator(del) 651 r.NoError(s.Commit()) 652 return del 653 }, 654 checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) { 655 delIt, err := s.GetPendingDelegatorIterator(staker.SubnetID, staker.NodeID) 656 r.NoError(err) 657 r.False(delIt.Next()) 658 delIt.Release() 659 }, 660 checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) { 661 valsMap := s.cfg.Validators.GetMap(staker.SubnetID) 662 r.Empty(valsMap) 663 }, 664 checkValidatorUptimes: func(*require.Assertions, *state, *Staker) {}, 665 checkDiffs: func(*require.Assertions, *state, *Staker, uint64) {}, 666 }, 667 } 668 669 subnetIDs := []ids.ID{constants.PrimaryNetworkID, ids.GenerateTestID()} 670 for _, subnetID := range subnetIDs { 671 for name, test := range tests { 672 t.Run(fmt.Sprintf("%s - subnetID %s", name, subnetID), func(t *testing.T) { 673 require := require.New(t) 674 675 state, db := newUninitializedState(require) 676 677 // create and store the staker 678 staker := test.storeStaker(require, subnetID, state) 679 680 // check all relevant data are stored 681 test.checkStakerInState(require, state, staker) 682 test.checkValidatorsSet(require, state, staker) 683 test.checkValidatorUptimes(require, state, staker) 684 test.checkDiffs(require, state, staker, 0 /*height*/) 685 686 // rebuild the state 687 rebuiltState := newStateFromDB(require, db) 688 689 // load relevant quantities 690 require.NoError(rebuiltState.loadCurrentValidators()) 691 require.NoError(rebuiltState.loadPendingValidators()) 692 require.NoError(rebuiltState.initValidatorSets()) 693 694 // check again that all relevant data are still available in rebuilt state 695 test.checkStakerInState(require, state, staker) 696 test.checkValidatorsSet(require, state, staker) 697 test.checkValidatorUptimes(require, state, staker) 698 test.checkDiffs(require, state, staker, 0 /*height*/) 699 }) 700 } 701 } 702 } 703 704 func newInitializedState(require *require.Assertions) State { 705 s, _ := newUninitializedState(require) 706 707 initialValidator := &txs.AddValidatorTx{ 708 Validator: txs.Validator{ 709 NodeID: initialNodeID, 710 Start: uint64(initialTime.Unix()), 711 End: uint64(initialValidatorEndTime.Unix()), 712 Wght: units.Avax, 713 }, 714 StakeOuts: []*avax.TransferableOutput{ 715 { 716 Asset: avax.Asset{ID: initialTxID}, 717 Out: &secp256k1fx.TransferOutput{ 718 Amt: units.Avax, 719 }, 720 }, 721 }, 722 RewardsOwner: &secp256k1fx.OutputOwners{}, 723 DelegationShares: reward.PercentDenominator, 724 } 725 initialValidatorTx := &txs.Tx{Unsigned: initialValidator} 726 require.NoError(initialValidatorTx.Initialize(txs.Codec)) 727 728 initialChain := &txs.CreateChainTx{ 729 SubnetID: constants.PrimaryNetworkID, 730 ChainName: "x", 731 VMID: constants.AVMID, 732 SubnetAuth: &secp256k1fx.Input{}, 733 } 734 initialChainTx := &txs.Tx{Unsigned: initialChain} 735 require.NoError(initialChainTx.Initialize(txs.Codec)) 736 737 genesisBlkID := ids.GenerateTestID() 738 genesisState := &genesis.Genesis{ 739 UTXOs: []*genesis.UTXO{ 740 { 741 UTXO: avax.UTXO{ 742 UTXOID: avax.UTXOID{ 743 TxID: initialTxID, 744 OutputIndex: 0, 745 }, 746 Asset: avax.Asset{ID: initialTxID}, 747 Out: &secp256k1fx.TransferOutput{ 748 Amt: units.Schmeckle, 749 }, 750 }, 751 Message: nil, 752 }, 753 }, 754 Validators: []*txs.Tx{ 755 initialValidatorTx, 756 }, 757 Chains: []*txs.Tx{ 758 initialChainTx, 759 }, 760 Timestamp: uint64(initialTime.Unix()), 761 InitialSupply: units.Schmeckle + units.Avax, 762 } 763 764 genesisBlk, err := block.NewApricotCommitBlock(genesisBlkID, 0) 765 require.NoError(err) 766 require.NoError(s.syncGenesis(genesisBlk, genesisState)) 767 768 return s 769 } 770 771 func newUninitializedState(require *require.Assertions) (*state, database.Database) { 772 db := memdb.New() 773 return newStateFromDB(require, db), db 774 } 775 776 func newStateFromDB(require *require.Assertions, db database.Database) *state { 777 execCfg, _ := config.GetExecutionConfig(nil) 778 state, err := newState( 779 db, 780 metrics.Noop, 781 &config.Config{ 782 Validators: validators.NewManager(), 783 }, 784 execCfg, 785 &snow.Context{}, 786 prometheus.NewRegistry(), 787 reward.NewCalculator(reward.Config{ 788 MaxConsumptionRate: .12 * reward.PercentDenominator, 789 MinConsumptionRate: .1 * reward.PercentDenominator, 790 MintingPeriod: 365 * 24 * time.Hour, 791 SupplyCap: 720 * units.MegaAvax, 792 }), 793 ) 794 require.NoError(err) 795 require.NotNil(state) 796 return state 797 } 798 799 func createPermissionlessValidatorTx(r *require.Assertions, subnetID ids.ID, validatorsData txs.Validator) *txs.AddPermissionlessValidatorTx { 800 var sig signer.Signer = &signer.Empty{} 801 if subnetID == constants.PrimaryNetworkID { 802 sk, err := bls.NewSecretKey() 803 r.NoError(err) 804 sig = signer.NewProofOfPossession(sk) 805 } 806 807 return &txs.AddPermissionlessValidatorTx{ 808 BaseTx: txs.BaseTx{ 809 BaseTx: avax.BaseTx{ 810 NetworkID: constants.MainnetID, 811 BlockchainID: constants.PlatformChainID, 812 Outs: []*avax.TransferableOutput{}, 813 Ins: []*avax.TransferableInput{ 814 { 815 UTXOID: avax.UTXOID{ 816 TxID: ids.GenerateTestID(), 817 OutputIndex: 1, 818 }, 819 Asset: avax.Asset{ 820 ID: ids.GenerateTestID(), 821 }, 822 In: &secp256k1fx.TransferInput{ 823 Amt: 2 * units.KiloAvax, 824 Input: secp256k1fx.Input{ 825 SigIndices: []uint32{1}, 826 }, 827 }, 828 }, 829 }, 830 Memo: types.JSONByteSlice{}, 831 }, 832 }, 833 Validator: validatorsData, 834 Subnet: subnetID, 835 Signer: sig, 836 837 StakeOuts: []*avax.TransferableOutput{ 838 { 839 Asset: avax.Asset{ 840 ID: ids.GenerateTestID(), 841 }, 842 Out: &secp256k1fx.TransferOutput{ 843 Amt: 2 * units.KiloAvax, 844 OutputOwners: secp256k1fx.OutputOwners{ 845 Locktime: 0, 846 Threshold: 1, 847 Addrs: []ids.ShortID{ 848 ids.GenerateTestShortID(), 849 }, 850 }, 851 }, 852 }, 853 }, 854 ValidatorRewardsOwner: &secp256k1fx.OutputOwners{ 855 Locktime: 0, 856 Threshold: 1, 857 Addrs: []ids.ShortID{ 858 ids.GenerateTestShortID(), 859 }, 860 }, 861 DelegatorRewardsOwner: &secp256k1fx.OutputOwners{ 862 Locktime: 0, 863 Threshold: 1, 864 Addrs: []ids.ShortID{ 865 ids.GenerateTestShortID(), 866 }, 867 }, 868 DelegationShares: reward.PercentDenominator, 869 } 870 } 871 872 func createPermissionlessDelegatorTx(subnetID ids.ID, delegatorData txs.Validator) *txs.AddPermissionlessDelegatorTx { 873 return &txs.AddPermissionlessDelegatorTx{ 874 BaseTx: txs.BaseTx{ 875 BaseTx: avax.BaseTx{ 876 NetworkID: constants.MainnetID, 877 BlockchainID: constants.PlatformChainID, 878 Outs: []*avax.TransferableOutput{}, 879 Ins: []*avax.TransferableInput{ 880 { 881 UTXOID: avax.UTXOID{ 882 TxID: ids.GenerateTestID(), 883 OutputIndex: 1, 884 }, 885 Asset: avax.Asset{ 886 ID: ids.GenerateTestID(), 887 }, 888 In: &secp256k1fx.TransferInput{ 889 Amt: 2 * units.KiloAvax, 890 Input: secp256k1fx.Input{ 891 SigIndices: []uint32{1}, 892 }, 893 }, 894 }, 895 }, 896 Memo: types.JSONByteSlice{}, 897 }, 898 }, 899 Validator: delegatorData, 900 Subnet: subnetID, 901 902 StakeOuts: []*avax.TransferableOutput{ 903 { 904 Asset: avax.Asset{ 905 ID: ids.GenerateTestID(), 906 }, 907 Out: &secp256k1fx.TransferOutput{ 908 Amt: 2 * units.KiloAvax, 909 OutputOwners: secp256k1fx.OutputOwners{ 910 Locktime: 0, 911 Threshold: 1, 912 Addrs: []ids.ShortID{ 913 ids.GenerateTestShortID(), 914 }, 915 }, 916 }, 917 }, 918 }, 919 DelegationRewardsOwner: &secp256k1fx.OutputOwners{ 920 Locktime: 0, 921 Threshold: 1, 922 Addrs: []ids.ShortID{ 923 ids.GenerateTestShortID(), 924 }, 925 }, 926 } 927 } 928 929 func TestValidatorWeightDiff(t *testing.T) { 930 type test struct { 931 name string 932 ops []func(*ValidatorWeightDiff) error 933 expected *ValidatorWeightDiff 934 expectedErr error 935 } 936 937 tests := []test{ 938 { 939 name: "no ops", 940 ops: []func(*ValidatorWeightDiff) error{}, 941 expected: &ValidatorWeightDiff{}, 942 expectedErr: nil, 943 }, 944 { 945 name: "simple decrease", 946 ops: []func(*ValidatorWeightDiff) error{ 947 func(d *ValidatorWeightDiff) error { 948 return d.Add(true, 1) 949 }, 950 func(d *ValidatorWeightDiff) error { 951 return d.Add(true, 1) 952 }, 953 }, 954 expected: &ValidatorWeightDiff{ 955 Decrease: true, 956 Amount: 2, 957 }, 958 expectedErr: nil, 959 }, 960 { 961 name: "decrease overflow", 962 ops: []func(*ValidatorWeightDiff) error{ 963 func(d *ValidatorWeightDiff) error { 964 return d.Add(true, math.MaxUint64) 965 }, 966 func(d *ValidatorWeightDiff) error { 967 return d.Add(true, 1) 968 }, 969 }, 970 expected: &ValidatorWeightDiff{}, 971 expectedErr: safemath.ErrOverflow, 972 }, 973 { 974 name: "simple increase", 975 ops: []func(*ValidatorWeightDiff) error{ 976 func(d *ValidatorWeightDiff) error { 977 return d.Add(false, 1) 978 }, 979 func(d *ValidatorWeightDiff) error { 980 return d.Add(false, 1) 981 }, 982 }, 983 expected: &ValidatorWeightDiff{ 984 Decrease: false, 985 Amount: 2, 986 }, 987 expectedErr: nil, 988 }, 989 { 990 name: "increase overflow", 991 ops: []func(*ValidatorWeightDiff) error{ 992 func(d *ValidatorWeightDiff) error { 993 return d.Add(false, math.MaxUint64) 994 }, 995 func(d *ValidatorWeightDiff) error { 996 return d.Add(false, 1) 997 }, 998 }, 999 expected: &ValidatorWeightDiff{}, 1000 expectedErr: safemath.ErrOverflow, 1001 }, 1002 { 1003 name: "varied use", 1004 ops: []func(*ValidatorWeightDiff) error{ 1005 // Add to 0 1006 func(d *ValidatorWeightDiff) error { 1007 return d.Add(false, 2) // Value 2 1008 }, 1009 // Subtract from positive number 1010 func(d *ValidatorWeightDiff) error { 1011 return d.Add(true, 1) // Value 1 1012 }, 1013 // Subtract from positive number 1014 // to make it negative 1015 func(d *ValidatorWeightDiff) error { 1016 return d.Add(true, 3) // Value -2 1017 }, 1018 // Subtract from a negative number 1019 func(d *ValidatorWeightDiff) error { 1020 return d.Add(true, 3) // Value -5 1021 }, 1022 // Add to a negative number 1023 func(d *ValidatorWeightDiff) error { 1024 return d.Add(false, 1) // Value -4 1025 }, 1026 // Add to a negative number 1027 // to make it positive 1028 func(d *ValidatorWeightDiff) error { 1029 return d.Add(false, 5) // Value 1 1030 }, 1031 // Add to a positive number 1032 func(d *ValidatorWeightDiff) error { 1033 return d.Add(false, 1) // Value 2 1034 }, 1035 // Get to zero 1036 func(d *ValidatorWeightDiff) error { 1037 return d.Add(true, 2) // Value 0 1038 }, 1039 // Subtract from zero 1040 func(d *ValidatorWeightDiff) error { 1041 return d.Add(true, 2) // Value -2 1042 }, 1043 }, 1044 expected: &ValidatorWeightDiff{ 1045 Decrease: true, 1046 Amount: 2, 1047 }, 1048 expectedErr: nil, 1049 }, 1050 } 1051 1052 for _, tt := range tests { 1053 t.Run(tt.name, func(t *testing.T) { 1054 require := require.New(t) 1055 diff := &ValidatorWeightDiff{} 1056 errs := wrappers.Errs{} 1057 for _, op := range tt.ops { 1058 errs.Add(op(diff)) 1059 } 1060 require.ErrorIs(errs.Err, tt.expectedErr) 1061 if tt.expectedErr != nil { 1062 return 1063 } 1064 require.Equal(tt.expected, diff) 1065 }) 1066 } 1067 } 1068 1069 // Tests PutCurrentValidator, DeleteCurrentValidator, GetCurrentValidator, 1070 // ApplyValidatorWeightDiffs, ApplyValidatorPublicKeyDiffs 1071 func TestStateAddRemoveValidator(t *testing.T) { 1072 require := require.New(t) 1073 1074 state := newInitializedState(require) 1075 1076 var ( 1077 numNodes = 3 1078 subnetID = ids.GenerateTestID() 1079 startTime = time.Now() 1080 endTime = startTime.Add(24 * time.Hour) 1081 stakers = make([]Staker, numNodes) 1082 ) 1083 for i := 0; i < numNodes; i++ { 1084 stakers[i] = Staker{ 1085 TxID: ids.GenerateTestID(), 1086 NodeID: ids.GenerateTestNodeID(), 1087 Weight: uint64(i + 1), 1088 StartTime: startTime.Add(time.Duration(i) * time.Second), 1089 EndTime: endTime.Add(time.Duration(i) * time.Second), 1090 PotentialReward: uint64(i + 1), 1091 } 1092 if i%2 == 0 { 1093 stakers[i].SubnetID = subnetID 1094 } else { 1095 sk, err := bls.NewSecretKey() 1096 require.NoError(err) 1097 stakers[i].PublicKey = bls.PublicFromSecretKey(sk) 1098 stakers[i].SubnetID = constants.PrimaryNetworkID 1099 } 1100 } 1101 1102 type diff struct { 1103 addedValidators []Staker 1104 addedDelegators []Staker 1105 removedDelegators []Staker 1106 removedValidators []Staker 1107 1108 expectedPrimaryValidatorSet map[ids.NodeID]*validators.GetValidatorOutput 1109 expectedSubnetValidatorSet map[ids.NodeID]*validators.GetValidatorOutput 1110 } 1111 diffs := []diff{ 1112 { 1113 // Do nothing 1114 expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{}, 1115 expectedSubnetValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{}, 1116 }, 1117 { 1118 // Add a subnet validator 1119 addedValidators: []Staker{stakers[0]}, 1120 expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{}, 1121 expectedSubnetValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{ 1122 stakers[0].NodeID: { 1123 NodeID: stakers[0].NodeID, 1124 Weight: stakers[0].Weight, 1125 }, 1126 }, 1127 }, 1128 { 1129 // Remove a subnet validator 1130 removedValidators: []Staker{stakers[0]}, 1131 expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{}, 1132 expectedSubnetValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{}, 1133 }, 1134 { // Add a primary network validator 1135 addedValidators: []Staker{stakers[1]}, 1136 expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{ 1137 stakers[1].NodeID: { 1138 NodeID: stakers[1].NodeID, 1139 PublicKey: stakers[1].PublicKey, 1140 Weight: stakers[1].Weight, 1141 }, 1142 }, 1143 expectedSubnetValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{}, 1144 }, 1145 { 1146 // Do nothing 1147 expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{ 1148 stakers[1].NodeID: { 1149 NodeID: stakers[1].NodeID, 1150 PublicKey: stakers[1].PublicKey, 1151 Weight: stakers[1].Weight, 1152 }, 1153 }, 1154 expectedSubnetValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{}, 1155 }, 1156 { // Remove a primary network validator 1157 removedValidators: []Staker{stakers[1]}, 1158 expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{}, 1159 expectedSubnetValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{}, 1160 }, 1161 { 1162 // Add 2 subnet validators and a primary network validator 1163 addedValidators: []Staker{stakers[0], stakers[1], stakers[2]}, 1164 expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{ 1165 stakers[1].NodeID: { 1166 NodeID: stakers[1].NodeID, 1167 PublicKey: stakers[1].PublicKey, 1168 Weight: stakers[1].Weight, 1169 }, 1170 }, 1171 expectedSubnetValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{ 1172 stakers[0].NodeID: { 1173 NodeID: stakers[0].NodeID, 1174 Weight: stakers[0].Weight, 1175 }, 1176 stakers[2].NodeID: { 1177 NodeID: stakers[2].NodeID, 1178 Weight: stakers[2].Weight, 1179 }, 1180 }, 1181 }, 1182 { 1183 // Remove 2 subnet validators and a primary network validator. 1184 removedValidators: []Staker{stakers[0], stakers[1], stakers[2]}, 1185 expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{}, 1186 expectedSubnetValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{}, 1187 }, 1188 } 1189 for currentIndex, diff := range diffs { 1190 for _, added := range diff.addedValidators { 1191 added := added 1192 state.PutCurrentValidator(&added) 1193 } 1194 for _, added := range diff.addedDelegators { 1195 added := added 1196 state.PutCurrentDelegator(&added) 1197 } 1198 for _, removed := range diff.removedDelegators { 1199 removed := removed 1200 state.DeleteCurrentDelegator(&removed) 1201 } 1202 for _, removed := range diff.removedValidators { 1203 removed := removed 1204 state.DeleteCurrentValidator(&removed) 1205 } 1206 1207 currentHeight := uint64(currentIndex + 1) 1208 state.SetHeight(currentHeight) 1209 1210 require.NoError(state.Commit()) 1211 1212 for _, added := range diff.addedValidators { 1213 gotValidator, err := state.GetCurrentValidator(added.SubnetID, added.NodeID) 1214 require.NoError(err) 1215 require.Equal(added, *gotValidator) 1216 } 1217 1218 for _, removed := range diff.removedValidators { 1219 _, err := state.GetCurrentValidator(removed.SubnetID, removed.NodeID) 1220 require.ErrorIs(err, database.ErrNotFound) 1221 } 1222 1223 for i := 0; i < currentIndex; i++ { 1224 prevDiff := diffs[i] 1225 prevHeight := uint64(i + 1) 1226 1227 primaryValidatorSet := copyValidatorSet(diff.expectedPrimaryValidatorSet) 1228 require.NoError(state.ApplyValidatorWeightDiffs( 1229 context.Background(), 1230 primaryValidatorSet, 1231 currentHeight, 1232 prevHeight+1, 1233 constants.PrimaryNetworkID, 1234 )) 1235 requireEqualWeightsValidatorSet(require, prevDiff.expectedPrimaryValidatorSet, primaryValidatorSet) 1236 1237 require.NoError(state.ApplyValidatorPublicKeyDiffs( 1238 context.Background(), 1239 primaryValidatorSet, 1240 currentHeight, 1241 prevHeight+1, 1242 )) 1243 requireEqualPublicKeysValidatorSet(require, prevDiff.expectedPrimaryValidatorSet, primaryValidatorSet) 1244 1245 subnetValidatorSet := copyValidatorSet(diff.expectedSubnetValidatorSet) 1246 require.NoError(state.ApplyValidatorWeightDiffs( 1247 context.Background(), 1248 subnetValidatorSet, 1249 currentHeight, 1250 prevHeight+1, 1251 subnetID, 1252 )) 1253 requireEqualWeightsValidatorSet(require, prevDiff.expectedSubnetValidatorSet, subnetValidatorSet) 1254 } 1255 } 1256 } 1257 1258 func copyValidatorSet( 1259 input map[ids.NodeID]*validators.GetValidatorOutput, 1260 ) map[ids.NodeID]*validators.GetValidatorOutput { 1261 result := make(map[ids.NodeID]*validators.GetValidatorOutput, len(input)) 1262 for nodeID, vdr := range input { 1263 vdrCopy := *vdr 1264 result[nodeID] = &vdrCopy 1265 } 1266 return result 1267 } 1268 1269 func requireEqualWeightsValidatorSet( 1270 require *require.Assertions, 1271 expected map[ids.NodeID]*validators.GetValidatorOutput, 1272 actual map[ids.NodeID]*validators.GetValidatorOutput, 1273 ) { 1274 require.Len(actual, len(expected)) 1275 for nodeID, expectedVdr := range expected { 1276 require.Contains(actual, nodeID) 1277 1278 actualVdr := actual[nodeID] 1279 require.Equal(expectedVdr.NodeID, actualVdr.NodeID) 1280 require.Equal(expectedVdr.Weight, actualVdr.Weight) 1281 } 1282 } 1283 1284 func requireEqualPublicKeysValidatorSet( 1285 require *require.Assertions, 1286 expected map[ids.NodeID]*validators.GetValidatorOutput, 1287 actual map[ids.NodeID]*validators.GetValidatorOutput, 1288 ) { 1289 require.Len(actual, len(expected)) 1290 for nodeID, expectedVdr := range expected { 1291 require.Contains(actual, nodeID) 1292 1293 actualVdr := actual[nodeID] 1294 require.Equal(expectedVdr.NodeID, actualVdr.NodeID) 1295 require.Equal(expectedVdr.PublicKey, actualVdr.PublicKey) 1296 } 1297 } 1298 1299 func TestParsedStateBlock(t *testing.T) { 1300 var ( 1301 require = require.New(t) 1302 blks = makeBlocks(require) 1303 ) 1304 1305 for _, blk := range blks { 1306 stBlk := stateBlk{ 1307 Bytes: blk.Bytes(), 1308 Status: choices.Accepted, 1309 } 1310 1311 stBlkBytes, err := block.GenesisCodec.Marshal(block.CodecVersion, &stBlk) 1312 require.NoError(err) 1313 1314 gotBlk, isStateBlk, err := parseStoredBlock(stBlkBytes) 1315 require.NoError(err) 1316 require.True(isStateBlk) 1317 require.Equal(blk.ID(), gotBlk.ID()) 1318 1319 gotBlk, isStateBlk, err = parseStoredBlock(blk.Bytes()) 1320 require.NoError(err) 1321 require.False(isStateBlk) 1322 require.Equal(blk.ID(), gotBlk.ID()) 1323 } 1324 } 1325 1326 func TestReindexBlocks(t *testing.T) { 1327 var ( 1328 require = require.New(t) 1329 s = newInitializedState(require).(*state) 1330 blks = makeBlocks(require) 1331 ) 1332 1333 // Populate the blocks using the legacy format. 1334 for _, blk := range blks { 1335 stBlk := stateBlk{ 1336 Bytes: blk.Bytes(), 1337 Status: choices.Accepted, 1338 } 1339 stBlkBytes, err := block.GenesisCodec.Marshal(block.CodecVersion, &stBlk) 1340 require.NoError(err) 1341 1342 blkID := blk.ID() 1343 require.NoError(s.blockDB.Put(blkID[:], stBlkBytes)) 1344 } 1345 1346 // Convert the indices to the new format. 1347 require.NoError(s.ReindexBlocks(&sync.Mutex{}, logging.NoLog{})) 1348 1349 // Verify that the blocks are stored in the new format. 1350 for _, blk := range blks { 1351 blkID := blk.ID() 1352 blkBytes, err := s.blockDB.Get(blkID[:]) 1353 require.NoError(err) 1354 1355 parsedBlk, err := block.Parse(block.GenesisCodec, blkBytes) 1356 require.NoError(err) 1357 require.Equal(blkID, parsedBlk.ID()) 1358 } 1359 1360 // Verify that the flag has been written to disk to allow skipping future 1361 // reindexings. 1362 reindexed, err := s.singletonDB.Has(BlocksReindexedKey) 1363 require.NoError(err) 1364 require.True(reindexed) 1365 } 1366 1367 func TestStateSubnetOwner(t *testing.T) { 1368 require := require.New(t) 1369 1370 state := newInitializedState(require) 1371 ctrl := gomock.NewController(t) 1372 1373 var ( 1374 owner1 = fx.NewMockOwner(ctrl) 1375 owner2 = fx.NewMockOwner(ctrl) 1376 1377 createSubnetTx = &txs.Tx{ 1378 Unsigned: &txs.CreateSubnetTx{ 1379 BaseTx: txs.BaseTx{}, 1380 Owner: owner1, 1381 }, 1382 } 1383 1384 subnetID = createSubnetTx.ID() 1385 ) 1386 1387 owner, err := state.GetSubnetOwner(subnetID) 1388 require.ErrorIs(err, database.ErrNotFound) 1389 require.Nil(owner) 1390 1391 state.AddSubnet(subnetID) 1392 state.SetSubnetOwner(subnetID, owner1) 1393 1394 owner, err = state.GetSubnetOwner(subnetID) 1395 require.NoError(err) 1396 require.Equal(owner1, owner) 1397 1398 state.SetSubnetOwner(subnetID, owner2) 1399 owner, err = state.GetSubnetOwner(subnetID) 1400 require.NoError(err) 1401 require.Equal(owner2, owner) 1402 } 1403 1404 func makeBlocks(require *require.Assertions) []block.Block { 1405 var blks []block.Block 1406 { 1407 blk, err := block.NewApricotAbortBlock(ids.GenerateTestID(), 1000) 1408 require.NoError(err) 1409 blks = append(blks, blk) 1410 } 1411 1412 { 1413 blk, err := block.NewApricotAtomicBlock(ids.GenerateTestID(), 1000, &txs.Tx{ 1414 Unsigned: &txs.AdvanceTimeTx{ 1415 Time: 1000, 1416 }, 1417 }) 1418 require.NoError(err) 1419 blks = append(blks, blk) 1420 } 1421 1422 { 1423 blk, err := block.NewApricotCommitBlock(ids.GenerateTestID(), 1000) 1424 require.NoError(err) 1425 blks = append(blks, blk) 1426 } 1427 1428 { 1429 tx := &txs.Tx{ 1430 Unsigned: &txs.RewardValidatorTx{ 1431 TxID: ids.GenerateTestID(), 1432 }, 1433 } 1434 require.NoError(tx.Initialize(txs.Codec)) 1435 blk, err := block.NewApricotProposalBlock(ids.GenerateTestID(), 1000, tx) 1436 require.NoError(err) 1437 blks = append(blks, blk) 1438 } 1439 1440 { 1441 tx := &txs.Tx{ 1442 Unsigned: &txs.RewardValidatorTx{ 1443 TxID: ids.GenerateTestID(), 1444 }, 1445 } 1446 require.NoError(tx.Initialize(txs.Codec)) 1447 blk, err := block.NewApricotStandardBlock(ids.GenerateTestID(), 1000, []*txs.Tx{tx}) 1448 require.NoError(err) 1449 blks = append(blks, blk) 1450 } 1451 1452 { 1453 blk, err := block.NewBanffAbortBlock(time.Now(), ids.GenerateTestID(), 1000) 1454 require.NoError(err) 1455 blks = append(blks, blk) 1456 } 1457 1458 { 1459 blk, err := block.NewBanffCommitBlock(time.Now(), ids.GenerateTestID(), 1000) 1460 require.NoError(err) 1461 blks = append(blks, blk) 1462 } 1463 1464 { 1465 tx := &txs.Tx{ 1466 Unsigned: &txs.RewardValidatorTx{ 1467 TxID: ids.GenerateTestID(), 1468 }, 1469 } 1470 require.NoError(tx.Initialize(txs.Codec)) 1471 1472 blk, err := block.NewBanffProposalBlock(time.Now(), ids.GenerateTestID(), 1000, tx, []*txs.Tx{}) 1473 require.NoError(err) 1474 blks = append(blks, blk) 1475 } 1476 1477 { 1478 tx := &txs.Tx{ 1479 Unsigned: &txs.RewardValidatorTx{ 1480 TxID: ids.GenerateTestID(), 1481 }, 1482 } 1483 require.NoError(tx.Initialize(txs.Codec)) 1484 1485 blk, err := block.NewBanffStandardBlock(time.Now(), ids.GenerateTestID(), 1000, []*txs.Tx{tx}) 1486 require.NoError(err) 1487 blks = append(blks, blk) 1488 } 1489 return blks 1490 }