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