github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/vm_regression_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 "bytes" 8 "context" 9 "errors" 10 "testing" 11 "time" 12 13 "github.com/prometheus/client_golang/prometheus" 14 "github.com/stretchr/testify/require" 15 "golang.org/x/sync/errgroup" 16 17 "github.com/MetalBlockchain/metalgo/chains" 18 "github.com/MetalBlockchain/metalgo/chains/atomic" 19 "github.com/MetalBlockchain/metalgo/database" 20 "github.com/MetalBlockchain/metalgo/database/memdb" 21 "github.com/MetalBlockchain/metalgo/database/prefixdb" 22 "github.com/MetalBlockchain/metalgo/ids" 23 "github.com/MetalBlockchain/metalgo/network/p2p" 24 "github.com/MetalBlockchain/metalgo/network/p2p/gossip" 25 "github.com/MetalBlockchain/metalgo/snow/choices" 26 "github.com/MetalBlockchain/metalgo/snow/consensus/snowman" 27 "github.com/MetalBlockchain/metalgo/snow/engine/common" 28 "github.com/MetalBlockchain/metalgo/snow/snowtest" 29 "github.com/MetalBlockchain/metalgo/snow/uptime" 30 "github.com/MetalBlockchain/metalgo/snow/validators" 31 "github.com/MetalBlockchain/metalgo/utils/bloom" 32 "github.com/MetalBlockchain/metalgo/utils/constants" 33 "github.com/MetalBlockchain/metalgo/utils/crypto/bls" 34 "github.com/MetalBlockchain/metalgo/utils/crypto/secp256k1" 35 "github.com/MetalBlockchain/metalgo/utils/timer/mockable" 36 "github.com/MetalBlockchain/metalgo/version" 37 "github.com/MetalBlockchain/metalgo/vms/components/avax" 38 "github.com/MetalBlockchain/metalgo/vms/platformvm/block" 39 "github.com/MetalBlockchain/metalgo/vms/platformvm/config" 40 "github.com/MetalBlockchain/metalgo/vms/platformvm/metrics" 41 "github.com/MetalBlockchain/metalgo/vms/platformvm/network" 42 "github.com/MetalBlockchain/metalgo/vms/platformvm/reward" 43 "github.com/MetalBlockchain/metalgo/vms/platformvm/signer" 44 "github.com/MetalBlockchain/metalgo/vms/platformvm/state" 45 "github.com/MetalBlockchain/metalgo/vms/platformvm/txs" 46 "github.com/MetalBlockchain/metalgo/vms/platformvm/txs/executor" 47 "github.com/MetalBlockchain/metalgo/vms/platformvm/txs/txstest" 48 "github.com/MetalBlockchain/metalgo/vms/platformvm/upgrade" 49 "github.com/MetalBlockchain/metalgo/vms/secp256k1fx" 50 51 blockexecutor "github.com/MetalBlockchain/metalgo/vms/platformvm/block/executor" 52 walletsigner "github.com/MetalBlockchain/metalgo/wallet/chain/p/signer" 53 walletcommon "github.com/MetalBlockchain/metalgo/wallet/subnet/primary/common" 54 ) 55 56 func TestAddDelegatorTxOverDelegatedRegression(t *testing.T) { 57 require := require.New(t) 58 vm, factory, _, _ := defaultVM(t, cortina) 59 vm.ctx.Lock.Lock() 60 defer vm.ctx.Lock.Unlock() 61 62 validatorStartTime := vm.clock.Time().Add(executor.SyncBound).Add(1 * time.Second) 63 validatorEndTime := validatorStartTime.Add(360 * 24 * time.Hour) 64 65 nodeID := ids.GenerateTestNodeID() 66 changeAddr := keys[0].PublicKey().Address() 67 68 // create valid tx 69 builder, txSigner := factory.NewWallet(keys[0]) 70 utx, err := builder.NewAddValidatorTx( 71 &txs.Validator{ 72 NodeID: nodeID, 73 Start: uint64(validatorStartTime.Unix()), 74 End: uint64(validatorEndTime.Unix()), 75 Wght: vm.MinValidatorStake, 76 }, 77 &secp256k1fx.OutputOwners{ 78 Threshold: 1, 79 Addrs: []ids.ShortID{changeAddr}, 80 }, 81 reward.PercentDenominator, 82 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 83 Threshold: 1, 84 Addrs: []ids.ShortID{changeAddr}, 85 }), 86 ) 87 require.NoError(err) 88 addValidatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, utx) 89 require.NoError(err) 90 91 // trigger block creation 92 vm.ctx.Lock.Unlock() 93 require.NoError(vm.issueTxFromRPC(addValidatorTx)) 94 vm.ctx.Lock.Lock() 95 96 addValidatorBlock, err := vm.Builder.BuildBlock(context.Background()) 97 require.NoError(err) 98 require.NoError(addValidatorBlock.Verify(context.Background())) 99 require.NoError(addValidatorBlock.Accept(context.Background())) 100 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 101 102 vm.clock.Set(validatorStartTime) 103 104 firstAdvanceTimeBlock, err := vm.Builder.BuildBlock(context.Background()) 105 require.NoError(err) 106 require.NoError(firstAdvanceTimeBlock.Verify(context.Background())) 107 require.NoError(firstAdvanceTimeBlock.Accept(context.Background())) 108 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 109 110 firstDelegatorStartTime := validatorStartTime.Add(executor.SyncBound).Add(1 * time.Second) 111 firstDelegatorEndTime := firstDelegatorStartTime.Add(vm.MinStakeDuration) 112 113 // create valid tx 114 builder, txSigner = factory.NewWallet(keys[0], keys[1]) 115 uDelTx1, err := builder.NewAddDelegatorTx( 116 &txs.Validator{ 117 NodeID: nodeID, 118 Start: uint64(firstDelegatorStartTime.Unix()), 119 End: uint64(firstDelegatorEndTime.Unix()), 120 Wght: 4 * vm.MinValidatorStake, // maximum amount of stake this delegator can provide 121 }, 122 &secp256k1fx.OutputOwners{ 123 Threshold: 1, 124 Addrs: []ids.ShortID{changeAddr}, 125 }, 126 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 127 Threshold: 1, 128 Addrs: []ids.ShortID{changeAddr}, 129 }), 130 ) 131 require.NoError(err) 132 addFirstDelegatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uDelTx1) 133 require.NoError(err) 134 135 // trigger block creation 136 vm.ctx.Lock.Unlock() 137 require.NoError(vm.issueTxFromRPC(addFirstDelegatorTx)) 138 vm.ctx.Lock.Lock() 139 140 addFirstDelegatorBlock, err := vm.Builder.BuildBlock(context.Background()) 141 require.NoError(err) 142 require.NoError(addFirstDelegatorBlock.Verify(context.Background())) 143 require.NoError(addFirstDelegatorBlock.Accept(context.Background())) 144 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 145 146 vm.clock.Set(firstDelegatorStartTime) 147 148 secondAdvanceTimeBlock, err := vm.Builder.BuildBlock(context.Background()) 149 require.NoError(err) 150 require.NoError(secondAdvanceTimeBlock.Verify(context.Background())) 151 require.NoError(secondAdvanceTimeBlock.Accept(context.Background())) 152 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 153 154 secondDelegatorStartTime := firstDelegatorEndTime.Add(2 * time.Second) 155 secondDelegatorEndTime := secondDelegatorStartTime.Add(vm.MinStakeDuration) 156 157 vm.clock.Set(secondDelegatorStartTime.Add(-10 * executor.SyncBound)) 158 159 // create valid tx 160 builder, txSigner = factory.NewWallet(keys[0], keys[1], keys[3]) 161 uDelTx2, err := builder.NewAddDelegatorTx( 162 &txs.Validator{ 163 NodeID: nodeID, 164 Start: uint64(secondDelegatorStartTime.Unix()), 165 End: uint64(secondDelegatorEndTime.Unix()), 166 Wght: vm.MinDelegatorStake, 167 }, 168 &secp256k1fx.OutputOwners{ 169 Threshold: 1, 170 Addrs: []ids.ShortID{changeAddr}, 171 }, 172 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 173 Threshold: 1, 174 Addrs: []ids.ShortID{changeAddr}, 175 }), 176 ) 177 require.NoError(err) 178 addSecondDelegatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uDelTx2) 179 require.NoError(err) 180 181 // trigger block creation 182 vm.ctx.Lock.Unlock() 183 require.NoError(vm.issueTxFromRPC(addSecondDelegatorTx)) 184 vm.ctx.Lock.Lock() 185 186 addSecondDelegatorBlock, err := vm.Builder.BuildBlock(context.Background()) 187 require.NoError(err) 188 require.NoError(addSecondDelegatorBlock.Verify(context.Background())) 189 require.NoError(addSecondDelegatorBlock.Accept(context.Background())) 190 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 191 192 thirdDelegatorStartTime := firstDelegatorEndTime.Add(-time.Second) 193 thirdDelegatorEndTime := thirdDelegatorStartTime.Add(vm.MinStakeDuration) 194 195 // create valid tx 196 builder, txSigner = factory.NewWallet(keys[0], keys[1], keys[4]) 197 uDelTx3, err := builder.NewAddDelegatorTx( 198 &txs.Validator{ 199 NodeID: nodeID, 200 Start: uint64(thirdDelegatorStartTime.Unix()), 201 End: uint64(thirdDelegatorEndTime.Unix()), 202 Wght: vm.MinDelegatorStake, 203 }, 204 &secp256k1fx.OutputOwners{ 205 Threshold: 1, 206 Addrs: []ids.ShortID{changeAddr}, 207 }, 208 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 209 Threshold: 1, 210 Addrs: []ids.ShortID{changeAddr}, 211 }), 212 ) 213 require.NoError(err) 214 addThirdDelegatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uDelTx3) 215 require.NoError(err) 216 217 // trigger block creation 218 vm.ctx.Lock.Unlock() 219 err = vm.issueTxFromRPC(addThirdDelegatorTx) 220 require.ErrorIs(err, executor.ErrOverDelegated) 221 vm.ctx.Lock.Lock() 222 } 223 224 func TestAddDelegatorTxHeapCorruption(t *testing.T) { 225 validatorStartTime := latestForkTime.Add(executor.SyncBound).Add(1 * time.Second) 226 validatorEndTime := validatorStartTime.Add(360 * 24 * time.Hour) 227 validatorStake := defaultMaxValidatorStake / 5 228 229 delegator1StartTime := validatorStartTime 230 delegator1EndTime := delegator1StartTime.Add(3 * defaultMinStakingDuration) 231 delegator1Stake := defaultMinValidatorStake 232 233 delegator2StartTime := validatorStartTime.Add(1 * defaultMinStakingDuration) 234 delegator2EndTime := delegator1StartTime.Add(6 * defaultMinStakingDuration) 235 delegator2Stake := defaultMinValidatorStake 236 237 delegator3StartTime := validatorStartTime.Add(2 * defaultMinStakingDuration) 238 delegator3EndTime := delegator1StartTime.Add(4 * defaultMinStakingDuration) 239 delegator3Stake := defaultMaxValidatorStake - validatorStake - 2*defaultMinValidatorStake 240 241 delegator4StartTime := validatorStartTime.Add(5 * defaultMinStakingDuration) 242 delegator4EndTime := delegator1StartTime.Add(7 * defaultMinStakingDuration) 243 delegator4Stake := defaultMaxValidatorStake - validatorStake - defaultMinValidatorStake 244 245 tests := []struct { 246 name string 247 ap3Time time.Time 248 }{ 249 { 250 name: "pre-upgrade is no longer restrictive", 251 ap3Time: validatorEndTime, 252 }, 253 { 254 name: "post-upgrade calculate max stake correctly", 255 ap3Time: defaultGenesisTime, 256 }, 257 } 258 259 for _, test := range tests { 260 t.Run(test.name, func(t *testing.T) { 261 require := require.New(t) 262 263 vm, factory, _, _ := defaultVM(t, apricotPhase3) 264 vm.UpgradeConfig.ApricotPhase3Time = test.ap3Time 265 266 vm.ctx.Lock.Lock() 267 defer vm.ctx.Lock.Unlock() 268 269 key, err := secp256k1.NewPrivateKey() 270 require.NoError(err) 271 272 id := key.PublicKey().Address() 273 nodeID := ids.GenerateTestNodeID() 274 changeAddr := keys[0].PublicKey().Address() 275 276 // create valid tx 277 builder, txSigner := factory.NewWallet(keys[0], keys[1]) 278 utx, err := builder.NewAddValidatorTx( 279 &txs.Validator{ 280 NodeID: nodeID, 281 Start: uint64(validatorStartTime.Unix()), 282 End: uint64(validatorEndTime.Unix()), 283 Wght: validatorStake, 284 }, 285 &secp256k1fx.OutputOwners{ 286 Threshold: 1, 287 Addrs: []ids.ShortID{id}, 288 }, 289 reward.PercentDenominator, 290 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 291 Threshold: 1, 292 Addrs: []ids.ShortID{changeAddr}, 293 }), 294 ) 295 require.NoError(err) 296 addValidatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, utx) 297 require.NoError(err) 298 299 // issue the add validator tx 300 vm.ctx.Lock.Unlock() 301 require.NoError(vm.issueTxFromRPC(addValidatorTx)) 302 vm.ctx.Lock.Lock() 303 304 // trigger block creation for the validator tx 305 addValidatorBlock, err := vm.Builder.BuildBlock(context.Background()) 306 require.NoError(err) 307 require.NoError(addValidatorBlock.Verify(context.Background())) 308 require.NoError(addValidatorBlock.Accept(context.Background())) 309 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 310 311 // create valid tx 312 uDelTx1, err := builder.NewAddDelegatorTx( 313 &txs.Validator{ 314 NodeID: nodeID, 315 Start: uint64(delegator1StartTime.Unix()), 316 End: uint64(delegator1EndTime.Unix()), 317 Wght: delegator1Stake, 318 }, 319 &secp256k1fx.OutputOwners{ 320 Threshold: 1, 321 Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, 322 }, 323 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 324 Threshold: 1, 325 Addrs: []ids.ShortID{changeAddr}, 326 }), 327 ) 328 require.NoError(err) 329 addFirstDelegatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uDelTx1) 330 require.NoError(err) 331 332 // issue the first add delegator tx 333 vm.ctx.Lock.Unlock() 334 require.NoError(vm.issueTxFromRPC(addFirstDelegatorTx)) 335 vm.ctx.Lock.Lock() 336 337 // trigger block creation for the first add delegator tx 338 addFirstDelegatorBlock, err := vm.Builder.BuildBlock(context.Background()) 339 require.NoError(err) 340 require.NoError(addFirstDelegatorBlock.Verify(context.Background())) 341 require.NoError(addFirstDelegatorBlock.Accept(context.Background())) 342 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 343 344 // create valid tx 345 uDelTx2, err := builder.NewAddDelegatorTx( 346 &txs.Validator{ 347 NodeID: nodeID, 348 Start: uint64(delegator2StartTime.Unix()), 349 End: uint64(delegator2EndTime.Unix()), 350 Wght: delegator2Stake, 351 }, 352 &secp256k1fx.OutputOwners{ 353 Threshold: 1, 354 Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, 355 }, 356 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 357 Threshold: 1, 358 Addrs: []ids.ShortID{changeAddr}, 359 }), 360 ) 361 require.NoError(err) 362 addSecondDelegatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uDelTx2) 363 require.NoError(err) 364 365 // issue the second add delegator tx 366 vm.ctx.Lock.Unlock() 367 require.NoError(vm.issueTxFromRPC(addSecondDelegatorTx)) 368 vm.ctx.Lock.Lock() 369 370 // trigger block creation for the second add delegator tx 371 addSecondDelegatorBlock, err := vm.Builder.BuildBlock(context.Background()) 372 require.NoError(err) 373 require.NoError(addSecondDelegatorBlock.Verify(context.Background())) 374 require.NoError(addSecondDelegatorBlock.Accept(context.Background())) 375 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 376 377 // create valid tx 378 uDelTx3, err := builder.NewAddDelegatorTx( 379 &txs.Validator{ 380 NodeID: nodeID, 381 Start: uint64(delegator3StartTime.Unix()), 382 End: uint64(delegator3EndTime.Unix()), 383 Wght: delegator3Stake, 384 }, 385 &secp256k1fx.OutputOwners{ 386 Threshold: 1, 387 Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, 388 }, 389 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 390 Threshold: 1, 391 Addrs: []ids.ShortID{changeAddr}, 392 }), 393 ) 394 require.NoError(err) 395 addThirdDelegatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uDelTx3) 396 require.NoError(err) 397 398 // issue the third add delegator tx 399 vm.ctx.Lock.Unlock() 400 require.NoError(vm.issueTxFromRPC(addThirdDelegatorTx)) 401 vm.ctx.Lock.Lock() 402 403 // trigger block creation for the third add delegator tx 404 addThirdDelegatorBlock, err := vm.Builder.BuildBlock(context.Background()) 405 require.NoError(err) 406 require.NoError(addThirdDelegatorBlock.Verify(context.Background())) 407 require.NoError(addThirdDelegatorBlock.Accept(context.Background())) 408 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 409 410 // create valid tx 411 uDelTx4, err := builder.NewAddDelegatorTx( 412 &txs.Validator{ 413 NodeID: nodeID, 414 Start: uint64(delegator4StartTime.Unix()), 415 End: uint64(delegator4EndTime.Unix()), 416 Wght: delegator4Stake, 417 }, 418 &secp256k1fx.OutputOwners{ 419 Threshold: 1, 420 Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, 421 }, 422 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 423 Threshold: 1, 424 Addrs: []ids.ShortID{changeAddr}, 425 }), 426 ) 427 require.NoError(err) 428 addFourthDelegatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uDelTx4) 429 require.NoError(err) 430 431 // issue the fourth add delegator tx 432 vm.ctx.Lock.Unlock() 433 require.NoError(vm.issueTxFromRPC(addFourthDelegatorTx)) 434 vm.ctx.Lock.Lock() 435 436 // trigger block creation for the fourth add delegator tx 437 addFourthDelegatorBlock, err := vm.Builder.BuildBlock(context.Background()) 438 require.NoError(err) 439 require.NoError(addFourthDelegatorBlock.Verify(context.Background())) 440 require.NoError(addFourthDelegatorBlock.Accept(context.Background())) 441 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 442 }) 443 } 444 } 445 446 // Test that calling Verify on a block with an unverified parent doesn't cause a 447 // panic. 448 func TestUnverifiedParentPanicRegression(t *testing.T) { 449 require := require.New(t) 450 451 baseDB := memdb.New() 452 atomicDB := prefixdb.New([]byte{1}, baseDB) 453 454 vm := &VM{Config: config.Config{ 455 Chains: chains.TestManager, 456 Validators: validators.NewManager(), 457 UptimeLockedCalculator: uptime.NewLockedCalculator(), 458 MinStakeDuration: defaultMinStakingDuration, 459 MaxStakeDuration: defaultMaxStakingDuration, 460 RewardConfig: defaultRewardConfig, 461 UpgradeConfig: upgrade.Config{ 462 BanffTime: latestForkTime, 463 CortinaTime: mockable.MaxTime, 464 DurangoTime: mockable.MaxTime, 465 EUpgradeTime: mockable.MaxTime, 466 }, 467 }} 468 469 ctx := snowtest.Context(t, snowtest.PChainID) 470 ctx.Lock.Lock() 471 defer func() { 472 require.NoError(vm.Shutdown(context.Background())) 473 ctx.Lock.Unlock() 474 }() 475 476 _, genesisBytes := defaultGenesis(t, ctx.AVAXAssetID) 477 478 msgChan := make(chan common.Message, 1) 479 require.NoError(vm.Initialize( 480 context.Background(), 481 ctx, 482 baseDB, 483 genesisBytes, 484 nil, 485 nil, 486 msgChan, 487 nil, 488 nil, 489 )) 490 491 m := atomic.NewMemory(atomicDB) 492 vm.ctx.SharedMemory = m.NewSharedMemory(ctx.ChainID) 493 494 // set time to post Banff fork 495 vm.clock.Set(latestForkTime.Add(time.Second)) 496 vm.state.SetTimestamp(latestForkTime.Add(time.Second)) 497 498 key0 := keys[0] 499 key1 := keys[1] 500 addr0 := key0.PublicKey().Address() 501 addr1 := key1.PublicKey().Address() 502 503 factory := txstest.NewWalletFactory( 504 vm.ctx, 505 &vm.Config, 506 vm.state, 507 ) 508 509 builder, txSigner := factory.NewWallet(key0) 510 utx0, err := builder.NewCreateSubnetTx( 511 &secp256k1fx.OutputOwners{ 512 Threshold: 1, 513 Addrs: []ids.ShortID{addr0}, 514 }, 515 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 516 Threshold: 1, 517 Addrs: []ids.ShortID{addr0}, 518 }), 519 ) 520 require.NoError(err) 521 addSubnetTx0, err := walletsigner.SignUnsigned(context.Background(), txSigner, utx0) 522 require.NoError(err) 523 524 builder, txSigner = factory.NewWallet(key1) 525 utx1, err := builder.NewCreateSubnetTx( 526 &secp256k1fx.OutputOwners{ 527 Threshold: 1, 528 Addrs: []ids.ShortID{addr1}, 529 }, 530 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 531 Threshold: 1, 532 Addrs: []ids.ShortID{addr1}, 533 }), 534 ) 535 require.NoError(err) 536 addSubnetTx1, err := walletsigner.SignUnsigned(context.Background(), txSigner, utx1) 537 require.NoError(err) 538 539 utx2, err := builder.NewCreateSubnetTx( 540 &secp256k1fx.OutputOwners{ 541 Threshold: 1, 542 Addrs: []ids.ShortID{addr1}, 543 }, 544 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 545 Threshold: 1, 546 Addrs: []ids.ShortID{addr0}, 547 }), 548 ) 549 require.NoError(err) 550 addSubnetTx2, err := walletsigner.SignUnsigned(context.Background(), txSigner, utx2) 551 require.NoError(err) 552 553 preferredID := vm.manager.Preferred() 554 preferred, err := vm.manager.GetBlock(preferredID) 555 require.NoError(err) 556 preferredChainTime := preferred.Timestamp() 557 preferredHeight := preferred.Height() 558 559 statelessStandardBlk, err := block.NewBanffStandardBlock( 560 preferredChainTime, 561 preferredID, 562 preferredHeight+1, 563 []*txs.Tx{addSubnetTx0}, 564 ) 565 require.NoError(err) 566 addSubnetBlk0 := vm.manager.NewBlock(statelessStandardBlk) 567 568 statelessStandardBlk, err = block.NewBanffStandardBlock( 569 preferredChainTime, 570 preferredID, 571 preferredHeight+1, 572 []*txs.Tx{addSubnetTx1}, 573 ) 574 require.NoError(err) 575 addSubnetBlk1 := vm.manager.NewBlock(statelessStandardBlk) 576 577 statelessStandardBlk, err = block.NewBanffStandardBlock( 578 preferredChainTime, 579 addSubnetBlk1.ID(), 580 preferredHeight+2, 581 []*txs.Tx{addSubnetTx2}, 582 ) 583 require.NoError(err) 584 addSubnetBlk2 := vm.manager.NewBlock(statelessStandardBlk) 585 586 _, err = vm.ParseBlock(context.Background(), addSubnetBlk0.Bytes()) 587 require.NoError(err) 588 589 _, err = vm.ParseBlock(context.Background(), addSubnetBlk1.Bytes()) 590 require.NoError(err) 591 592 _, err = vm.ParseBlock(context.Background(), addSubnetBlk2.Bytes()) 593 require.NoError(err) 594 595 require.NoError(addSubnetBlk0.Verify(context.Background())) 596 require.NoError(addSubnetBlk0.Accept(context.Background())) 597 598 // Doesn't matter what verify returns as long as it's not panicking. 599 _ = addSubnetBlk2.Verify(context.Background()) 600 } 601 602 func TestRejectedStateRegressionInvalidValidatorTimestamp(t *testing.T) { 603 require := require.New(t) 604 605 vm, factory, baseDB, mutableSharedMemory := defaultVM(t, cortina) 606 vm.ctx.Lock.Lock() 607 defer vm.ctx.Lock.Unlock() 608 609 nodeID := ids.GenerateTestNodeID() 610 newValidatorStartTime := vm.clock.Time().Add(executor.SyncBound).Add(1 * time.Second) 611 newValidatorEndTime := newValidatorStartTime.Add(defaultMinStakingDuration) 612 613 // Create the tx to add a new validator 614 builder, txSigner := factory.NewWallet(keys[0]) 615 utx, err := builder.NewAddValidatorTx( 616 &txs.Validator{ 617 NodeID: nodeID, 618 Start: uint64(newValidatorStartTime.Unix()), 619 End: uint64(newValidatorEndTime.Unix()), 620 Wght: vm.MinValidatorStake, 621 }, 622 &secp256k1fx.OutputOwners{ 623 Threshold: 1, 624 Addrs: []ids.ShortID{ids.GenerateTestShortID()}, 625 }, 626 reward.PercentDenominator, 627 ) 628 require.NoError(err) 629 addValidatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, utx) 630 require.NoError(err) 631 632 // Create the standard block to add the new validator 633 preferredID := vm.manager.Preferred() 634 preferred, err := vm.manager.GetBlock(preferredID) 635 require.NoError(err) 636 preferredChainTime := preferred.Timestamp() 637 preferredHeight := preferred.Height() 638 639 statelessBlk, err := block.NewBanffStandardBlock( 640 preferredChainTime, 641 preferredID, 642 preferredHeight+1, 643 []*txs.Tx{addValidatorTx}, 644 ) 645 require.NoError(err) 646 647 addValidatorStandardBlk := vm.manager.NewBlock(statelessBlk) 648 require.NoError(addValidatorStandardBlk.Verify(context.Background())) 649 650 // Verify that the new validator now in pending validator set 651 { 652 onAccept, found := vm.manager.GetState(addValidatorStandardBlk.ID()) 653 require.True(found) 654 655 _, err := onAccept.GetPendingValidator(constants.PrimaryNetworkID, nodeID) 656 require.NoError(err) 657 } 658 659 // Create the UTXO that will be added to shared memory 660 utxo := &avax.UTXO{ 661 UTXOID: avax.UTXOID{ 662 TxID: ids.GenerateTestID(), 663 }, 664 Asset: avax.Asset{ 665 ID: vm.ctx.AVAXAssetID, 666 }, 667 Out: &secp256k1fx.TransferOutput{ 668 Amt: vm.StaticFeeConfig.TxFee, 669 OutputOwners: secp256k1fx.OutputOwners{}, 670 }, 671 } 672 673 // Create the import tx that will fail verification 674 unsignedImportTx := &txs.ImportTx{ 675 BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ 676 NetworkID: vm.ctx.NetworkID, 677 BlockchainID: vm.ctx.ChainID, 678 }}, 679 SourceChain: vm.ctx.XChainID, 680 ImportedInputs: []*avax.TransferableInput{ 681 { 682 UTXOID: utxo.UTXOID, 683 Asset: utxo.Asset, 684 In: &secp256k1fx.TransferInput{ 685 Amt: vm.StaticFeeConfig.TxFee, 686 }, 687 }, 688 }, 689 } 690 signedImportTx := &txs.Tx{Unsigned: unsignedImportTx} 691 require.NoError(signedImportTx.Sign(txs.Codec, [][]*secp256k1.PrivateKey{ 692 {}, // There is one input, with no required signers 693 })) 694 695 // Create the standard block that will fail verification, and then be 696 // re-verified. 697 preferredChainTime = addValidatorStandardBlk.Timestamp() 698 preferredID = addValidatorStandardBlk.ID() 699 preferredHeight = addValidatorStandardBlk.Height() 700 701 statelessImportBlk, err := block.NewBanffStandardBlock( 702 preferredChainTime, 703 preferredID, 704 preferredHeight+1, 705 []*txs.Tx{signedImportTx}, 706 ) 707 require.NoError(err) 708 709 importBlk := vm.manager.NewBlock(statelessImportBlk) 710 711 // Because the shared memory UTXO hasn't been populated, this block is 712 // currently invalid. 713 err = importBlk.Verify(context.Background()) 714 require.ErrorIs(err, database.ErrNotFound) 715 716 // Because we no longer ever reject a block in verification, the status 717 // should remain as processing. 718 importBlkStatus := importBlk.Status() 719 require.Equal(choices.Processing, importBlkStatus) 720 721 // Populate the shared memory UTXO. 722 m := atomic.NewMemory(prefixdb.New([]byte{5}, baseDB)) 723 724 mutableSharedMemory.SharedMemory = m.NewSharedMemory(vm.ctx.ChainID) 725 peerSharedMemory := m.NewSharedMemory(vm.ctx.XChainID) 726 727 utxoBytes, err := txs.Codec.Marshal(txs.CodecVersion, utxo) 728 require.NoError(err) 729 730 inputID := utxo.InputID() 731 require.NoError(peerSharedMemory.Apply( 732 map[ids.ID]*atomic.Requests{ 733 vm.ctx.ChainID: { 734 PutRequests: []*atomic.Element{ 735 { 736 Key: inputID[:], 737 Value: utxoBytes, 738 }, 739 }, 740 }, 741 }, 742 )) 743 744 // Because the shared memory UTXO has now been populated, the block should 745 // pass verification. 746 require.NoError(importBlk.Verify(context.Background())) 747 748 // The status shouldn't have been changed during a successful verification. 749 importBlkStatus = importBlk.Status() 750 require.Equal(choices.Processing, importBlkStatus) 751 752 // Move chain time ahead to bring the new validator from the pending 753 // validator set into the current validator set. 754 vm.clock.Set(newValidatorStartTime) 755 756 // Create the proposal block that should have moved the new validator from 757 // the pending validator set into the current validator set. 758 preferredID = importBlk.ID() 759 preferredHeight = importBlk.Height() 760 761 statelessAdvanceTimeStandardBlk, err := block.NewBanffStandardBlock( 762 newValidatorStartTime, 763 preferredID, 764 preferredHeight+1, 765 nil, 766 ) 767 require.NoError(err) 768 769 advanceTimeStandardBlk := vm.manager.NewBlock(statelessAdvanceTimeStandardBlk) 770 require.NoError(advanceTimeStandardBlk.Verify(context.Background())) 771 772 // Accept all the blocks 773 allBlocks := []snowman.Block{ 774 addValidatorStandardBlk, 775 importBlk, 776 advanceTimeStandardBlk, 777 } 778 for _, blk := range allBlocks { 779 require.NoError(blk.Accept(context.Background())) 780 781 status := blk.Status() 782 require.Equal(choices.Accepted, status) 783 } 784 785 // Force a reload of the state from the database. 786 vm.Config.Validators = validators.NewManager() 787 execCfg, _ := config.GetExecutionConfig(nil) 788 newState, err := state.New( 789 vm.db, 790 nil, 791 prometheus.NewRegistry(), 792 &vm.Config, 793 execCfg, 794 vm.ctx, 795 metrics.Noop, 796 reward.NewCalculator(vm.Config.RewardConfig), 797 ) 798 require.NoError(err) 799 800 // Verify that new validator is now in the current validator set. 801 { 802 _, err := newState.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) 803 require.NoError(err) 804 805 _, err = newState.GetPendingValidator(constants.PrimaryNetworkID, nodeID) 806 require.ErrorIs(err, database.ErrNotFound) 807 808 currentTimestamp := newState.GetTimestamp() 809 require.Equal(newValidatorStartTime.Unix(), currentTimestamp.Unix()) 810 } 811 } 812 813 func TestRejectedStateRegressionInvalidValidatorReward(t *testing.T) { 814 require := require.New(t) 815 816 vm, factory, baseDB, mutableSharedMemory := defaultVM(t, cortina) 817 vm.ctx.Lock.Lock() 818 defer vm.ctx.Lock.Unlock() 819 820 vm.state.SetCurrentSupply(constants.PrimaryNetworkID, defaultRewardConfig.SupplyCap/2) 821 822 newValidatorStartTime0 := vm.clock.Time().Add(executor.SyncBound).Add(1 * time.Second) 823 newValidatorEndTime0 := newValidatorStartTime0.Add(defaultMaxStakingDuration) 824 825 nodeID0 := ids.GenerateTestNodeID() 826 827 // Create the tx to add the first new validator 828 builder, txSigner := factory.NewWallet(keys[0]) 829 utx, err := builder.NewAddValidatorTx( 830 &txs.Validator{ 831 NodeID: nodeID0, 832 Start: uint64(newValidatorStartTime0.Unix()), 833 End: uint64(newValidatorEndTime0.Unix()), 834 Wght: vm.MaxValidatorStake, 835 }, 836 &secp256k1fx.OutputOwners{ 837 Threshold: 1, 838 Addrs: []ids.ShortID{ids.GenerateTestShortID()}, 839 }, 840 reward.PercentDenominator, 841 ) 842 require.NoError(err) 843 addValidatorTx0, err := walletsigner.SignUnsigned(context.Background(), txSigner, utx) 844 require.NoError(err) 845 846 // Create the standard block to add the first new validator 847 preferredID := vm.manager.Preferred() 848 preferred, err := vm.manager.GetBlock(preferredID) 849 require.NoError(err) 850 preferredChainTime := preferred.Timestamp() 851 preferredHeight := preferred.Height() 852 853 statelessAddValidatorStandardBlk0, err := block.NewBanffStandardBlock( 854 preferredChainTime, 855 preferredID, 856 preferredHeight+1, 857 []*txs.Tx{addValidatorTx0}, 858 ) 859 require.NoError(err) 860 861 addValidatorStandardBlk0 := vm.manager.NewBlock(statelessAddValidatorStandardBlk0) 862 require.NoError(addValidatorStandardBlk0.Verify(context.Background())) 863 864 // Verify that first new validator now in pending validator set 865 { 866 onAccept, ok := vm.manager.GetState(addValidatorStandardBlk0.ID()) 867 require.True(ok) 868 869 _, err := onAccept.GetPendingValidator(constants.PrimaryNetworkID, nodeID0) 870 require.NoError(err) 871 } 872 873 // Move chain time to bring the first new validator from the pending 874 // validator set into the current validator set. 875 vm.clock.Set(newValidatorStartTime0) 876 877 // Create the proposal block that moves the first new validator from the 878 // pending validator set into the current validator set. 879 preferredID = addValidatorStandardBlk0.ID() 880 preferredHeight = addValidatorStandardBlk0.Height() 881 882 statelessAdvanceTimeStandardBlk0, err := block.NewBanffStandardBlock( 883 newValidatorStartTime0, 884 preferredID, 885 preferredHeight+1, 886 nil, 887 ) 888 require.NoError(err) 889 890 advanceTimeStandardBlk0 := vm.manager.NewBlock(statelessAdvanceTimeStandardBlk0) 891 require.NoError(advanceTimeStandardBlk0.Verify(context.Background())) 892 893 // Verify that the first new validator is now in the current validator set. 894 { 895 onAccept, ok := vm.manager.GetState(advanceTimeStandardBlk0.ID()) 896 require.True(ok) 897 898 _, err := onAccept.GetCurrentValidator(constants.PrimaryNetworkID, nodeID0) 899 require.NoError(err) 900 901 _, err = onAccept.GetPendingValidator(constants.PrimaryNetworkID, nodeID0) 902 require.ErrorIs(err, database.ErrNotFound) 903 904 currentTimestamp := onAccept.GetTimestamp() 905 require.Equal(newValidatorStartTime0.Unix(), currentTimestamp.Unix()) 906 } 907 908 // Create the UTXO that will be added to shared memory 909 utxo := &avax.UTXO{ 910 UTXOID: avax.UTXOID{ 911 TxID: ids.GenerateTestID(), 912 }, 913 Asset: avax.Asset{ 914 ID: vm.ctx.AVAXAssetID, 915 }, 916 Out: &secp256k1fx.TransferOutput{ 917 Amt: vm.StaticFeeConfig.TxFee, 918 OutputOwners: secp256k1fx.OutputOwners{}, 919 }, 920 } 921 922 // Create the import tx that will fail verification 923 unsignedImportTx := &txs.ImportTx{ 924 BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ 925 NetworkID: vm.ctx.NetworkID, 926 BlockchainID: vm.ctx.ChainID, 927 }}, 928 SourceChain: vm.ctx.XChainID, 929 ImportedInputs: []*avax.TransferableInput{ 930 { 931 UTXOID: utxo.UTXOID, 932 Asset: utxo.Asset, 933 In: &secp256k1fx.TransferInput{ 934 Amt: vm.StaticFeeConfig.TxFee, 935 }, 936 }, 937 }, 938 } 939 signedImportTx := &txs.Tx{Unsigned: unsignedImportTx} 940 require.NoError(signedImportTx.Sign(txs.Codec, [][]*secp256k1.PrivateKey{ 941 {}, // There is one input, with no required signers 942 })) 943 944 // Create the standard block that will fail verification, and then be 945 // re-verified. 946 preferredChainTime = advanceTimeStandardBlk0.Timestamp() 947 preferredID = advanceTimeStandardBlk0.ID() 948 preferredHeight = advanceTimeStandardBlk0.Height() 949 950 statelessImportBlk, err := block.NewBanffStandardBlock( 951 preferredChainTime, 952 preferredID, 953 preferredHeight+1, 954 []*txs.Tx{signedImportTx}, 955 ) 956 require.NoError(err) 957 958 importBlk := vm.manager.NewBlock(statelessImportBlk) 959 // Because the shared memory UTXO hasn't been populated, this block is 960 // currently invalid. 961 err = importBlk.Verify(context.Background()) 962 require.ErrorIs(err, database.ErrNotFound) 963 964 // Because we no longer ever reject a block in verification, the status 965 // should remain as processing. 966 importBlkStatus := importBlk.Status() 967 require.Equal(choices.Processing, importBlkStatus) 968 969 // Populate the shared memory UTXO. 970 m := atomic.NewMemory(prefixdb.New([]byte{5}, baseDB)) 971 972 mutableSharedMemory.SharedMemory = m.NewSharedMemory(vm.ctx.ChainID) 973 peerSharedMemory := m.NewSharedMemory(vm.ctx.XChainID) 974 975 utxoBytes, err := txs.Codec.Marshal(txs.CodecVersion, utxo) 976 require.NoError(err) 977 978 inputID := utxo.InputID() 979 require.NoError(peerSharedMemory.Apply( 980 map[ids.ID]*atomic.Requests{ 981 vm.ctx.ChainID: { 982 PutRequests: []*atomic.Element{ 983 { 984 Key: inputID[:], 985 Value: utxoBytes, 986 }, 987 }, 988 }, 989 }, 990 )) 991 992 // Because the shared memory UTXO has now been populated, the block should 993 // pass verification. 994 require.NoError(importBlk.Verify(context.Background())) 995 996 // The status shouldn't have been changed during a successful verification. 997 importBlkStatus = importBlk.Status() 998 require.Equal(choices.Processing, importBlkStatus) 999 1000 newValidatorStartTime1 := newValidatorStartTime0.Add(executor.SyncBound).Add(1 * time.Second) 1001 newValidatorEndTime1 := newValidatorStartTime1.Add(defaultMaxStakingDuration) 1002 1003 nodeID1 := ids.GenerateTestNodeID() 1004 1005 // Create the tx to add the second new validator 1006 builder, txSigner = factory.NewWallet(keys[1]) 1007 utx1, err := builder.NewAddValidatorTx( 1008 &txs.Validator{ 1009 NodeID: nodeID1, 1010 Start: uint64(newValidatorStartTime1.Unix()), 1011 End: uint64(newValidatorEndTime1.Unix()), 1012 Wght: vm.MaxValidatorStake, 1013 }, 1014 &secp256k1fx.OutputOwners{ 1015 Threshold: 1, 1016 Addrs: []ids.ShortID{ids.GenerateTestShortID()}, 1017 }, 1018 reward.PercentDenominator, 1019 ) 1020 require.NoError(err) 1021 addValidatorTx1, err := walletsigner.SignUnsigned(context.Background(), txSigner, utx1) 1022 require.NoError(err) 1023 1024 // Create the standard block to add the second new validator 1025 preferredChainTime = importBlk.Timestamp() 1026 preferredID = importBlk.ID() 1027 preferredHeight = importBlk.Height() 1028 1029 statelessAddValidatorStandardBlk1, err := block.NewBanffStandardBlock( 1030 preferredChainTime, 1031 preferredID, 1032 preferredHeight+1, 1033 []*txs.Tx{addValidatorTx1}, 1034 ) 1035 require.NoError(err) 1036 1037 addValidatorStandardBlk1 := vm.manager.NewBlock(statelessAddValidatorStandardBlk1) 1038 1039 require.NoError(addValidatorStandardBlk1.Verify(context.Background())) 1040 1041 // Verify that the second new validator now in pending validator set 1042 { 1043 onAccept, ok := vm.manager.GetState(addValidatorStandardBlk1.ID()) 1044 require.True(ok) 1045 1046 _, err := onAccept.GetPendingValidator(constants.PrimaryNetworkID, nodeID1) 1047 require.NoError(err) 1048 } 1049 1050 // Move chain time to bring the second new validator from the pending 1051 // validator set into the current validator set. 1052 vm.clock.Set(newValidatorStartTime1) 1053 1054 // Create the proposal block that moves the second new validator from the 1055 // pending validator set into the current validator set. 1056 preferredID = addValidatorStandardBlk1.ID() 1057 preferredHeight = addValidatorStandardBlk1.Height() 1058 1059 statelessAdvanceTimeStandardBlk1, err := block.NewBanffStandardBlock( 1060 newValidatorStartTime1, 1061 preferredID, 1062 preferredHeight+1, 1063 nil, 1064 ) 1065 require.NoError(err) 1066 1067 advanceTimeStandardBlk1 := vm.manager.NewBlock(statelessAdvanceTimeStandardBlk1) 1068 require.NoError(advanceTimeStandardBlk1.Verify(context.Background())) 1069 1070 // Verify that the second new validator is now in the current validator set. 1071 { 1072 onAccept, ok := vm.manager.GetState(advanceTimeStandardBlk1.ID()) 1073 require.True(ok) 1074 1075 _, err := onAccept.GetCurrentValidator(constants.PrimaryNetworkID, nodeID1) 1076 require.NoError(err) 1077 1078 _, err = onAccept.GetPendingValidator(constants.PrimaryNetworkID, nodeID1) 1079 require.ErrorIs(err, database.ErrNotFound) 1080 1081 currentTimestamp := onAccept.GetTimestamp() 1082 require.Equal(newValidatorStartTime1.Unix(), currentTimestamp.Unix()) 1083 } 1084 1085 // Accept all the blocks 1086 allBlocks := []snowman.Block{ 1087 addValidatorStandardBlk0, 1088 advanceTimeStandardBlk0, 1089 importBlk, 1090 addValidatorStandardBlk1, 1091 advanceTimeStandardBlk1, 1092 } 1093 for _, blk := range allBlocks { 1094 require.NoError(blk.Accept(context.Background())) 1095 1096 status := blk.Status() 1097 require.Equal(choices.Accepted, status) 1098 } 1099 1100 // Force a reload of the state from the database. 1101 vm.Config.Validators = validators.NewManager() 1102 execCfg, _ := config.GetExecutionConfig(nil) 1103 newState, err := state.New( 1104 vm.db, 1105 nil, 1106 prometheus.NewRegistry(), 1107 &vm.Config, 1108 execCfg, 1109 vm.ctx, 1110 metrics.Noop, 1111 reward.NewCalculator(vm.Config.RewardConfig), 1112 ) 1113 require.NoError(err) 1114 1115 // Verify that validators are in the current validator set with the correct 1116 // reward calculated. 1117 { 1118 staker0, err := newState.GetCurrentValidator(constants.PrimaryNetworkID, nodeID0) 1119 require.NoError(err) 1120 require.Equal(uint64(60000000), staker0.PotentialReward) 1121 1122 staker1, err := newState.GetCurrentValidator(constants.PrimaryNetworkID, nodeID1) 1123 require.NoError(err) 1124 require.Equal(uint64(59999999), staker1.PotentialReward) 1125 1126 _, err = newState.GetPendingValidator(constants.PrimaryNetworkID, nodeID0) 1127 require.ErrorIs(err, database.ErrNotFound) 1128 1129 _, err = newState.GetPendingValidator(constants.PrimaryNetworkID, nodeID1) 1130 require.ErrorIs(err, database.ErrNotFound) 1131 1132 currentTimestamp := newState.GetTimestamp() 1133 require.Equal(newValidatorStartTime1.Unix(), currentTimestamp.Unix()) 1134 } 1135 } 1136 1137 func TestValidatorSetAtCacheOverwriteRegression(t *testing.T) { 1138 require := require.New(t) 1139 1140 vm, factory, _, _ := defaultVM(t, cortina) 1141 vm.ctx.Lock.Lock() 1142 defer vm.ctx.Lock.Unlock() 1143 1144 currentHeight, err := vm.GetCurrentHeight(context.Background()) 1145 require.NoError(err) 1146 require.Equal(uint64(1), currentHeight) 1147 1148 expectedValidators1 := map[ids.NodeID]uint64{ 1149 genesisNodeIDs[0]: defaultWeight, 1150 genesisNodeIDs[1]: defaultWeight, 1151 genesisNodeIDs[2]: defaultWeight, 1152 genesisNodeIDs[3]: defaultWeight, 1153 genesisNodeIDs[4]: defaultWeight, 1154 } 1155 validators, err := vm.GetValidatorSet(context.Background(), 1, constants.PrimaryNetworkID) 1156 require.NoError(err) 1157 for nodeID, weight := range expectedValidators1 { 1158 require.Equal(weight, validators[nodeID].Weight) 1159 } 1160 1161 newValidatorStartTime0 := vm.clock.Time().Add(executor.SyncBound).Add(1 * time.Second) 1162 newValidatorEndTime0 := newValidatorStartTime0.Add(defaultMaxStakingDuration) 1163 1164 extraNodeID := ids.GenerateTestNodeID() 1165 1166 // Create the tx to add the first new validator 1167 builder, txSigner := factory.NewWallet(keys[0]) 1168 utx, err := builder.NewAddValidatorTx( 1169 &txs.Validator{ 1170 NodeID: extraNodeID, 1171 Start: uint64(newValidatorStartTime0.Unix()), 1172 End: uint64(newValidatorEndTime0.Unix()), 1173 Wght: vm.MaxValidatorStake, 1174 }, 1175 &secp256k1fx.OutputOwners{ 1176 Threshold: 1, 1177 Addrs: []ids.ShortID{ids.GenerateTestShortID()}, 1178 }, 1179 reward.PercentDenominator, 1180 ) 1181 require.NoError(err) 1182 addValidatorTx0, err := walletsigner.SignUnsigned(context.Background(), txSigner, utx) 1183 require.NoError(err) 1184 1185 // Create the standard block to add the first new validator 1186 preferredID := vm.manager.Preferred() 1187 preferred, err := vm.manager.GetBlock(preferredID) 1188 require.NoError(err) 1189 preferredChainTime := preferred.Timestamp() 1190 preferredHeight := preferred.Height() 1191 1192 statelessStandardBlk, err := block.NewBanffStandardBlock( 1193 preferredChainTime, 1194 preferredID, 1195 preferredHeight+1, 1196 []*txs.Tx{addValidatorTx0}, 1197 ) 1198 require.NoError(err) 1199 addValidatorProposalBlk0 := vm.manager.NewBlock(statelessStandardBlk) 1200 require.NoError(addValidatorProposalBlk0.Verify(context.Background())) 1201 require.NoError(addValidatorProposalBlk0.Accept(context.Background())) 1202 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1203 1204 currentHeight, err = vm.GetCurrentHeight(context.Background()) 1205 require.NoError(err) 1206 require.Equal(uint64(2), currentHeight) 1207 1208 for i := uint64(1); i <= 2; i++ { 1209 validators, err = vm.GetValidatorSet(context.Background(), i, constants.PrimaryNetworkID) 1210 require.NoError(err) 1211 for nodeID, weight := range expectedValidators1 { 1212 require.Equal(weight, validators[nodeID].Weight) 1213 } 1214 } 1215 1216 // Advance chain time to move the first new validator from the pending 1217 // validator set into the current validator set. 1218 vm.clock.Set(newValidatorStartTime0) 1219 1220 // Create the standard block that moves the first new validator from the 1221 // pending validator set into the current validator set. 1222 preferredID = vm.manager.Preferred() 1223 preferred, err = vm.manager.GetBlock(preferredID) 1224 require.NoError(err) 1225 preferredID = preferred.ID() 1226 preferredHeight = preferred.Height() 1227 1228 statelessStandardBlk, err = block.NewBanffStandardBlock( 1229 newValidatorStartTime0, 1230 preferredID, 1231 preferredHeight+1, 1232 nil, 1233 ) 1234 require.NoError(err) 1235 advanceTimeProposalBlk0 := vm.manager.NewBlock(statelessStandardBlk) 1236 require.NoError(advanceTimeProposalBlk0.Verify(context.Background())) 1237 require.NoError(advanceTimeProposalBlk0.Accept(context.Background())) 1238 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1239 1240 currentHeight, err = vm.GetCurrentHeight(context.Background()) 1241 require.NoError(err) 1242 require.Equal(uint64(3), currentHeight) 1243 1244 for i := uint64(1); i <= 2; i++ { 1245 validators, err = vm.GetValidatorSet(context.Background(), i, constants.PrimaryNetworkID) 1246 require.NoError(err) 1247 for nodeID, weight := range expectedValidators1 { 1248 require.Equal(weight, validators[nodeID].Weight) 1249 } 1250 } 1251 1252 expectedValidators2 := map[ids.NodeID]uint64{ 1253 genesisNodeIDs[0]: defaultWeight, 1254 genesisNodeIDs[1]: defaultWeight, 1255 genesisNodeIDs[2]: defaultWeight, 1256 genesisNodeIDs[3]: defaultWeight, 1257 genesisNodeIDs[4]: defaultWeight, 1258 extraNodeID: vm.MaxValidatorStake, 1259 } 1260 validators, err = vm.GetValidatorSet(context.Background(), 3, constants.PrimaryNetworkID) 1261 require.NoError(err) 1262 for nodeID, weight := range expectedValidators2 { 1263 require.Equal(weight, validators[nodeID].Weight) 1264 } 1265 } 1266 1267 func TestAddDelegatorTxAddBeforeRemove(t *testing.T) { 1268 require := require.New(t) 1269 1270 validatorStartTime := latestForkTime.Add(executor.SyncBound).Add(1 * time.Second) 1271 validatorEndTime := validatorStartTime.Add(360 * 24 * time.Hour) 1272 validatorStake := defaultMaxValidatorStake / 5 1273 1274 delegator1StartTime := validatorStartTime 1275 delegator1EndTime := delegator1StartTime.Add(3 * defaultMinStakingDuration) 1276 delegator1Stake := defaultMaxValidatorStake - validatorStake 1277 1278 delegator2StartTime := delegator1EndTime 1279 delegator2EndTime := delegator2StartTime.Add(3 * defaultMinStakingDuration) 1280 delegator2Stake := defaultMaxValidatorStake - validatorStake 1281 1282 vm, factory, _, _ := defaultVM(t, cortina) 1283 vm.ctx.Lock.Lock() 1284 defer vm.ctx.Lock.Unlock() 1285 1286 key, err := secp256k1.NewPrivateKey() 1287 require.NoError(err) 1288 1289 id := key.Address() 1290 nodeID := ids.GenerateTestNodeID() 1291 changeAddr := keys[0].PublicKey().Address() 1292 1293 // create valid tx 1294 builder, txSigner := factory.NewWallet(keys[0], keys[1]) 1295 utx, err := builder.NewAddValidatorTx( 1296 &txs.Validator{ 1297 NodeID: nodeID, 1298 Start: uint64(validatorStartTime.Unix()), 1299 End: uint64(validatorEndTime.Unix()), 1300 Wght: validatorStake, 1301 }, 1302 &secp256k1fx.OutputOwners{ 1303 Threshold: 1, 1304 Addrs: []ids.ShortID{id}, 1305 }, 1306 reward.PercentDenominator, 1307 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1308 Threshold: 1, 1309 Addrs: []ids.ShortID{changeAddr}, 1310 }), 1311 ) 1312 require.NoError(err) 1313 addValidatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, utx) 1314 require.NoError(err) 1315 1316 // issue the add validator tx 1317 vm.ctx.Lock.Unlock() 1318 require.NoError(vm.issueTxFromRPC(addValidatorTx)) 1319 vm.ctx.Lock.Lock() 1320 1321 // trigger block creation for the validator tx 1322 addValidatorBlock, err := vm.Builder.BuildBlock(context.Background()) 1323 require.NoError(err) 1324 require.NoError(addValidatorBlock.Verify(context.Background())) 1325 require.NoError(addValidatorBlock.Accept(context.Background())) 1326 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1327 1328 // create valid tx 1329 uDelTx, err := builder.NewAddDelegatorTx( 1330 &txs.Validator{ 1331 NodeID: nodeID, 1332 Start: uint64(delegator1StartTime.Unix()), 1333 End: uint64(delegator1EndTime.Unix()), 1334 Wght: delegator1Stake, 1335 }, 1336 &secp256k1fx.OutputOwners{ 1337 Threshold: 1, 1338 Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, 1339 }, 1340 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1341 Threshold: 1, 1342 Addrs: []ids.ShortID{changeAddr}, 1343 }), 1344 ) 1345 require.NoError(err) 1346 addFirstDelegatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uDelTx) 1347 require.NoError(err) 1348 1349 // issue the first add delegator tx 1350 vm.ctx.Lock.Unlock() 1351 require.NoError(vm.issueTxFromRPC(addFirstDelegatorTx)) 1352 vm.ctx.Lock.Lock() 1353 1354 // trigger block creation for the first add delegator tx 1355 addFirstDelegatorBlock, err := vm.Builder.BuildBlock(context.Background()) 1356 require.NoError(err) 1357 require.NoError(addFirstDelegatorBlock.Verify(context.Background())) 1358 require.NoError(addFirstDelegatorBlock.Accept(context.Background())) 1359 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1360 1361 // create valid tx 1362 uDelTx, err = builder.NewAddDelegatorTx( 1363 &txs.Validator{ 1364 NodeID: nodeID, 1365 Start: uint64(delegator2StartTime.Unix()), 1366 End: uint64(delegator2EndTime.Unix()), 1367 Wght: delegator2Stake, 1368 }, 1369 &secp256k1fx.OutputOwners{ 1370 Threshold: 1, 1371 Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, 1372 }, 1373 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1374 Threshold: 1, 1375 Addrs: []ids.ShortID{changeAddr}, 1376 }), 1377 ) 1378 require.NoError(err) 1379 addSecondDelegatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uDelTx) 1380 require.NoError(err) 1381 1382 // attempting to issue the second add delegator tx should fail because the 1383 // total stake weight would go over the limit. 1384 vm.ctx.Lock.Unlock() 1385 err = vm.issueTxFromRPC(addSecondDelegatorTx) 1386 require.ErrorIs(err, executor.ErrOverDelegated) 1387 vm.ctx.Lock.Lock() 1388 } 1389 1390 func TestRemovePermissionedValidatorDuringPendingToCurrentTransitionNotTracked(t *testing.T) { 1391 require := require.New(t) 1392 1393 validatorStartTime := latestForkTime.Add(executor.SyncBound).Add(1 * time.Second) 1394 validatorEndTime := validatorStartTime.Add(360 * 24 * time.Hour) 1395 1396 vm, factory, _, _ := defaultVM(t, cortina) 1397 vm.ctx.Lock.Lock() 1398 defer vm.ctx.Lock.Unlock() 1399 1400 key, err := secp256k1.NewPrivateKey() 1401 require.NoError(err) 1402 1403 id := key.Address() 1404 nodeID := ids.GenerateTestNodeID() 1405 changeAddr := keys[0].PublicKey().Address() 1406 1407 builder, txSigner := factory.NewWallet(keys[0], keys[1]) 1408 utx, err := builder.NewAddValidatorTx( 1409 &txs.Validator{ 1410 NodeID: nodeID, 1411 Start: uint64(validatorStartTime.Unix()), 1412 End: uint64(validatorEndTime.Unix()), 1413 Wght: defaultMaxValidatorStake, 1414 }, 1415 &secp256k1fx.OutputOwners{ 1416 Threshold: 1, 1417 Addrs: []ids.ShortID{id}, 1418 }, 1419 reward.PercentDenominator, 1420 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1421 Threshold: 1, 1422 Addrs: []ids.ShortID{changeAddr}, 1423 }), 1424 ) 1425 require.NoError(err) 1426 addValidatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, utx) 1427 require.NoError(err) 1428 1429 vm.ctx.Lock.Unlock() 1430 require.NoError(vm.issueTxFromRPC(addValidatorTx)) 1431 vm.ctx.Lock.Lock() 1432 1433 // trigger block creation for the validator tx 1434 addValidatorBlock, err := vm.Builder.BuildBlock(context.Background()) 1435 require.NoError(err) 1436 require.NoError(addValidatorBlock.Verify(context.Background())) 1437 require.NoError(addValidatorBlock.Accept(context.Background())) 1438 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1439 1440 uSubnetTx, err := builder.NewCreateSubnetTx( 1441 &secp256k1fx.OutputOwners{ 1442 Threshold: 1, 1443 Addrs: []ids.ShortID{changeAddr}, 1444 }, 1445 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1446 Threshold: 1, 1447 Addrs: []ids.ShortID{changeAddr}, 1448 }), 1449 ) 1450 require.NoError(err) 1451 createSubnetTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uSubnetTx) 1452 require.NoError(err) 1453 1454 vm.ctx.Lock.Unlock() 1455 require.NoError(vm.issueTxFromRPC(createSubnetTx)) 1456 vm.ctx.Lock.Lock() 1457 1458 // trigger block creation for the subnet tx 1459 createSubnetBlock, err := vm.Builder.BuildBlock(context.Background()) 1460 require.NoError(err) 1461 require.NoError(createSubnetBlock.Verify(context.Background())) 1462 require.NoError(createSubnetBlock.Accept(context.Background())) 1463 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1464 1465 uSubnetValTx, err := builder.NewAddSubnetValidatorTx( 1466 &txs.SubnetValidator{ 1467 Validator: txs.Validator{ 1468 NodeID: nodeID, 1469 Start: uint64(validatorStartTime.Unix()), 1470 End: uint64(validatorEndTime.Unix()), 1471 Wght: defaultMaxValidatorStake, 1472 }, 1473 Subnet: createSubnetTx.ID(), 1474 }, 1475 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1476 Threshold: 1, 1477 Addrs: []ids.ShortID{changeAddr}, 1478 }), 1479 ) 1480 require.NoError(err) 1481 addSubnetValidatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uSubnetValTx) 1482 require.NoError(err) 1483 1484 vm.ctx.Lock.Unlock() 1485 require.NoError(vm.issueTxFromRPC(addSubnetValidatorTx)) 1486 vm.ctx.Lock.Lock() 1487 1488 // trigger block creation for the validator tx 1489 addSubnetValidatorBlock, err := vm.Builder.BuildBlock(context.Background()) 1490 require.NoError(err) 1491 require.NoError(addSubnetValidatorBlock.Verify(context.Background())) 1492 require.NoError(addSubnetValidatorBlock.Accept(context.Background())) 1493 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1494 1495 emptyValidatorSet, err := vm.GetValidatorSet( 1496 context.Background(), 1497 addSubnetValidatorBlock.Height(), 1498 createSubnetTx.ID(), 1499 ) 1500 require.NoError(err) 1501 require.Empty(emptyValidatorSet) 1502 1503 uRemoveSubnetValTx, err := builder.NewRemoveSubnetValidatorTx( 1504 nodeID, 1505 createSubnetTx.ID(), 1506 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1507 Threshold: 1, 1508 Addrs: []ids.ShortID{changeAddr}, 1509 }), 1510 ) 1511 require.NoError(err) 1512 removeSubnetValidatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uRemoveSubnetValTx) 1513 require.NoError(err) 1514 1515 // Set the clock so that the validator will be moved from the pending 1516 // validator set into the current validator set. 1517 vm.clock.Set(validatorStartTime) 1518 1519 vm.ctx.Lock.Unlock() 1520 require.NoError(vm.issueTxFromRPC(removeSubnetValidatorTx)) 1521 vm.ctx.Lock.Lock() 1522 1523 // trigger block creation for the validator tx 1524 removeSubnetValidatorBlock, err := vm.Builder.BuildBlock(context.Background()) 1525 require.NoError(err) 1526 require.NoError(removeSubnetValidatorBlock.Verify(context.Background())) 1527 require.NoError(removeSubnetValidatorBlock.Accept(context.Background())) 1528 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1529 1530 emptyValidatorSet, err = vm.GetValidatorSet( 1531 context.Background(), 1532 addSubnetValidatorBlock.Height(), 1533 createSubnetTx.ID(), 1534 ) 1535 require.NoError(err) 1536 require.Empty(emptyValidatorSet) 1537 } 1538 1539 func TestRemovePermissionedValidatorDuringPendingToCurrentTransitionTracked(t *testing.T) { 1540 require := require.New(t) 1541 1542 validatorStartTime := latestForkTime.Add(executor.SyncBound).Add(1 * time.Second) 1543 validatorEndTime := validatorStartTime.Add(360 * 24 * time.Hour) 1544 1545 vm, factory, _, _ := defaultVM(t, cortina) 1546 vm.ctx.Lock.Lock() 1547 defer vm.ctx.Lock.Unlock() 1548 1549 key, err := secp256k1.NewPrivateKey() 1550 require.NoError(err) 1551 1552 id := key.PublicKey().Address() 1553 nodeID := ids.GenerateTestNodeID() 1554 changeAddr := keys[0].PublicKey().Address() 1555 1556 builder, txSigner := factory.NewWallet(keys[0], keys[1]) 1557 utx, err := builder.NewAddValidatorTx( 1558 &txs.Validator{ 1559 NodeID: nodeID, 1560 Start: uint64(validatorStartTime.Unix()), 1561 End: uint64(validatorEndTime.Unix()), 1562 Wght: defaultMaxValidatorStake, 1563 }, 1564 &secp256k1fx.OutputOwners{ 1565 Threshold: 1, 1566 Addrs: []ids.ShortID{id}, 1567 }, 1568 reward.PercentDenominator, 1569 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1570 Threshold: 1, 1571 Addrs: []ids.ShortID{changeAddr}, 1572 }), 1573 ) 1574 require.NoError(err) 1575 addValidatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, utx) 1576 require.NoError(err) 1577 1578 vm.ctx.Lock.Unlock() 1579 require.NoError(vm.issueTxFromRPC(addValidatorTx)) 1580 vm.ctx.Lock.Lock() 1581 1582 // trigger block creation for the validator tx 1583 addValidatorBlock, err := vm.Builder.BuildBlock(context.Background()) 1584 require.NoError(err) 1585 require.NoError(addValidatorBlock.Verify(context.Background())) 1586 require.NoError(addValidatorBlock.Accept(context.Background())) 1587 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1588 1589 uCreateSubnetTx, err := builder.NewCreateSubnetTx( 1590 &secp256k1fx.OutputOwners{ 1591 Threshold: 1, 1592 Addrs: []ids.ShortID{changeAddr}, 1593 }, 1594 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1595 Threshold: 1, 1596 Addrs: []ids.ShortID{changeAddr}, 1597 }), 1598 ) 1599 require.NoError(err) 1600 createSubnetTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uCreateSubnetTx) 1601 require.NoError(err) 1602 1603 vm.ctx.Lock.Unlock() 1604 require.NoError(vm.issueTxFromRPC(createSubnetTx)) 1605 vm.ctx.Lock.Lock() 1606 1607 // trigger block creation for the subnet tx 1608 createSubnetBlock, err := vm.Builder.BuildBlock(context.Background()) 1609 require.NoError(err) 1610 require.NoError(createSubnetBlock.Verify(context.Background())) 1611 require.NoError(createSubnetBlock.Accept(context.Background())) 1612 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1613 1614 uAddSubnetValTx, err := builder.NewAddSubnetValidatorTx( 1615 &txs.SubnetValidator{ 1616 Validator: txs.Validator{ 1617 NodeID: nodeID, 1618 Start: uint64(validatorStartTime.Unix()), 1619 End: uint64(validatorEndTime.Unix()), 1620 Wght: defaultMaxValidatorStake, 1621 }, 1622 Subnet: createSubnetTx.ID(), 1623 }, 1624 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1625 Threshold: 1, 1626 Addrs: []ids.ShortID{changeAddr}, 1627 }), 1628 ) 1629 require.NoError(err) 1630 addSubnetValidatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uAddSubnetValTx) 1631 require.NoError(err) 1632 1633 vm.ctx.Lock.Unlock() 1634 require.NoError(vm.issueTxFromRPC(addSubnetValidatorTx)) 1635 vm.ctx.Lock.Lock() 1636 1637 // trigger block creation for the validator tx 1638 addSubnetValidatorBlock, err := vm.Builder.BuildBlock(context.Background()) 1639 require.NoError(err) 1640 require.NoError(addSubnetValidatorBlock.Verify(context.Background())) 1641 require.NoError(addSubnetValidatorBlock.Accept(context.Background())) 1642 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1643 1644 uRemoveSubnetValTx, err := builder.NewRemoveSubnetValidatorTx( 1645 nodeID, 1646 createSubnetTx.ID(), 1647 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1648 Threshold: 1, 1649 Addrs: []ids.ShortID{changeAddr}, 1650 }), 1651 ) 1652 require.NoError(err) 1653 removeSubnetValidatorTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uRemoveSubnetValTx) 1654 require.NoError(err) 1655 1656 // Set the clock so that the validator will be moved from the pending 1657 // validator set into the current validator set. 1658 vm.clock.Set(validatorStartTime) 1659 1660 vm.ctx.Lock.Unlock() 1661 require.NoError(vm.issueTxFromRPC(removeSubnetValidatorTx)) 1662 vm.ctx.Lock.Lock() 1663 1664 // trigger block creation for the validator tx 1665 removeSubnetValidatorBlock, err := vm.Builder.BuildBlock(context.Background()) 1666 require.NoError(err) 1667 require.NoError(removeSubnetValidatorBlock.Verify(context.Background())) 1668 require.NoError(removeSubnetValidatorBlock.Accept(context.Background())) 1669 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1670 } 1671 1672 // GetValidatorSet must return the BLS keys for a given validator correctly when 1673 // queried at a previous height, even in case it has currently expired 1674 func TestSubnetValidatorBLSKeyDiffAfterExpiry(t *testing.T) { 1675 // setup 1676 require := require.New(t) 1677 vm, factory, _, _ := defaultVM(t, cortina) 1678 vm.ctx.Lock.Lock() 1679 defer vm.ctx.Lock.Unlock() 1680 1681 subnetID := testSubnet1.TxID 1682 1683 // setup time 1684 currentTime := defaultGenesisTime 1685 vm.clock.Set(currentTime) 1686 vm.state.SetTimestamp(currentTime) 1687 1688 // A subnet validator stakes and then stops; also its primary network counterpart stops staking 1689 var ( 1690 primaryStartTime = currentTime.Add(executor.SyncBound) 1691 subnetStartTime = primaryStartTime.Add(executor.SyncBound) 1692 subnetEndTime = subnetStartTime.Add(defaultMinStakingDuration) 1693 primaryEndTime = subnetEndTime.Add(time.Second) 1694 primaryReStartTime = primaryEndTime.Add(executor.SyncBound) 1695 primaryReEndTime = primaryReStartTime.Add(defaultMinStakingDuration) 1696 ) 1697 1698 // insert primary network validator 1699 var ( 1700 nodeID = ids.GenerateTestNodeID() 1701 addr = keys[0].PublicKey().Address() 1702 ) 1703 sk1, err := bls.NewSecretKey() 1704 require.NoError(err) 1705 1706 // build primary network validator with BLS key 1707 builder, txSigner := factory.NewWallet(keys...) 1708 uPrimaryTx, err := builder.NewAddPermissionlessValidatorTx( 1709 &txs.SubnetValidator{ 1710 Validator: txs.Validator{ 1711 NodeID: nodeID, 1712 Start: uint64(primaryStartTime.Unix()), 1713 End: uint64(primaryEndTime.Unix()), 1714 Wght: vm.MinValidatorStake, 1715 }, 1716 Subnet: constants.PrimaryNetworkID, 1717 }, 1718 signer.NewProofOfPossession(sk1), 1719 vm.ctx.AVAXAssetID, 1720 &secp256k1fx.OutputOwners{ 1721 Threshold: 1, 1722 Addrs: []ids.ShortID{addr}, 1723 }, 1724 &secp256k1fx.OutputOwners{ 1725 Threshold: 1, 1726 Addrs: []ids.ShortID{addr}, 1727 }, 1728 reward.PercentDenominator, 1729 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1730 Threshold: 1, 1731 Addrs: []ids.ShortID{addr}, 1732 }), 1733 ) 1734 require.NoError(err) 1735 primaryTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uPrimaryTx) 1736 require.NoError(err) 1737 1738 vm.ctx.Lock.Unlock() 1739 require.NoError(vm.issueTxFromRPC(primaryTx)) 1740 vm.ctx.Lock.Lock() 1741 require.NoError(buildAndAcceptStandardBlock(vm)) 1742 1743 // move time ahead, promoting primary validator to current 1744 currentTime = primaryStartTime 1745 vm.clock.Set(currentTime) 1746 vm.state.SetTimestamp(currentTime) 1747 require.NoError(buildAndAcceptStandardBlock(vm)) 1748 1749 _, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) 1750 require.NoError(err) 1751 1752 primaryStartHeight, err := vm.GetCurrentHeight(context.Background()) 1753 require.NoError(err) 1754 1755 // insert the subnet validator 1756 builder, txSigner = factory.NewWallet(keys[0], keys[1]) 1757 uAddSubnetValTx, err := builder.NewAddSubnetValidatorTx( 1758 &txs.SubnetValidator{ 1759 Validator: txs.Validator{ 1760 NodeID: nodeID, 1761 Start: uint64(subnetStartTime.Unix()), 1762 End: uint64(subnetEndTime.Unix()), 1763 Wght: 1, 1764 }, 1765 Subnet: subnetID, 1766 }, 1767 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1768 Threshold: 1, 1769 Addrs: []ids.ShortID{addr}, 1770 }), 1771 ) 1772 require.NoError(err) 1773 subnetTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uAddSubnetValTx) 1774 require.NoError(err) 1775 1776 vm.ctx.Lock.Unlock() 1777 require.NoError(vm.issueTxFromRPC(subnetTx)) 1778 vm.ctx.Lock.Lock() 1779 require.NoError(buildAndAcceptStandardBlock(vm)) 1780 1781 // move time ahead, promoting the subnet validator to current 1782 currentTime = subnetStartTime 1783 vm.clock.Set(currentTime) 1784 vm.state.SetTimestamp(currentTime) 1785 require.NoError(buildAndAcceptStandardBlock(vm)) 1786 1787 _, err = vm.state.GetCurrentValidator(subnetID, nodeID) 1788 require.NoError(err) 1789 1790 subnetStartHeight, err := vm.GetCurrentHeight(context.Background()) 1791 require.NoError(err) 1792 1793 // move time ahead, terminating the subnet validator 1794 currentTime = subnetEndTime 1795 vm.clock.Set(currentTime) 1796 vm.state.SetTimestamp(currentTime) 1797 require.NoError(buildAndAcceptStandardBlock(vm)) 1798 1799 _, err = vm.state.GetCurrentValidator(subnetID, nodeID) 1800 require.ErrorIs(err, database.ErrNotFound) 1801 1802 subnetEndHeight, err := vm.GetCurrentHeight(context.Background()) 1803 require.NoError(err) 1804 1805 // move time ahead, terminating primary network validator 1806 currentTime = primaryEndTime 1807 vm.clock.Set(currentTime) 1808 vm.state.SetTimestamp(currentTime) 1809 1810 blk, err := vm.Builder.BuildBlock(context.Background()) // must be a proposal block rewarding the primary validator 1811 require.NoError(err) 1812 require.NoError(blk.Verify(context.Background())) 1813 1814 proposalBlk := blk.(snowman.OracleBlock) 1815 options, err := proposalBlk.Options(context.Background()) 1816 require.NoError(err) 1817 1818 commit := options[0].(*blockexecutor.Block) 1819 require.IsType(&block.BanffCommitBlock{}, commit.Block) 1820 1821 require.NoError(blk.Accept(context.Background())) 1822 require.NoError(commit.Verify(context.Background())) 1823 require.NoError(commit.Accept(context.Background())) 1824 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 1825 1826 _, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) 1827 require.ErrorIs(err, database.ErrNotFound) 1828 1829 primaryEndHeight, err := vm.GetCurrentHeight(context.Background()) 1830 require.NoError(err) 1831 1832 // reinsert primary validator with a different BLS key 1833 sk2, err := bls.NewSecretKey() 1834 require.NoError(err) 1835 require.NotEqual(sk1, sk2) 1836 1837 builder, txSigner = factory.NewWallet(keys...) 1838 uPrimaryRestartTx, err := builder.NewAddPermissionlessValidatorTx( 1839 &txs.SubnetValidator{ 1840 Validator: txs.Validator{ 1841 NodeID: nodeID, 1842 Start: uint64(primaryReStartTime.Unix()), 1843 End: uint64(primaryReEndTime.Unix()), 1844 Wght: vm.MinValidatorStake, 1845 }, 1846 Subnet: constants.PrimaryNetworkID, 1847 }, 1848 signer.NewProofOfPossession(sk2), 1849 vm.ctx.AVAXAssetID, 1850 &secp256k1fx.OutputOwners{ 1851 Threshold: 1, 1852 Addrs: []ids.ShortID{addr}, 1853 }, 1854 &secp256k1fx.OutputOwners{ 1855 Threshold: 1, 1856 Addrs: []ids.ShortID{addr}, 1857 }, 1858 reward.PercentDenominator, 1859 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1860 Threshold: 1, 1861 Addrs: []ids.ShortID{addr}, 1862 }), 1863 ) 1864 require.NoError(err) 1865 primaryRestartTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uPrimaryRestartTx) 1866 require.NoError(err) 1867 1868 vm.ctx.Lock.Unlock() 1869 require.NoError(vm.issueTxFromRPC(primaryRestartTx)) 1870 vm.ctx.Lock.Lock() 1871 require.NoError(buildAndAcceptStandardBlock(vm)) 1872 1873 // move time ahead, promoting restarted primary validator to current 1874 currentTime = primaryReStartTime 1875 vm.clock.Set(currentTime) 1876 vm.state.SetTimestamp(currentTime) 1877 require.NoError(buildAndAcceptStandardBlock(vm)) 1878 1879 _, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) 1880 require.NoError(err) 1881 1882 primaryRestartHeight, err := vm.GetCurrentHeight(context.Background()) 1883 require.NoError(err) 1884 1885 // Show that validators are rebuilt with the right BLS key 1886 for height := primaryStartHeight; height < primaryEndHeight; height++ { 1887 require.NoError(checkValidatorBlsKeyIsSet( 1888 vm.State, 1889 nodeID, 1890 constants.PrimaryNetworkID, 1891 height, 1892 uPrimaryTx.Signer.Key(), 1893 )) 1894 } 1895 for height := primaryEndHeight; height < primaryRestartHeight; height++ { 1896 err := checkValidatorBlsKeyIsSet( 1897 vm.State, 1898 nodeID, 1899 constants.PrimaryNetworkID, 1900 primaryEndHeight, 1901 uPrimaryTx.Signer.Key(), 1902 ) 1903 require.ErrorIs(err, database.ErrNotFound) 1904 } 1905 require.NoError(checkValidatorBlsKeyIsSet( 1906 vm.State, 1907 nodeID, 1908 constants.PrimaryNetworkID, 1909 primaryRestartHeight, 1910 uPrimaryRestartTx.Signer.Key(), 1911 )) 1912 1913 for height := subnetStartHeight; height < subnetEndHeight; height++ { 1914 require.NoError(checkValidatorBlsKeyIsSet( 1915 vm.State, 1916 nodeID, 1917 subnetID, 1918 height, 1919 uPrimaryTx.Signer.Key(), 1920 )) 1921 } 1922 1923 for height := subnetEndHeight; height <= primaryRestartHeight; height++ { 1924 err := checkValidatorBlsKeyIsSet( 1925 vm.State, 1926 nodeID, 1927 subnetID, 1928 primaryEndHeight, 1929 uPrimaryTx.Signer.Key(), 1930 ) 1931 require.ErrorIs(err, database.ErrNotFound) 1932 } 1933 } 1934 1935 func TestPrimaryNetworkValidatorPopulatedToEmptyBLSKeyDiff(t *testing.T) { 1936 // A primary network validator has an empty BLS key. Then it restakes adding 1937 // the BLS key. Querying the validator set back when BLS key was empty must 1938 // return an empty BLS key. 1939 1940 // setup 1941 require := require.New(t) 1942 vm, factory, _, _ := defaultVM(t, cortina) 1943 vm.ctx.Lock.Lock() 1944 defer vm.ctx.Lock.Unlock() 1945 1946 // setup time 1947 currentTime := defaultGenesisTime 1948 vm.clock.Set(currentTime) 1949 vm.state.SetTimestamp(currentTime) 1950 1951 // A primary network validator stake twice 1952 var ( 1953 primaryStartTime1 = currentTime.Add(executor.SyncBound) 1954 primaryEndTime1 = primaryStartTime1.Add(defaultMinStakingDuration) 1955 primaryStartTime2 = primaryEndTime1.Add(executor.SyncBound) 1956 primaryEndTime2 = primaryStartTime2.Add(defaultMinStakingDuration) 1957 ) 1958 1959 // Add a primary network validator with no BLS key 1960 nodeID := ids.GenerateTestNodeID() 1961 addr := keys[0].PublicKey().Address() 1962 1963 builder, txSigner := factory.NewWallet(keys[0]) 1964 uAddValTx1, err := builder.NewAddValidatorTx( 1965 &txs.Validator{ 1966 NodeID: nodeID, 1967 Start: uint64(primaryStartTime1.Unix()), 1968 End: uint64(primaryEndTime1.Unix()), 1969 Wght: vm.MinValidatorStake, 1970 }, 1971 &secp256k1fx.OutputOwners{ 1972 Threshold: 1, 1973 Addrs: []ids.ShortID{addr}, 1974 }, 1975 reward.PercentDenominator, 1976 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 1977 Threshold: 1, 1978 Addrs: []ids.ShortID{addr}, 1979 }), 1980 ) 1981 require.NoError(err) 1982 primaryTx1, err := walletsigner.SignUnsigned(context.Background(), txSigner, uAddValTx1) 1983 require.NoError(err) 1984 1985 vm.ctx.Lock.Unlock() 1986 require.NoError(vm.issueTxFromRPC(primaryTx1)) 1987 vm.ctx.Lock.Lock() 1988 require.NoError(buildAndAcceptStandardBlock(vm)) 1989 1990 // move time ahead, promoting primary validator to current 1991 currentTime = primaryStartTime1 1992 vm.clock.Set(currentTime) 1993 vm.state.SetTimestamp(currentTime) 1994 require.NoError(buildAndAcceptStandardBlock(vm)) 1995 1996 _, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) 1997 require.NoError(err) 1998 1999 primaryStartHeight, err := vm.GetCurrentHeight(context.Background()) 2000 require.NoError(err) 2001 2002 // move time ahead, terminating primary network validator 2003 currentTime = primaryEndTime1 2004 vm.clock.Set(currentTime) 2005 vm.state.SetTimestamp(currentTime) 2006 2007 blk, err := vm.Builder.BuildBlock(context.Background()) // must be a proposal block rewarding the primary validator 2008 require.NoError(err) 2009 require.NoError(blk.Verify(context.Background())) 2010 2011 proposalBlk := blk.(snowman.OracleBlock) 2012 options, err := proposalBlk.Options(context.Background()) 2013 require.NoError(err) 2014 2015 commit := options[0].(*blockexecutor.Block) 2016 require.IsType(&block.BanffCommitBlock{}, commit.Block) 2017 2018 require.NoError(blk.Accept(context.Background())) 2019 require.NoError(commit.Verify(context.Background())) 2020 require.NoError(commit.Accept(context.Background())) 2021 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 2022 2023 _, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) 2024 require.ErrorIs(err, database.ErrNotFound) 2025 2026 primaryEndHeight, err := vm.GetCurrentHeight(context.Background()) 2027 require.NoError(err) 2028 2029 // reinsert primary validator with a different BLS key 2030 sk2, err := bls.NewSecretKey() 2031 require.NoError(err) 2032 2033 builder, txSigner = factory.NewWallet(keys...) 2034 uPrimaryRestartTx, err := builder.NewAddPermissionlessValidatorTx( 2035 &txs.SubnetValidator{ 2036 Validator: txs.Validator{ 2037 NodeID: nodeID, 2038 Start: uint64(primaryStartTime2.Unix()), 2039 End: uint64(primaryEndTime2.Unix()), 2040 Wght: vm.MinValidatorStake, 2041 }, 2042 Subnet: constants.PrimaryNetworkID, 2043 }, 2044 signer.NewProofOfPossession(sk2), 2045 vm.ctx.AVAXAssetID, 2046 &secp256k1fx.OutputOwners{ 2047 Threshold: 1, 2048 Addrs: []ids.ShortID{addr}, 2049 }, 2050 &secp256k1fx.OutputOwners{ 2051 Threshold: 1, 2052 Addrs: []ids.ShortID{addr}, 2053 }, 2054 reward.PercentDenominator, 2055 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 2056 Threshold: 1, 2057 Addrs: []ids.ShortID{addr}, 2058 }), 2059 ) 2060 require.NoError(err) 2061 primaryRestartTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uPrimaryRestartTx) 2062 require.NoError(err) 2063 2064 vm.ctx.Lock.Unlock() 2065 require.NoError(vm.issueTxFromRPC(primaryRestartTx)) 2066 vm.ctx.Lock.Lock() 2067 require.NoError(buildAndAcceptStandardBlock(vm)) 2068 2069 // move time ahead, promoting restarted primary validator to current 2070 currentTime = primaryStartTime2 2071 vm.clock.Set(currentTime) 2072 vm.state.SetTimestamp(currentTime) 2073 require.NoError(buildAndAcceptStandardBlock(vm)) 2074 2075 _, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) 2076 require.NoError(err) 2077 2078 emptySigner := &signer.Empty{} 2079 for height := primaryStartHeight; height < primaryEndHeight; height++ { 2080 require.NoError(checkValidatorBlsKeyIsSet( 2081 vm.State, 2082 nodeID, 2083 constants.PrimaryNetworkID, 2084 height, 2085 emptySigner.Key(), 2086 )) 2087 } 2088 } 2089 2090 func TestSubnetValidatorPopulatedToEmptyBLSKeyDiff(t *testing.T) { 2091 // A primary network validator has an empty BLS key and a subnet validator. 2092 // Primary network validator terminates its first staking cycle and it 2093 // restakes adding the BLS key. Querying the validator set back when BLS key 2094 // was empty must return an empty BLS key for the subnet validator 2095 2096 // setup 2097 require := require.New(t) 2098 vm, factory, _, _ := defaultVM(t, cortina) 2099 vm.ctx.Lock.Lock() 2100 defer vm.ctx.Lock.Unlock() 2101 2102 subnetID := testSubnet1.TxID 2103 2104 // setup time 2105 currentTime := defaultGenesisTime 2106 vm.clock.Set(currentTime) 2107 vm.state.SetTimestamp(currentTime) 2108 2109 // A primary network validator stake twice 2110 var ( 2111 primaryStartTime1 = currentTime.Add(executor.SyncBound) 2112 subnetStartTime = primaryStartTime1.Add(executor.SyncBound) 2113 subnetEndTime = subnetStartTime.Add(defaultMinStakingDuration) 2114 primaryEndTime1 = subnetEndTime.Add(time.Second) 2115 primaryStartTime2 = primaryEndTime1.Add(executor.SyncBound) 2116 primaryEndTime2 = primaryStartTime2.Add(defaultMinStakingDuration) 2117 ) 2118 2119 // Add a primary network validator with no BLS key 2120 nodeID := ids.GenerateTestNodeID() 2121 addr := keys[0].PublicKey().Address() 2122 2123 builder, txSigner := factory.NewWallet(keys[0]) 2124 uPrimaryTx1, err := builder.NewAddValidatorTx( 2125 &txs.Validator{ 2126 NodeID: nodeID, 2127 Start: uint64(primaryStartTime1.Unix()), 2128 End: uint64(primaryEndTime1.Unix()), 2129 Wght: vm.MinValidatorStake, 2130 }, 2131 &secp256k1fx.OutputOwners{ 2132 Threshold: 1, 2133 Addrs: []ids.ShortID{addr}, 2134 }, 2135 reward.PercentDenominator, 2136 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 2137 Threshold: 1, 2138 Addrs: []ids.ShortID{addr}, 2139 }), 2140 ) 2141 require.NoError(err) 2142 primaryTx1, err := walletsigner.SignUnsigned(context.Background(), txSigner, uPrimaryTx1) 2143 require.NoError(err) 2144 2145 vm.ctx.Lock.Unlock() 2146 require.NoError(vm.issueTxFromRPC(primaryTx1)) 2147 vm.ctx.Lock.Lock() 2148 require.NoError(buildAndAcceptStandardBlock(vm)) 2149 2150 // move time ahead, promoting primary validator to current 2151 currentTime = primaryStartTime1 2152 vm.clock.Set(currentTime) 2153 vm.state.SetTimestamp(currentTime) 2154 require.NoError(buildAndAcceptStandardBlock(vm)) 2155 2156 _, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) 2157 require.NoError(err) 2158 2159 primaryStartHeight, err := vm.GetCurrentHeight(context.Background()) 2160 require.NoError(err) 2161 2162 // insert the subnet validator 2163 builder, txSigner = factory.NewWallet(keys[0], keys[1]) 2164 uAddSubnetValTx, err := builder.NewAddSubnetValidatorTx( 2165 &txs.SubnetValidator{ 2166 Validator: txs.Validator{ 2167 NodeID: nodeID, 2168 Start: uint64(subnetStartTime.Unix()), 2169 End: uint64(subnetEndTime.Unix()), 2170 Wght: 1, 2171 }, 2172 Subnet: subnetID, 2173 }, 2174 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 2175 Threshold: 1, 2176 Addrs: []ids.ShortID{addr}, 2177 }), 2178 ) 2179 require.NoError(err) 2180 subnetTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uAddSubnetValTx) 2181 require.NoError(err) 2182 2183 vm.ctx.Lock.Unlock() 2184 require.NoError(vm.issueTxFromRPC(subnetTx)) 2185 vm.ctx.Lock.Lock() 2186 require.NoError(buildAndAcceptStandardBlock(vm)) 2187 2188 // move time ahead, promoting the subnet validator to current 2189 currentTime = subnetStartTime 2190 vm.clock.Set(currentTime) 2191 vm.state.SetTimestamp(currentTime) 2192 require.NoError(buildAndAcceptStandardBlock(vm)) 2193 2194 _, err = vm.state.GetCurrentValidator(subnetID, nodeID) 2195 require.NoError(err) 2196 2197 subnetStartHeight, err := vm.GetCurrentHeight(context.Background()) 2198 require.NoError(err) 2199 2200 // move time ahead, terminating the subnet validator 2201 currentTime = subnetEndTime 2202 vm.clock.Set(currentTime) 2203 vm.state.SetTimestamp(currentTime) 2204 require.NoError(buildAndAcceptStandardBlock(vm)) 2205 2206 _, err = vm.state.GetCurrentValidator(subnetID, nodeID) 2207 require.ErrorIs(err, database.ErrNotFound) 2208 2209 subnetEndHeight, err := vm.GetCurrentHeight(context.Background()) 2210 require.NoError(err) 2211 2212 // move time ahead, terminating primary network validator 2213 currentTime = primaryEndTime1 2214 vm.clock.Set(currentTime) 2215 vm.state.SetTimestamp(currentTime) 2216 2217 blk, err := vm.Builder.BuildBlock(context.Background()) // must be a proposal block rewarding the primary validator 2218 require.NoError(err) 2219 require.NoError(blk.Verify(context.Background())) 2220 2221 proposalBlk := blk.(snowman.OracleBlock) 2222 options, err := proposalBlk.Options(context.Background()) 2223 require.NoError(err) 2224 2225 commit := options[0].(*blockexecutor.Block) 2226 require.IsType(&block.BanffCommitBlock{}, commit.Block) 2227 2228 require.NoError(blk.Accept(context.Background())) 2229 require.NoError(commit.Verify(context.Background())) 2230 require.NoError(commit.Accept(context.Background())) 2231 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 2232 2233 _, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) 2234 require.ErrorIs(err, database.ErrNotFound) 2235 2236 primaryEndHeight, err := vm.GetCurrentHeight(context.Background()) 2237 require.NoError(err) 2238 2239 // reinsert primary validator with a different BLS key 2240 sk2, err := bls.NewSecretKey() 2241 require.NoError(err) 2242 2243 builder, txSigner = factory.NewWallet(keys...) 2244 uPrimaryRestartTx, err := builder.NewAddPermissionlessValidatorTx( 2245 &txs.SubnetValidator{ 2246 Validator: txs.Validator{ 2247 NodeID: nodeID, 2248 Start: uint64(primaryStartTime2.Unix()), 2249 End: uint64(primaryEndTime2.Unix()), 2250 Wght: vm.MinValidatorStake, 2251 }, 2252 Subnet: constants.PrimaryNetworkID, 2253 }, 2254 signer.NewProofOfPossession(sk2), 2255 vm.ctx.AVAXAssetID, 2256 &secp256k1fx.OutputOwners{ 2257 Threshold: 1, 2258 Addrs: []ids.ShortID{addr}, 2259 }, 2260 &secp256k1fx.OutputOwners{ 2261 Threshold: 1, 2262 Addrs: []ids.ShortID{addr}, 2263 }, 2264 reward.PercentDenominator, 2265 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 2266 Threshold: 1, 2267 Addrs: []ids.ShortID{addr}, 2268 }), 2269 ) 2270 require.NoError(err) 2271 primaryRestartTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uPrimaryRestartTx) 2272 require.NoError(err) 2273 2274 vm.ctx.Lock.Unlock() 2275 require.NoError(vm.issueTxFromRPC(primaryRestartTx)) 2276 vm.ctx.Lock.Lock() 2277 require.NoError(buildAndAcceptStandardBlock(vm)) 2278 2279 // move time ahead, promoting restarted primary validator to current 2280 currentTime = primaryStartTime2 2281 vm.clock.Set(currentTime) 2282 vm.state.SetTimestamp(currentTime) 2283 2284 require.NoError(buildAndAcceptStandardBlock(vm)) 2285 _, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) 2286 require.NoError(err) 2287 2288 emptySigner := &signer.Empty{} 2289 for height := primaryStartHeight; height < primaryEndHeight; height++ { 2290 require.NoError(checkValidatorBlsKeyIsSet( 2291 vm.State, 2292 nodeID, 2293 constants.PrimaryNetworkID, 2294 height, 2295 emptySigner.Key(), 2296 )) 2297 } 2298 for height := subnetStartHeight; height < subnetEndHeight; height++ { 2299 require.NoError(checkValidatorBlsKeyIsSet( 2300 vm.State, 2301 nodeID, 2302 subnetID, 2303 height, 2304 emptySigner.Key(), 2305 )) 2306 } 2307 } 2308 2309 func TestSubnetValidatorSetAfterPrimaryNetworkValidatorRemoval(t *testing.T) { 2310 // A primary network validator and a subnet validator are running. 2311 // Primary network validator terminates its staking cycle. 2312 // Querying the validator set when the subnet validator existed should 2313 // succeed. 2314 2315 // setup 2316 require := require.New(t) 2317 vm, factory, _, _ := defaultVM(t, cortina) 2318 vm.ctx.Lock.Lock() 2319 defer vm.ctx.Lock.Unlock() 2320 2321 subnetID := testSubnet1.TxID 2322 2323 // setup time 2324 currentTime := defaultGenesisTime 2325 vm.clock.Set(currentTime) 2326 vm.state.SetTimestamp(currentTime) 2327 2328 // A primary network validator stake twice 2329 var ( 2330 primaryStartTime1 = currentTime.Add(executor.SyncBound) 2331 subnetStartTime = primaryStartTime1.Add(executor.SyncBound) 2332 subnetEndTime = subnetStartTime.Add(defaultMinStakingDuration) 2333 primaryEndTime1 = subnetEndTime.Add(time.Second) 2334 ) 2335 2336 // Add a primary network validator with no BLS key 2337 nodeID := ids.GenerateTestNodeID() 2338 addr := keys[0].PublicKey().Address() 2339 2340 builder, txSigner := factory.NewWallet(keys[0]) 2341 uPrimaryTx1, err := builder.NewAddValidatorTx( 2342 &txs.Validator{ 2343 NodeID: nodeID, 2344 Start: uint64(primaryStartTime1.Unix()), 2345 End: uint64(primaryEndTime1.Unix()), 2346 Wght: vm.MinValidatorStake, 2347 }, 2348 &secp256k1fx.OutputOwners{ 2349 Threshold: 1, 2350 Addrs: []ids.ShortID{addr}, 2351 }, 2352 reward.PercentDenominator, 2353 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 2354 Threshold: 1, 2355 Addrs: []ids.ShortID{addr}, 2356 }), 2357 ) 2358 require.NoError(err) 2359 primaryTx1, err := walletsigner.SignUnsigned(context.Background(), txSigner, uPrimaryTx1) 2360 require.NoError(err) 2361 2362 vm.ctx.Lock.Unlock() 2363 require.NoError(vm.issueTxFromRPC(primaryTx1)) 2364 vm.ctx.Lock.Lock() 2365 require.NoError(buildAndAcceptStandardBlock(vm)) 2366 2367 // move time ahead, promoting primary validator to current 2368 currentTime = primaryStartTime1 2369 vm.clock.Set(currentTime) 2370 vm.state.SetTimestamp(currentTime) 2371 require.NoError(buildAndAcceptStandardBlock(vm)) 2372 2373 _, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) 2374 require.NoError(err) 2375 2376 // insert the subnet validator 2377 builder, txSigner = factory.NewWallet(keys[0], keys[1]) 2378 uAddSubnetValTx, err := builder.NewAddSubnetValidatorTx( 2379 &txs.SubnetValidator{ 2380 Validator: txs.Validator{ 2381 NodeID: nodeID, 2382 Start: uint64(subnetStartTime.Unix()), 2383 End: uint64(subnetEndTime.Unix()), 2384 Wght: 1, 2385 }, 2386 Subnet: subnetID, 2387 }, 2388 walletcommon.WithChangeOwner(&secp256k1fx.OutputOwners{ 2389 Threshold: 1, 2390 Addrs: []ids.ShortID{addr}, 2391 }), 2392 ) 2393 require.NoError(err) 2394 subnetTx, err := walletsigner.SignUnsigned(context.Background(), txSigner, uAddSubnetValTx) 2395 require.NoError(err) 2396 2397 vm.ctx.Lock.Unlock() 2398 require.NoError(vm.issueTxFromRPC(subnetTx)) 2399 vm.ctx.Lock.Lock() 2400 require.NoError(buildAndAcceptStandardBlock(vm)) 2401 2402 // move time ahead, promoting the subnet validator to current 2403 currentTime = subnetStartTime 2404 vm.clock.Set(currentTime) 2405 vm.state.SetTimestamp(currentTime) 2406 require.NoError(buildAndAcceptStandardBlock(vm)) 2407 2408 _, err = vm.state.GetCurrentValidator(subnetID, nodeID) 2409 require.NoError(err) 2410 2411 subnetStartHeight, err := vm.GetCurrentHeight(context.Background()) 2412 require.NoError(err) 2413 2414 // move time ahead, terminating the subnet validator 2415 currentTime = subnetEndTime 2416 vm.clock.Set(currentTime) 2417 vm.state.SetTimestamp(currentTime) 2418 require.NoError(buildAndAcceptStandardBlock(vm)) 2419 2420 _, err = vm.state.GetCurrentValidator(subnetID, nodeID) 2421 require.ErrorIs(err, database.ErrNotFound) 2422 2423 // move time ahead, terminating primary network validator 2424 currentTime = primaryEndTime1 2425 vm.clock.Set(currentTime) 2426 vm.state.SetTimestamp(currentTime) 2427 2428 blk, err := vm.Builder.BuildBlock(context.Background()) // must be a proposal block rewarding the primary validator 2429 require.NoError(err) 2430 require.NoError(blk.Verify(context.Background())) 2431 2432 proposalBlk := blk.(snowman.OracleBlock) 2433 options, err := proposalBlk.Options(context.Background()) 2434 require.NoError(err) 2435 2436 commit := options[0].(*blockexecutor.Block) 2437 require.IsType(&block.BanffCommitBlock{}, commit.Block) 2438 2439 require.NoError(blk.Accept(context.Background())) 2440 require.NoError(commit.Verify(context.Background())) 2441 require.NoError(commit.Accept(context.Background())) 2442 require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted())) 2443 2444 _, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) 2445 require.ErrorIs(err, database.ErrNotFound) 2446 2447 // Generating the validator set should not error when re-introducing a 2448 // subnet validator whose primary network validator was also removed. 2449 _, err = vm.State.GetValidatorSet(context.Background(), subnetStartHeight, subnetID) 2450 require.NoError(err) 2451 } 2452 2453 func TestValidatorSetRaceCondition(t *testing.T) { 2454 require := require.New(t) 2455 vm, _, _, _ := defaultVM(t, cortina) 2456 vm.ctx.Lock.Lock() 2457 defer vm.ctx.Lock.Unlock() 2458 2459 nodeID := ids.GenerateTestNodeID() 2460 require.NoError(vm.Connected(context.Background(), nodeID, version.CurrentApp)) 2461 2462 protocolAppRequestBytest, err := gossip.MarshalAppRequest( 2463 bloom.EmptyFilter.Marshal(), 2464 ids.Empty[:], 2465 ) 2466 require.NoError(err) 2467 2468 appRequestBytes := p2p.PrefixMessage( 2469 p2p.ProtocolPrefix(network.TxGossipHandlerID), 2470 protocolAppRequestBytest, 2471 ) 2472 2473 var ( 2474 eg errgroup.Group 2475 ctx, cancel = context.WithCancel(context.Background()) 2476 ) 2477 // keep 10 workers running 2478 for i := 0; i < 10; i++ { 2479 eg.Go(func() error { 2480 for ctx.Err() == nil { 2481 err := vm.AppRequest( 2482 context.Background(), 2483 nodeID, 2484 0, 2485 time.Now().Add(time.Hour), 2486 appRequestBytes, 2487 ) 2488 if err != nil { 2489 return err 2490 } 2491 } 2492 return nil 2493 }) 2494 } 2495 2496 // If the validator set lock isn't held, the race detector should fail here. 2497 for i := uint64(0); i < 1000; i++ { 2498 blk, err := block.NewBanffStandardBlock( 2499 time.Now(), 2500 vm.state.GetLastAccepted(), 2501 i, 2502 nil, 2503 ) 2504 require.NoError(err) 2505 2506 vm.state.SetLastAccepted(blk.ID()) 2507 vm.state.SetHeight(blk.Height()) 2508 vm.state.AddStatelessBlock(blk) 2509 } 2510 2511 // If the validator set lock is grabbed, we need to make sure to release the 2512 // lock to avoid a deadlock. 2513 vm.ctx.Lock.Unlock() 2514 cancel() // stop and wait for workers 2515 require.NoError(eg.Wait()) 2516 vm.ctx.Lock.Lock() 2517 } 2518 2519 func buildAndAcceptStandardBlock(vm *VM) error { 2520 blk, err := vm.Builder.BuildBlock(context.Background()) 2521 if err != nil { 2522 return err 2523 } 2524 2525 if err := blk.Verify(context.Background()); err != nil { 2526 return err 2527 } 2528 2529 if err := blk.Accept(context.Background()); err != nil { 2530 return err 2531 } 2532 2533 return vm.SetPreference(context.Background(), vm.manager.LastAccepted()) 2534 } 2535 2536 func checkValidatorBlsKeyIsSet( 2537 valState validators.State, 2538 nodeID ids.NodeID, 2539 subnetID ids.ID, 2540 height uint64, 2541 expectedBlsKey *bls.PublicKey, 2542 ) error { 2543 vals, err := valState.GetValidatorSet(context.Background(), height, subnetID) 2544 if err != nil { 2545 return err 2546 } 2547 2548 val, found := vals[nodeID] 2549 switch { 2550 case !found: 2551 return database.ErrNotFound 2552 case expectedBlsKey == val.PublicKey: 2553 return nil 2554 case expectedBlsKey == nil && val.PublicKey != nil: 2555 return errors.New("unexpected BLS key") 2556 case expectedBlsKey != nil && val.PublicKey == nil: 2557 return errors.New("missing BLS key") 2558 case !bytes.Equal(bls.PublicKeyToUncompressedBytes(expectedBlsKey), bls.PublicKeyToUncompressedBytes(val.PublicKey)): 2559 return errors.New("incorrect BLS key") 2560 default: 2561 return nil 2562 } 2563 }