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  }