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