github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/validator_set_property_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 platformvm 5 6 import ( 7 "context" 8 "errors" 9 "fmt" 10 "reflect" 11 "sort" 12 "testing" 13 "time" 14 15 "github.com/leanovate/gopter" 16 "github.com/leanovate/gopter/gen" 17 "github.com/leanovate/gopter/prop" 18 "github.com/stretchr/testify/require" 19 "golang.org/x/exp/maps" 20 21 "github.com/ava-labs/avalanchego/chains" 22 "github.com/ava-labs/avalanchego/chains/atomic" 23 "github.com/ava-labs/avalanchego/database/memdb" 24 "github.com/ava-labs/avalanchego/database/prefixdb" 25 "github.com/ava-labs/avalanchego/ids" 26 "github.com/ava-labs/avalanchego/snow" 27 "github.com/ava-labs/avalanchego/snow/consensus/snowman" 28 "github.com/ava-labs/avalanchego/snow/engine/common" 29 "github.com/ava-labs/avalanchego/snow/engine/enginetest" 30 "github.com/ava-labs/avalanchego/snow/snowtest" 31 "github.com/ava-labs/avalanchego/snow/uptime" 32 "github.com/ava-labs/avalanchego/snow/validators" 33 "github.com/ava-labs/avalanchego/upgrade/upgradetest" 34 "github.com/ava-labs/avalanchego/utils/constants" 35 "github.com/ava-labs/avalanchego/utils/crypto/bls" 36 "github.com/ava-labs/avalanchego/utils/timer/mockable" 37 "github.com/ava-labs/avalanchego/vms/platformvm/block" 38 "github.com/ava-labs/avalanchego/vms/platformvm/config" 39 "github.com/ava-labs/avalanchego/vms/platformvm/genesis/genesistest" 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/state" 43 "github.com/ava-labs/avalanchego/vms/platformvm/txs" 44 "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" 45 "github.com/ava-labs/avalanchego/vms/secp256k1fx" 46 47 blockexecutor "github.com/ava-labs/avalanchego/vms/platformvm/block/executor" 48 txexecutor "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" 49 walletcommon "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" 50 ) 51 52 const ( 53 startPrimaryWithBLS uint8 = iota 54 startSubnetValidator 55 56 failedValidatorSnapshotString = "could not take validators snapshot: " 57 failedBuildingEventSeqString = "failed building events sequence: " 58 ) 59 60 var errEmptyEventsList = errors.New("empty events list") 61 62 // for a given (permissioned) subnet, the test stakes and restakes multiple 63 // times a node as a primary and subnet validator. The BLS key of the node is 64 // changed across staking periods, and it can even be nil. We test that 65 // GetValidatorSet returns the correct primary and subnet validators data, with 66 // the right BLS key version at all relevant heights. 67 func TestGetValidatorsSetProperty(t *testing.T) { 68 properties := gopter.NewProperties(nil) 69 70 // to reproduce a given scenario do something like this: 71 // parameters := gopter.DefaultTestParametersWithSeed(1685887576153675816) 72 // properties := gopter.NewProperties(parameters) 73 74 properties.Property("check GetValidatorSet", prop.ForAll( 75 func(events []uint8) string { 76 vm, subnetID, err := buildVM(t) 77 if err != nil { 78 return "failed building vm: " + err.Error() 79 } 80 vm.ctx.Lock.Lock() 81 defer func() { 82 _ = vm.Shutdown(context.Background()) 83 vm.ctx.Lock.Unlock() 84 }() 85 nodeID := ids.GenerateTestNodeID() 86 87 currentTime := genesistest.DefaultValidatorStartTime 88 vm.clock.Set(currentTime) 89 vm.state.SetTimestamp(currentTime) 90 91 // build a valid sequence of validators start/end times, given the 92 // random events sequence received as test input 93 validatorsTimes, err := buildTimestampsList(events, currentTime, nodeID) 94 if err != nil { 95 return "failed building events sequence: " + err.Error() 96 } 97 98 validatorSetByHeightAndSubnet := make(map[uint64]map[ids.ID]map[ids.NodeID]*validators.GetValidatorOutput) 99 if err := takeValidatorsSnapshotAtCurrentHeight(vm, validatorSetByHeightAndSubnet); err != nil { 100 return failedValidatorSnapshotString + err.Error() 101 } 102 103 // insert validator sequence 104 var ( 105 currentPrimaryValidator = (*state.Staker)(nil) 106 currentSubnetValidator = (*state.Staker)(nil) 107 ) 108 for _, ev := range validatorsTimes { 109 // at each step we remove at least a subnet validator 110 if currentSubnetValidator != nil { 111 err := terminateSubnetValidator(vm, currentSubnetValidator) 112 if err != nil { 113 return "could not terminate current subnet validator: " + err.Error() 114 } 115 currentSubnetValidator = nil 116 117 if err := takeValidatorsSnapshotAtCurrentHeight(vm, validatorSetByHeightAndSubnet); err != nil { 118 return failedValidatorSnapshotString + err.Error() 119 } 120 } 121 122 switch ev.eventType { 123 case startSubnetValidator: 124 currentSubnetValidator = addSubnetValidator(t, vm, ev, subnetID) 125 if err := takeValidatorsSnapshotAtCurrentHeight(vm, validatorSetByHeightAndSubnet); err != nil { 126 return failedValidatorSnapshotString + err.Error() 127 } 128 129 case startPrimaryWithBLS: 130 // when adding a primary validator, also remove the current 131 // primary one 132 if currentPrimaryValidator != nil { 133 err := terminatePrimaryValidator(vm, currentPrimaryValidator) 134 if err != nil { 135 return "could not terminate current primary validator: " + err.Error() 136 } 137 // no need to nil current primary validator, we'll 138 // reassign immediately 139 140 if err := takeValidatorsSnapshotAtCurrentHeight(vm, validatorSetByHeightAndSubnet); err != nil { 141 return failedValidatorSnapshotString + err.Error() 142 } 143 } 144 currentPrimaryValidator = addPrimaryValidatorWithBLSKey(t, vm, ev) 145 if err := takeValidatorsSnapshotAtCurrentHeight(vm, validatorSetByHeightAndSubnet); err != nil { 146 return failedValidatorSnapshotString + err.Error() 147 } 148 149 default: 150 return fmt.Sprintf("unexpected staker type: %v", ev.eventType) 151 } 152 } 153 154 // Checks: let's look back at validator sets at previous heights and 155 // make sure they match the snapshots already taken 156 snapshotHeights := maps.Keys(validatorSetByHeightAndSubnet) 157 sort.Slice(snapshotHeights, func(i, j int) bool { return snapshotHeights[i] < snapshotHeights[j] }) 158 for idx, snapShotHeight := range snapshotHeights { 159 lastAcceptedHeight, err := vm.GetCurrentHeight(context.Background()) 160 if err != nil { 161 return err.Error() 162 } 163 164 nextSnapShotHeight := lastAcceptedHeight + 1 165 if idx != len(snapshotHeights)-1 { 166 nextSnapShotHeight = snapshotHeights[idx+1] 167 } 168 169 // within [snapShotHeight] and [nextSnapShotHeight], the validator set 170 // does not change and must be equal to snapshot at [snapShotHeight] 171 for height := snapShotHeight; height < nextSnapShotHeight; height++ { 172 for subnetID, validatorsSet := range validatorSetByHeightAndSubnet[snapShotHeight] { 173 res, err := vm.GetValidatorSet(context.Background(), height, subnetID) 174 if err != nil { 175 return fmt.Sprintf("failed GetValidatorSet at height %v: %v", height, err) 176 } 177 if !reflect.DeepEqual(validatorsSet, res) { 178 return "failed validators set comparison" 179 } 180 } 181 } 182 } 183 184 return "" 185 }, 186 gen.SliceOfN( 187 10, 188 gen.OneConstOf( 189 startPrimaryWithBLS, 190 startSubnetValidator, 191 ), 192 ).SuchThat(func(v interface{}) bool { 193 list := v.([]uint8) 194 return len(list) > 0 && list[0] == startPrimaryWithBLS 195 }), 196 )) 197 198 properties.TestingRun(t) 199 } 200 201 func takeValidatorsSnapshotAtCurrentHeight(vm *VM, validatorsSetByHeightAndSubnet map[uint64]map[ids.ID]map[ids.NodeID]*validators.GetValidatorOutput) error { 202 if validatorsSetByHeightAndSubnet == nil { 203 validatorsSetByHeightAndSubnet = make(map[uint64]map[ids.ID]map[ids.NodeID]*validators.GetValidatorOutput) 204 } 205 206 lastBlkID := vm.state.GetLastAccepted() 207 lastBlk, err := vm.state.GetStatelessBlock(lastBlkID) 208 if err != nil { 209 return err 210 } 211 height := lastBlk.Height() 212 validatorsSetBySubnet, ok := validatorsSetByHeightAndSubnet[height] 213 if !ok { 214 validatorsSetByHeightAndSubnet[height] = make(map[ids.ID]map[ids.NodeID]*validators.GetValidatorOutput) 215 validatorsSetBySubnet = validatorsSetByHeightAndSubnet[height] 216 } 217 218 stakerIt, err := vm.state.GetCurrentStakerIterator() 219 if err != nil { 220 return err 221 } 222 defer stakerIt.Release() 223 for stakerIt.Next() { 224 v := stakerIt.Value() 225 validatorsSet, ok := validatorsSetBySubnet[v.SubnetID] 226 if !ok { 227 validatorsSetBySubnet[v.SubnetID] = make(map[ids.NodeID]*validators.GetValidatorOutput) 228 validatorsSet = validatorsSetBySubnet[v.SubnetID] 229 } 230 231 blsKey := v.PublicKey 232 if v.SubnetID != constants.PrimaryNetworkID { 233 // pick bls key from primary validator 234 s, err := vm.state.GetCurrentValidator(constants.PlatformChainID, v.NodeID) 235 if err != nil { 236 return err 237 } 238 blsKey = s.PublicKey 239 } 240 241 validatorsSet[v.NodeID] = &validators.GetValidatorOutput{ 242 NodeID: v.NodeID, 243 PublicKey: blsKey, 244 Weight: v.Weight, 245 } 246 } 247 return nil 248 } 249 250 func addSubnetValidator(t testing.TB, vm *VM, data *validatorInputData, subnetID ids.ID) *state.Staker { 251 require := require.New(t) 252 253 wallet := newWallet(t, vm, walletConfig{ 254 subnetIDs: []ids.ID{subnetID}, 255 }) 256 tx, err := wallet.IssueAddSubnetValidatorTx( 257 &txs.SubnetValidator{ 258 Validator: txs.Validator{ 259 NodeID: data.nodeID, 260 Start: uint64(data.startTime.Unix()), 261 End: uint64(data.endTime.Unix()), 262 Wght: vm.Config.MinValidatorStake, 263 }, 264 Subnet: subnetID, 265 }, 266 ) 267 require.NoError(err) 268 269 staker, err := internalAddValidator(vm, tx) 270 require.NoError(err) 271 return staker 272 } 273 274 func addPrimaryValidatorWithBLSKey(t testing.TB, vm *VM, data *validatorInputData) *state.Staker { 275 require := require.New(t) 276 277 wallet := newWallet(t, vm, walletConfig{}) 278 279 sk, err := bls.NewSecretKey() 280 require.NoError(err) 281 282 rewardsOwner := &secp256k1fx.OutputOwners{ 283 Threshold: 1, 284 Addrs: []ids.ShortID{ids.GenerateTestShortID()}, 285 } 286 287 tx, err := wallet.IssueAddPermissionlessValidatorTx( 288 &txs.SubnetValidator{ 289 Validator: txs.Validator{ 290 NodeID: data.nodeID, 291 Start: uint64(data.startTime.Unix()), 292 End: uint64(data.endTime.Unix()), 293 Wght: vm.Config.MinValidatorStake, 294 }, 295 Subnet: constants.PrimaryNetworkID, 296 }, 297 signer.NewProofOfPossession(sk), 298 vm.ctx.AVAXAssetID, 299 rewardsOwner, 300 rewardsOwner, 301 reward.PercentDenominator, 302 ) 303 require.NoError(err) 304 305 staker, err := internalAddValidator(vm, tx) 306 require.NoError(err) 307 return staker 308 } 309 310 func internalAddValidator(vm *VM, signedTx *txs.Tx) (*state.Staker, error) { 311 vm.ctx.Lock.Unlock() 312 err := vm.issueTxFromRPC(signedTx) 313 vm.ctx.Lock.Lock() 314 315 if err != nil { 316 return nil, fmt.Errorf("could not add tx to mempool: %w", err) 317 } 318 319 blk, err := vm.Builder.BuildBlock(context.Background()) 320 if err != nil { 321 return nil, fmt.Errorf("failed building block: %w", err) 322 } 323 if err := blk.Verify(context.Background()); err != nil { 324 return nil, fmt.Errorf("failed verifying block: %w", err) 325 } 326 if err := blk.Accept(context.Background()); err != nil { 327 return nil, fmt.Errorf("failed accepting block: %w", err) 328 } 329 if err := vm.SetPreference(context.Background(), vm.manager.LastAccepted()); err != nil { 330 return nil, fmt.Errorf("failed setting preference: %w", err) 331 } 332 333 stakerTx := signedTx.Unsigned.(txs.Staker) 334 return vm.state.GetCurrentValidator(stakerTx.SubnetID(), stakerTx.NodeID()) 335 } 336 337 func terminateSubnetValidator(vm *VM, validator *state.Staker) error { 338 currentTime := validator.EndTime 339 vm.clock.Set(currentTime) 340 vm.state.SetTimestamp(currentTime) 341 342 blk, err := vm.Builder.BuildBlock(context.Background()) 343 if err != nil { 344 return fmt.Errorf("failed building block: %w", err) 345 } 346 if err := blk.Verify(context.Background()); err != nil { 347 return fmt.Errorf("failed verifying block: %w", err) 348 } 349 if err := blk.Accept(context.Background()); err != nil { 350 return fmt.Errorf("failed accepting block: %w", err) 351 } 352 if err := vm.SetPreference(context.Background(), vm.manager.LastAccepted()); err != nil { 353 return fmt.Errorf("failed setting preference: %w", err) 354 } 355 356 return nil 357 } 358 359 func terminatePrimaryValidator(vm *VM, validator *state.Staker) error { 360 currentTime := validator.EndTime 361 vm.clock.Set(currentTime) 362 vm.state.SetTimestamp(currentTime) 363 364 blk, err := vm.Builder.BuildBlock(context.Background()) 365 if err != nil { 366 return fmt.Errorf("failed building block: %w", err) 367 } 368 if err := blk.Verify(context.Background()); err != nil { 369 return fmt.Errorf("failed verifying block: %w", err) 370 } 371 372 proposalBlk := blk.(snowman.OracleBlock) 373 options, err := proposalBlk.Options(context.Background()) 374 if err != nil { 375 return fmt.Errorf("failed retrieving options: %w", err) 376 } 377 378 commit := options[0].(*blockexecutor.Block) 379 _, ok := commit.Block.(*block.BanffCommitBlock) 380 if !ok { 381 return fmt.Errorf("failed retrieving commit option: %w", err) 382 } 383 if err := blk.Accept(context.Background()); err != nil { 384 return fmt.Errorf("failed accepting block: %w", err) 385 } 386 387 if err := commit.Verify(context.Background()); err != nil { 388 return fmt.Errorf("failed verifying commit block: %w", err) 389 } 390 if err := commit.Accept(context.Background()); err != nil { 391 return fmt.Errorf("failed accepting commit block: %w", err) 392 } 393 394 if err := vm.SetPreference(context.Background(), vm.manager.LastAccepted()); err != nil { 395 return fmt.Errorf("failed setting preference: %w", err) 396 } 397 398 return nil 399 } 400 401 type validatorInputData struct { 402 eventType uint8 403 startTime time.Time 404 endTime time.Time 405 nodeID ids.NodeID 406 publicKey *bls.PublicKey 407 } 408 409 // buildTimestampsList creates validators start and end time, given the event list. 410 // output is returned as a list of validatorInputData 411 func buildTimestampsList(events []uint8, currentTime time.Time, nodeID ids.NodeID) ([]*validatorInputData, error) { 412 res := make([]*validatorInputData, 0, len(events)) 413 414 currentTime = currentTime.Add(txexecutor.SyncBound) 415 switch endTime := currentTime.Add(defaultMinStakingDuration); events[0] { 416 case startPrimaryWithBLS: 417 sk, err := bls.NewSecretKey() 418 if err != nil { 419 return nil, fmt.Errorf("could not make private key: %w", err) 420 } 421 422 res = append(res, &validatorInputData{ 423 eventType: startPrimaryWithBLS, 424 startTime: currentTime, 425 endTime: endTime, 426 nodeID: nodeID, 427 publicKey: bls.PublicFromSecretKey(sk), 428 }) 429 default: 430 return nil, fmt.Errorf("unexpected initial event %d", events[0]) 431 } 432 433 // track current primary validator to make sure its staking period 434 // covers all of its subnet validators 435 currentPrimaryVal := res[0] 436 for i := 1; i < len(events); i++ { 437 currentTime = currentTime.Add(txexecutor.SyncBound) 438 439 switch currentEvent := events[i]; currentEvent { 440 case startSubnetValidator: 441 endTime := currentTime.Add(defaultMinStakingDuration) 442 res = append(res, &validatorInputData{ 443 eventType: startSubnetValidator, 444 startTime: currentTime, 445 endTime: endTime, 446 nodeID: nodeID, 447 publicKey: nil, 448 }) 449 450 currentPrimaryVal.endTime = endTime.Add(time.Second) 451 currentTime = endTime.Add(time.Second) 452 453 case startPrimaryWithBLS: 454 currentTime = currentPrimaryVal.endTime.Add(txexecutor.SyncBound) 455 sk, err := bls.NewSecretKey() 456 if err != nil { 457 return nil, fmt.Errorf("could not make private key: %w", err) 458 } 459 460 endTime := currentTime.Add(defaultMinStakingDuration) 461 val := &validatorInputData{ 462 eventType: startPrimaryWithBLS, 463 startTime: currentTime, 464 endTime: endTime, 465 nodeID: nodeID, 466 publicKey: bls.PublicFromSecretKey(sk), 467 } 468 res = append(res, val) 469 currentPrimaryVal = val 470 } 471 } 472 return res, nil 473 } 474 475 func TestTimestampListGenerator(t *testing.T) { 476 properties := gopter.NewProperties(nil) 477 478 properties.Property("primary validators are returned in sequence", prop.ForAll( 479 func(events []uint8) string { 480 currentTime := time.Now() 481 nodeID := ids.GenerateTestNodeID() 482 validatorsTimes, err := buildTimestampsList(events, currentTime, nodeID) 483 if err != nil { 484 return failedBuildingEventSeqString + err.Error() 485 } 486 487 if len(validatorsTimes) == 0 { 488 return errEmptyEventsList.Error() 489 } 490 491 // nil out non subnet validators 492 subnetIndexes := make([]int, 0) 493 for idx, ev := range validatorsTimes { 494 if ev.eventType == startSubnetValidator { 495 subnetIndexes = append(subnetIndexes, idx) 496 } 497 } 498 for _, idx := range subnetIndexes { 499 validatorsTimes[idx] = nil 500 } 501 502 currentEventTime := currentTime 503 for i, ev := range validatorsTimes { 504 if ev == nil { 505 continue // a subnet validator 506 } 507 if currentEventTime.After(ev.startTime) { 508 return fmt.Sprintf("validator %d start time larger than current event time", i) 509 } 510 511 if ev.startTime.After(ev.endTime) { 512 return fmt.Sprintf("validator %d start time larger than its end time", i) 513 } 514 515 currentEventTime = ev.endTime 516 } 517 518 return "" 519 }, 520 gen.SliceOf(gen.OneConstOf( 521 startPrimaryWithBLS, 522 startSubnetValidator, 523 )).SuchThat(func(v interface{}) bool { 524 list := v.([]uint8) 525 return len(list) > 0 && list[0] == startPrimaryWithBLS 526 }), 527 )) 528 529 properties.Property("subnet validators are returned in sequence", prop.ForAll( 530 func(events []uint8) string { 531 currentTime := time.Now() 532 nodeID := ids.GenerateTestNodeID() 533 validatorsTimes, err := buildTimestampsList(events, currentTime, nodeID) 534 if err != nil { 535 return failedBuildingEventSeqString + err.Error() 536 } 537 538 if len(validatorsTimes) == 0 { 539 return errEmptyEventsList.Error() 540 } 541 542 // nil out non subnet validators 543 nonSubnetIndexes := make([]int, 0) 544 for idx, ev := range validatorsTimes { 545 if ev.eventType != startSubnetValidator { 546 nonSubnetIndexes = append(nonSubnetIndexes, idx) 547 } 548 } 549 for _, idx := range nonSubnetIndexes { 550 validatorsTimes[idx] = nil 551 } 552 553 currentEventTime := currentTime 554 for i, ev := range validatorsTimes { 555 if ev == nil { 556 continue // a non-subnet validator 557 } 558 if currentEventTime.After(ev.startTime) { 559 return fmt.Sprintf("validator %d start time larger than current event time", i) 560 } 561 562 if ev.startTime.After(ev.endTime) { 563 return fmt.Sprintf("validator %d start time larger than its end time", i) 564 } 565 566 currentEventTime = ev.endTime 567 } 568 569 return "" 570 }, 571 gen.SliceOf(gen.OneConstOf( 572 startPrimaryWithBLS, 573 startSubnetValidator, 574 )).SuchThat(func(v interface{}) bool { 575 list := v.([]uint8) 576 return len(list) > 0 && list[0] == startPrimaryWithBLS 577 }), 578 )) 579 580 properties.Property("subnet validators' times are bound by a primary validator's times", prop.ForAll( 581 func(events []uint8) string { 582 currentTime := time.Now() 583 nodeID := ids.GenerateTestNodeID() 584 validatorsTimes, err := buildTimestampsList(events, currentTime, nodeID) 585 if err != nil { 586 return failedBuildingEventSeqString + err.Error() 587 } 588 589 if len(validatorsTimes) == 0 { 590 return errEmptyEventsList.Error() 591 } 592 593 currentPrimaryValidator := validatorsTimes[0] 594 for i := 1; i < len(validatorsTimes); i++ { 595 if validatorsTimes[i].eventType != startSubnetValidator { 596 currentPrimaryValidator = validatorsTimes[i] 597 continue 598 } 599 600 subnetVal := validatorsTimes[i] 601 if currentPrimaryValidator.startTime.After(subnetVal.startTime) || 602 subnetVal.endTime.After(currentPrimaryValidator.endTime) { 603 return "subnet validator not bounded by primary network ones" 604 } 605 } 606 return "" 607 }, 608 gen.SliceOf(gen.OneConstOf( 609 startPrimaryWithBLS, 610 startSubnetValidator, 611 )).SuchThat(func(v interface{}) bool { 612 list := v.([]uint8) 613 return len(list) > 0 && list[0] == startPrimaryWithBLS 614 }), 615 )) 616 617 properties.TestingRun(t) 618 } 619 620 // add a single validator at the end of times, 621 // to make sure it won't pollute our tests 622 func buildVM(t *testing.T) (*VM, ids.ID, error) { 623 vm := &VM{Config: config.Config{ 624 Chains: chains.TestManager, 625 UptimeLockedCalculator: uptime.NewLockedCalculator(), 626 SybilProtectionEnabled: true, 627 Validators: validators.NewManager(), 628 StaticFeeConfig: fee.StaticConfig{ 629 TxFee: defaultTxFee, 630 CreateSubnetTxFee: 100 * defaultTxFee, 631 TransformSubnetTxFee: 100 * defaultTxFee, 632 CreateBlockchainTxFee: 100 * defaultTxFee, 633 }, 634 MinValidatorStake: defaultMinValidatorStake, 635 MaxValidatorStake: defaultMaxValidatorStake, 636 MinDelegatorStake: defaultMinDelegatorStake, 637 MinStakeDuration: defaultMinStakingDuration, 638 MaxStakeDuration: defaultMaxStakingDuration, 639 RewardConfig: defaultRewardConfig, 640 UpgradeConfig: upgradetest.GetConfigWithUpgradeTime(upgradetest.Durango, genesistest.DefaultValidatorStartTime), 641 }} 642 vm.clock.Set(genesistest.DefaultValidatorStartTime.Add(time.Second)) 643 644 baseDB := memdb.New() 645 chainDB := prefixdb.New([]byte{0}, baseDB) 646 atomicDB := prefixdb.New([]byte{1}, baseDB) 647 648 msgChan := make(chan common.Message, 1) 649 ctx := snowtest.Context(t, snowtest.PChainID) 650 651 m := atomic.NewMemory(atomicDB) 652 ctx.SharedMemory = m.NewSharedMemory(ctx.ChainID) 653 654 ctx.Lock.Lock() 655 defer ctx.Lock.Unlock() 656 appSender := &enginetest.Sender{} 657 appSender.CantSendAppGossip = true 658 appSender.SendAppGossipF = func(context.Context, common.SendConfig, []byte) error { 659 return nil 660 } 661 662 err := vm.Initialize( 663 context.Background(), 664 ctx, 665 chainDB, 666 genesistest.NewBytes(t, genesistest.Config{ 667 NodeIDs: []ids.NodeID{ 668 genesistest.DefaultNodeIDs[len(genesistest.DefaultNodeIDs)-1], 669 }, 670 ValidatorEndTime: mockable.MaxTime, 671 }), 672 nil, 673 nil, 674 msgChan, 675 nil, 676 appSender, 677 ) 678 if err != nil { 679 return nil, ids.Empty, err 680 } 681 682 err = vm.SetState(context.Background(), snow.NormalOp) 683 if err != nil { 684 return nil, ids.Empty, err 685 } 686 687 // Create a subnet and store it in testSubnet1 688 // Note: following Banff activation, block acceptance will move 689 // chain time ahead 690 wallet := newWallet(t, vm, walletConfig{}) 691 owner := &secp256k1fx.OutputOwners{ 692 Threshold: 1, 693 Addrs: []ids.ShortID{genesistest.DefaultFundedKeys[0].Address()}, 694 } 695 testSubnet1, err = wallet.IssueCreateSubnetTx( 696 owner, 697 walletcommon.WithChangeOwner(owner), 698 ) 699 if err != nil { 700 return nil, ids.Empty, err 701 } 702 703 vm.ctx.Lock.Unlock() 704 err = vm.issueTxFromRPC(testSubnet1) 705 vm.ctx.Lock.Lock() 706 if err != nil { 707 return nil, ids.Empty, err 708 } 709 710 blk, err := vm.Builder.BuildBlock(context.Background()) 711 if err != nil { 712 return nil, ids.Empty, err 713 } 714 if err := blk.Verify(context.Background()); err != nil { 715 return nil, ids.Empty, err 716 } 717 if err := blk.Accept(context.Background()); err != nil { 718 return nil, ids.Empty, err 719 } 720 if err := vm.SetPreference(context.Background(), vm.manager.LastAccepted()); err != nil { 721 return nil, ids.Empty, err 722 } 723 724 return vm, testSubnet1.ID(), nil 725 }