github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/vm_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  	"testing"
    10  	"time"
    11  
    12  	"github.com/prometheus/client_golang/prometheus"
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/ava-labs/avalanchego/chains"
    16  	"github.com/ava-labs/avalanchego/chains/atomic"
    17  	"github.com/ava-labs/avalanchego/database"
    18  	"github.com/ava-labs/avalanchego/database/memdb"
    19  	"github.com/ava-labs/avalanchego/database/prefixdb"
    20  	"github.com/ava-labs/avalanchego/ids"
    21  	"github.com/ava-labs/avalanchego/message"
    22  	"github.com/ava-labs/avalanchego/network/p2p"
    23  	"github.com/ava-labs/avalanchego/snow"
    24  	"github.com/ava-labs/avalanchego/snow/consensus/snowball"
    25  	"github.com/ava-labs/avalanchego/snow/engine/common"
    26  	"github.com/ava-labs/avalanchego/snow/engine/common/tracker"
    27  	"github.com/ava-labs/avalanchego/snow/engine/enginetest"
    28  	"github.com/ava-labs/avalanchego/snow/engine/snowman/bootstrap"
    29  	"github.com/ava-labs/avalanchego/snow/networking/benchlist"
    30  	"github.com/ava-labs/avalanchego/snow/networking/handler"
    31  	"github.com/ava-labs/avalanchego/snow/networking/router"
    32  	"github.com/ava-labs/avalanchego/snow/networking/sender"
    33  	"github.com/ava-labs/avalanchego/snow/networking/sender/sendertest"
    34  	"github.com/ava-labs/avalanchego/snow/networking/timeout"
    35  	"github.com/ava-labs/avalanchego/snow/snowtest"
    36  	"github.com/ava-labs/avalanchego/snow/uptime"
    37  	"github.com/ava-labs/avalanchego/snow/validators"
    38  	"github.com/ava-labs/avalanchego/subnets"
    39  	"github.com/ava-labs/avalanchego/upgrade/upgradetest"
    40  	"github.com/ava-labs/avalanchego/utils/constants"
    41  	"github.com/ava-labs/avalanchego/utils/crypto/bls"
    42  	"github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
    43  	"github.com/ava-labs/avalanchego/utils/logging"
    44  	"github.com/ava-labs/avalanchego/utils/math/meter"
    45  	"github.com/ava-labs/avalanchego/utils/resource"
    46  	"github.com/ava-labs/avalanchego/utils/set"
    47  	"github.com/ava-labs/avalanchego/utils/timer"
    48  	"github.com/ava-labs/avalanchego/utils/units"
    49  	"github.com/ava-labs/avalanchego/version"
    50  	"github.com/ava-labs/avalanchego/vms/components/avax"
    51  	"github.com/ava-labs/avalanchego/vms/components/gas"
    52  	"github.com/ava-labs/avalanchego/vms/platformvm/block"
    53  	"github.com/ava-labs/avalanchego/vms/platformvm/config"
    54  	"github.com/ava-labs/avalanchego/vms/platformvm/genesis/genesistest"
    55  	"github.com/ava-labs/avalanchego/vms/platformvm/reward"
    56  	"github.com/ava-labs/avalanchego/vms/platformvm/signer"
    57  	"github.com/ava-labs/avalanchego/vms/platformvm/status"
    58  	"github.com/ava-labs/avalanchego/vms/platformvm/txs"
    59  	"github.com/ava-labs/avalanchego/vms/platformvm/txs/fee"
    60  	"github.com/ava-labs/avalanchego/vms/platformvm/txs/txstest"
    61  	"github.com/ava-labs/avalanchego/vms/secp256k1fx"
    62  	"github.com/ava-labs/avalanchego/wallet/chain/p/wallet"
    63  
    64  	p2ppb "github.com/ava-labs/avalanchego/proto/pb/p2p"
    65  	smcon "github.com/ava-labs/avalanchego/snow/consensus/snowman"
    66  	smeng "github.com/ava-labs/avalanchego/snow/engine/snowman"
    67  	snowgetter "github.com/ava-labs/avalanchego/snow/engine/snowman/getter"
    68  	timetracker "github.com/ava-labs/avalanchego/snow/networking/tracker"
    69  	blockbuilder "github.com/ava-labs/avalanchego/vms/platformvm/block/builder"
    70  	blockexecutor "github.com/ava-labs/avalanchego/vms/platformvm/block/executor"
    71  	txexecutor "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor"
    72  	walletbuilder "github.com/ava-labs/avalanchego/wallet/chain/p/builder"
    73  	walletcommon "github.com/ava-labs/avalanchego/wallet/subnet/primary/common"
    74  )
    75  
    76  const (
    77  	defaultMinDelegatorStake = 1 * units.MilliAvax
    78  	defaultMinValidatorStake = 5 * defaultMinDelegatorStake
    79  	defaultMaxValidatorStake = 100 * defaultMinValidatorStake
    80  
    81  	defaultMinStakingDuration = 24 * time.Hour
    82  	defaultMaxStakingDuration = 365 * 24 * time.Hour
    83  
    84  	defaultTxFee = 100 * units.NanoAvax
    85  )
    86  
    87  var (
    88  	defaultRewardConfig = reward.Config{
    89  		MaxConsumptionRate: .12 * reward.PercentDenominator,
    90  		MinConsumptionRate: .10 * reward.PercentDenominator,
    91  		MintingPeriod:      365 * 24 * time.Hour,
    92  		SupplyCap:          720 * units.MegaAvax,
    93  	}
    94  
    95  	latestForkTime = genesistest.DefaultValidatorStartTime.Add(time.Second)
    96  
    97  	defaultStaticFeeConfig = fee.StaticConfig{
    98  		TxFee:                 defaultTxFee,
    99  		CreateSubnetTxFee:     100 * defaultTxFee,
   100  		TransformSubnetTxFee:  100 * defaultTxFee,
   101  		CreateBlockchainTxFee: 100 * defaultTxFee,
   102  	}
   103  	defaultDynamicFeeConfig = gas.Config{
   104  		Weights: gas.Dimensions{
   105  			gas.Bandwidth: 1,
   106  			gas.DBRead:    1,
   107  			gas.DBWrite:   1,
   108  			gas.Compute:   1,
   109  		},
   110  		MaxCapacity:              10_000,
   111  		MaxPerSecond:             1_000,
   112  		TargetPerSecond:          500,
   113  		MinPrice:                 1,
   114  		ExcessConversionConstant: 5_000,
   115  	}
   116  
   117  	// subnet that exists at genesis in defaultVM
   118  	testSubnet1 *txs.Tx
   119  )
   120  
   121  type mutableSharedMemory struct {
   122  	atomic.SharedMemory
   123  }
   124  
   125  func defaultVM(t *testing.T, f upgradetest.Fork) (*VM, database.Database, *mutableSharedMemory) {
   126  	require := require.New(t)
   127  
   128  	// always reset latestForkTime (a package level variable)
   129  	// to ensure test independence
   130  	latestForkTime = genesistest.DefaultValidatorStartTime.Add(time.Second)
   131  	vm := &VM{Config: config.Config{
   132  		Chains:                 chains.TestManager,
   133  		UptimeLockedCalculator: uptime.NewLockedCalculator(),
   134  		SybilProtectionEnabled: true,
   135  		Validators:             validators.NewManager(),
   136  		StaticFeeConfig:        defaultStaticFeeConfig,
   137  		DynamicFeeConfig:       defaultDynamicFeeConfig,
   138  		MinValidatorStake:      defaultMinValidatorStake,
   139  		MaxValidatorStake:      defaultMaxValidatorStake,
   140  		MinDelegatorStake:      defaultMinDelegatorStake,
   141  		MinStakeDuration:       defaultMinStakingDuration,
   142  		MaxStakeDuration:       defaultMaxStakingDuration,
   143  		RewardConfig:           defaultRewardConfig,
   144  		UpgradeConfig:          upgradetest.GetConfigWithUpgradeTime(f, latestForkTime),
   145  	}}
   146  
   147  	db := memdb.New()
   148  	chainDB := prefixdb.New([]byte{0}, db)
   149  	atomicDB := prefixdb.New([]byte{1}, db)
   150  
   151  	vm.clock.Set(latestForkTime)
   152  	msgChan := make(chan common.Message, 1)
   153  	ctx := snowtest.Context(t, snowtest.PChainID)
   154  
   155  	m := atomic.NewMemory(atomicDB)
   156  	msm := &mutableSharedMemory{
   157  		SharedMemory: m.NewSharedMemory(ctx.ChainID),
   158  	}
   159  	ctx.SharedMemory = msm
   160  
   161  	ctx.Lock.Lock()
   162  	defer ctx.Lock.Unlock()
   163  	appSender := &enginetest.Sender{}
   164  	appSender.CantSendAppGossip = true
   165  	appSender.SendAppGossipF = func(context.Context, common.SendConfig, []byte) error {
   166  		return nil
   167  	}
   168  	appSender.SendAppErrorF = func(context.Context, ids.NodeID, uint32, int32, string) error {
   169  		return nil
   170  	}
   171  
   172  	dynamicConfigBytes := []byte(`{"network":{"max-validator-set-staleness":0}}`)
   173  	require.NoError(vm.Initialize(
   174  		context.Background(),
   175  		ctx,
   176  		chainDB,
   177  		genesistest.NewBytes(t, genesistest.Config{}),
   178  		nil,
   179  		dynamicConfigBytes,
   180  		msgChan,
   181  		nil,
   182  		appSender,
   183  	))
   184  
   185  	// align chain time and local clock
   186  	vm.state.SetTimestamp(vm.clock.Time())
   187  	vm.state.SetFeeState(gas.State{
   188  		Capacity: defaultDynamicFeeConfig.MaxCapacity,
   189  	})
   190  
   191  	require.NoError(vm.SetState(context.Background(), snow.NormalOp))
   192  
   193  	wallet := newWallet(t, vm, walletConfig{
   194  		keys: []*secp256k1.PrivateKey{genesistest.DefaultFundedKeys[0]},
   195  	})
   196  
   197  	// Create a subnet and store it in testSubnet1
   198  	// Note: following Banff activation, block acceptance will move
   199  	// chain time ahead
   200  	var err error
   201  	testSubnet1, err = wallet.IssueCreateSubnetTx(
   202  		&secp256k1fx.OutputOwners{
   203  			Threshold: 2,
   204  			Addrs: []ids.ShortID{
   205  				genesistest.DefaultFundedKeys[0].Address(),
   206  				genesistest.DefaultFundedKeys[1].Address(),
   207  				genesistest.DefaultFundedKeys[2].Address(),
   208  			},
   209  		},
   210  	)
   211  	require.NoError(err)
   212  
   213  	vm.ctx.Lock.Unlock()
   214  	require.NoError(vm.issueTxFromRPC(testSubnet1))
   215  	vm.ctx.Lock.Lock()
   216  	require.NoError(buildAndAcceptStandardBlock(vm))
   217  
   218  	t.Cleanup(func() {
   219  		vm.ctx.Lock.Lock()
   220  		defer vm.ctx.Lock.Unlock()
   221  
   222  		require.NoError(vm.Shutdown(context.Background()))
   223  	})
   224  
   225  	return vm, db, msm
   226  }
   227  
   228  type walletConfig struct {
   229  	keys      []*secp256k1.PrivateKey
   230  	subnetIDs []ids.ID
   231  }
   232  
   233  func newWallet(t testing.TB, vm *VM, c walletConfig) wallet.Wallet {
   234  	if len(c.keys) == 0 {
   235  		c.keys = genesistest.DefaultFundedKeys
   236  	}
   237  	return txstest.NewWallet(
   238  		t,
   239  		vm.ctx,
   240  		&vm.Config,
   241  		vm.state,
   242  		secp256k1fx.NewKeychain(c.keys...),
   243  		c.subnetIDs,
   244  		[]ids.ID{vm.ctx.CChainID, vm.ctx.XChainID},
   245  	)
   246  }
   247  
   248  // Ensure genesis state is parsed from bytes and stored correctly
   249  func TestGenesis(t *testing.T) {
   250  	require := require.New(t)
   251  	vm, _, _ := defaultVM(t, upgradetest.Durango)
   252  	vm.ctx.Lock.Lock()
   253  	defer vm.ctx.Lock.Unlock()
   254  
   255  	// Ensure the genesis block has been accepted and stored
   256  	genesisBlockID, err := vm.LastAccepted(context.Background()) // lastAccepted should be ID of genesis block
   257  	require.NoError(err)
   258  
   259  	// Ensure the genesis block can be retrieved
   260  	genesisBlock, err := vm.manager.GetBlock(genesisBlockID)
   261  	require.NoError(err)
   262  	require.NotNil(genesisBlock)
   263  
   264  	genesisState := genesistest.New(t, genesistest.Config{})
   265  	// Ensure all the genesis UTXOs are there
   266  	for _, utxo := range genesisState.UTXOs {
   267  		genesisOut := utxo.Out.(*secp256k1fx.TransferOutput)
   268  		utxos, err := avax.GetAllUTXOs(
   269  			vm.state,
   270  			genesisOut.OutputOwners.AddressesSet(),
   271  		)
   272  		require.NoError(err)
   273  		require.Len(utxos, 1)
   274  
   275  		out := utxos[0].Out.(*secp256k1fx.TransferOutput)
   276  		if out.Amt != genesisOut.Amt {
   277  			require.Equal(
   278  				[]ids.ShortID{genesistest.DefaultFundedKeys[0].Address()},
   279  				out.OutputOwners.Addrs,
   280  			)
   281  			require.Equal(genesisOut.Amt-vm.StaticFeeConfig.CreateSubnetTxFee, out.Amt)
   282  		}
   283  	}
   284  
   285  	// Ensure current validator set of primary network is correct
   286  	require.Len(genesisState.Validators, vm.Validators.Count(constants.PrimaryNetworkID))
   287  
   288  	for _, nodeID := range genesistest.DefaultNodeIDs {
   289  		_, ok := vm.Validators.GetValidator(constants.PrimaryNetworkID, nodeID)
   290  		require.True(ok)
   291  	}
   292  
   293  	// Ensure the new subnet we created exists
   294  	_, _, err = vm.state.GetTx(testSubnet1.ID())
   295  	require.NoError(err)
   296  }
   297  
   298  // accept proposal to add validator to primary network
   299  func TestAddValidatorCommit(t *testing.T) {
   300  	require := require.New(t)
   301  	vm, _, _ := defaultVM(t, upgradetest.Latest)
   302  	vm.ctx.Lock.Lock()
   303  	defer vm.ctx.Lock.Unlock()
   304  
   305  	wallet := newWallet(t, vm, walletConfig{})
   306  
   307  	var (
   308  		endTime      = vm.clock.Time().Add(defaultMinStakingDuration)
   309  		nodeID       = ids.GenerateTestNodeID()
   310  		rewardsOwner = &secp256k1fx.OutputOwners{
   311  			Threshold: 1,
   312  			Addrs:     []ids.ShortID{ids.GenerateTestShortID()},
   313  		}
   314  	)
   315  
   316  	sk, err := bls.NewSecretKey()
   317  	require.NoError(err)
   318  
   319  	// create valid tx
   320  	tx, err := wallet.IssueAddPermissionlessValidatorTx(
   321  		&txs.SubnetValidator{
   322  			Validator: txs.Validator{
   323  				NodeID: nodeID,
   324  				End:    uint64(endTime.Unix()),
   325  				Wght:   vm.MinValidatorStake,
   326  			},
   327  			Subnet: constants.PrimaryNetworkID,
   328  		},
   329  		signer.NewProofOfPossession(sk),
   330  		vm.ctx.AVAXAssetID,
   331  		rewardsOwner,
   332  		rewardsOwner,
   333  		reward.PercentDenominator,
   334  	)
   335  	require.NoError(err)
   336  
   337  	// trigger block creation
   338  	vm.ctx.Lock.Unlock()
   339  	require.NoError(vm.issueTxFromRPC(tx))
   340  	vm.ctx.Lock.Lock()
   341  	require.NoError(buildAndAcceptStandardBlock(vm))
   342  
   343  	_, txStatus, err := vm.state.GetTx(tx.ID())
   344  	require.NoError(err)
   345  	require.Equal(status.Committed, txStatus)
   346  
   347  	// Verify that new validator now in current validator set
   348  	_, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID)
   349  	require.NoError(err)
   350  }
   351  
   352  // verify invalid attempt to add validator to primary network
   353  func TestInvalidAddValidatorCommit(t *testing.T) {
   354  	require := require.New(t)
   355  	vm, _, _ := defaultVM(t, upgradetest.Cortina)
   356  	vm.ctx.Lock.Lock()
   357  	defer vm.ctx.Lock.Unlock()
   358  
   359  	wallet := newWallet(t, vm, walletConfig{})
   360  
   361  	nodeID := ids.GenerateTestNodeID()
   362  	startTime := genesistest.DefaultValidatorStartTime.Add(-txexecutor.SyncBound).Add(-1 * time.Second)
   363  	endTime := startTime.Add(defaultMinStakingDuration)
   364  
   365  	// create invalid tx
   366  	tx, err := wallet.IssueAddValidatorTx(
   367  		&txs.Validator{
   368  			NodeID: nodeID,
   369  			Start:  uint64(startTime.Unix()),
   370  			End:    uint64(endTime.Unix()),
   371  			Wght:   vm.MinValidatorStake,
   372  		},
   373  		&secp256k1fx.OutputOwners{
   374  			Threshold: 1,
   375  			Addrs:     []ids.ShortID{ids.GenerateTestShortID()},
   376  		},
   377  		reward.PercentDenominator,
   378  	)
   379  	require.NoError(err)
   380  
   381  	preferredID := vm.manager.Preferred()
   382  	preferred, err := vm.manager.GetBlock(preferredID)
   383  	require.NoError(err)
   384  	preferredHeight := preferred.Height()
   385  
   386  	statelessBlk, err := block.NewBanffStandardBlock(
   387  		preferred.Timestamp(),
   388  		preferredID,
   389  		preferredHeight+1,
   390  		[]*txs.Tx{tx},
   391  	)
   392  	require.NoError(err)
   393  
   394  	blkBytes := statelessBlk.Bytes()
   395  
   396  	parsedBlock, err := vm.ParseBlock(context.Background(), blkBytes)
   397  	require.NoError(err)
   398  
   399  	err = parsedBlock.Verify(context.Background())
   400  	require.ErrorIs(err, txexecutor.ErrTimestampNotBeforeStartTime)
   401  
   402  	txID := statelessBlk.Txs()[0].ID()
   403  	reason := vm.Builder.GetDropReason(txID)
   404  	require.ErrorIs(reason, txexecutor.ErrTimestampNotBeforeStartTime)
   405  }
   406  
   407  // Reject attempt to add validator to primary network
   408  func TestAddValidatorReject(t *testing.T) {
   409  	require := require.New(t)
   410  	vm, _, _ := defaultVM(t, upgradetest.Cortina)
   411  	vm.ctx.Lock.Lock()
   412  	defer vm.ctx.Lock.Unlock()
   413  
   414  	wallet := newWallet(t, vm, walletConfig{})
   415  
   416  	var (
   417  		startTime     = vm.clock.Time().Add(txexecutor.SyncBound).Add(1 * time.Second)
   418  		endTime       = startTime.Add(defaultMinStakingDuration)
   419  		nodeID        = ids.GenerateTestNodeID()
   420  		rewardAddress = ids.GenerateTestShortID()
   421  	)
   422  
   423  	// create valid tx
   424  	tx, err := wallet.IssueAddValidatorTx(
   425  		&txs.Validator{
   426  			NodeID: nodeID,
   427  			Start:  uint64(startTime.Unix()),
   428  			End:    uint64(endTime.Unix()),
   429  			Wght:   vm.MinValidatorStake,
   430  		},
   431  		&secp256k1fx.OutputOwners{
   432  			Threshold: 1,
   433  			Addrs:     []ids.ShortID{rewardAddress},
   434  		},
   435  		reward.PercentDenominator,
   436  	)
   437  	require.NoError(err)
   438  
   439  	// trigger block creation
   440  	vm.ctx.Lock.Unlock()
   441  	require.NoError(vm.issueTxFromRPC(tx))
   442  	vm.ctx.Lock.Lock()
   443  
   444  	blk, err := vm.Builder.BuildBlock(context.Background())
   445  	require.NoError(err)
   446  
   447  	require.NoError(blk.Verify(context.Background()))
   448  	require.NoError(blk.Reject(context.Background()))
   449  
   450  	_, _, err = vm.state.GetTx(tx.ID())
   451  	require.ErrorIs(err, database.ErrNotFound)
   452  
   453  	_, err = vm.state.GetPendingValidator(constants.PrimaryNetworkID, nodeID)
   454  	require.ErrorIs(err, database.ErrNotFound)
   455  }
   456  
   457  // Reject proposal to add validator to primary network
   458  func TestAddValidatorInvalidNotReissued(t *testing.T) {
   459  	require := require.New(t)
   460  	vm, _, _ := defaultVM(t, upgradetest.Latest)
   461  	vm.ctx.Lock.Lock()
   462  	defer vm.ctx.Lock.Unlock()
   463  
   464  	wallet := newWallet(t, vm, walletConfig{})
   465  
   466  	// Use nodeID that is already in the genesis
   467  	repeatNodeID := genesistest.DefaultNodeIDs[0]
   468  
   469  	startTime := latestForkTime.Add(txexecutor.SyncBound).Add(1 * time.Second)
   470  	endTime := startTime.Add(defaultMinStakingDuration)
   471  
   472  	sk, err := bls.NewSecretKey()
   473  	require.NoError(err)
   474  
   475  	rewardsOwner := &secp256k1fx.OutputOwners{
   476  		Threshold: 1,
   477  		Addrs:     []ids.ShortID{ids.GenerateTestShortID()},
   478  	}
   479  
   480  	// create valid tx
   481  	tx, err := wallet.IssueAddPermissionlessValidatorTx(
   482  		&txs.SubnetValidator{
   483  			Validator: txs.Validator{
   484  				NodeID: repeatNodeID,
   485  				Start:  uint64(startTime.Unix()),
   486  				End:    uint64(endTime.Unix()),
   487  				Wght:   vm.MinValidatorStake,
   488  			},
   489  			Subnet: constants.PrimaryNetworkID,
   490  		},
   491  		signer.NewProofOfPossession(sk),
   492  		vm.ctx.AVAXAssetID,
   493  		rewardsOwner,
   494  		rewardsOwner,
   495  		reward.PercentDenominator,
   496  	)
   497  	require.NoError(err)
   498  
   499  	// trigger block creation
   500  	vm.ctx.Lock.Unlock()
   501  	err = vm.issueTxFromRPC(tx)
   502  	vm.ctx.Lock.Lock()
   503  	require.ErrorIs(err, txexecutor.ErrDuplicateValidator)
   504  }
   505  
   506  // Accept proposal to add validator to subnet
   507  func TestAddSubnetValidatorAccept(t *testing.T) {
   508  	require := require.New(t)
   509  	vm, _, _ := defaultVM(t, upgradetest.Latest)
   510  	vm.ctx.Lock.Lock()
   511  	defer vm.ctx.Lock.Unlock()
   512  
   513  	subnetID := testSubnet1.ID()
   514  	wallet := newWallet(t, vm, walletConfig{
   515  		subnetIDs: []ids.ID{subnetID},
   516  	})
   517  
   518  	var (
   519  		startTime = vm.clock.Time().Add(txexecutor.SyncBound).Add(1 * time.Second)
   520  		endTime   = startTime.Add(defaultMinStakingDuration)
   521  		nodeID    = genesistest.DefaultNodeIDs[0]
   522  	)
   523  
   524  	// create valid tx
   525  	// note that [startTime, endTime] is a subset of time that keys[0]
   526  	// validates primary network ([genesistest.DefaultValidatorStartTime, genesistest.DefaultValidatorEndTime])
   527  	tx, err := wallet.IssueAddSubnetValidatorTx(
   528  		&txs.SubnetValidator{
   529  			Validator: txs.Validator{
   530  				NodeID: nodeID,
   531  				Start:  uint64(startTime.Unix()),
   532  				End:    uint64(endTime.Unix()),
   533  				Wght:   genesistest.DefaultValidatorWeight,
   534  			},
   535  			Subnet: subnetID,
   536  		},
   537  	)
   538  	require.NoError(err)
   539  
   540  	// trigger block creation
   541  	vm.ctx.Lock.Unlock()
   542  	require.NoError(vm.issueTxFromRPC(tx))
   543  	vm.ctx.Lock.Lock()
   544  	require.NoError(buildAndAcceptStandardBlock(vm))
   545  
   546  	_, txStatus, err := vm.state.GetTx(tx.ID())
   547  	require.NoError(err)
   548  	require.Equal(status.Committed, txStatus)
   549  
   550  	// Verify that new validator is in current validator set
   551  	_, err = vm.state.GetCurrentValidator(subnetID, nodeID)
   552  	require.NoError(err)
   553  }
   554  
   555  // Reject proposal to add validator to subnet
   556  func TestAddSubnetValidatorReject(t *testing.T) {
   557  	require := require.New(t)
   558  	vm, _, _ := defaultVM(t, upgradetest.Latest)
   559  	vm.ctx.Lock.Lock()
   560  	defer vm.ctx.Lock.Unlock()
   561  
   562  	subnetID := testSubnet1.ID()
   563  	wallet := newWallet(t, vm, walletConfig{
   564  		subnetIDs: []ids.ID{subnetID},
   565  	})
   566  
   567  	var (
   568  		startTime = vm.clock.Time().Add(txexecutor.SyncBound).Add(1 * time.Second)
   569  		endTime   = startTime.Add(defaultMinStakingDuration)
   570  		nodeID    = genesistest.DefaultNodeIDs[0]
   571  	)
   572  
   573  	// create valid tx
   574  	// note that [startTime, endTime] is a subset of time that keys[0]
   575  	// validates primary network ([genesistest.DefaultValidatorStartTime, genesistest.DefaultValidatorEndTime])
   576  	tx, err := wallet.IssueAddSubnetValidatorTx(
   577  		&txs.SubnetValidator{
   578  			Validator: txs.Validator{
   579  				NodeID: nodeID,
   580  				Start:  uint64(startTime.Unix()),
   581  				End:    uint64(endTime.Unix()),
   582  				Wght:   genesistest.DefaultValidatorWeight,
   583  			},
   584  			Subnet: testSubnet1.ID(),
   585  		},
   586  	)
   587  	require.NoError(err)
   588  
   589  	// trigger block creation
   590  	vm.ctx.Lock.Unlock()
   591  	require.NoError(vm.issueTxFromRPC(tx))
   592  	vm.ctx.Lock.Lock()
   593  
   594  	blk, err := vm.Builder.BuildBlock(context.Background())
   595  	require.NoError(err)
   596  
   597  	require.NoError(blk.Verify(context.Background()))
   598  	require.NoError(blk.Reject(context.Background()))
   599  
   600  	_, _, err = vm.state.GetTx(tx.ID())
   601  	require.ErrorIs(err, database.ErrNotFound)
   602  
   603  	// Verify that new validator NOT in validator set
   604  	_, err = vm.state.GetCurrentValidator(testSubnet1.ID(), nodeID)
   605  	require.ErrorIs(err, database.ErrNotFound)
   606  }
   607  
   608  // Test case where primary network validator rewarded
   609  func TestRewardValidatorAccept(t *testing.T) {
   610  	require := require.New(t)
   611  	vm, _, _ := defaultVM(t, upgradetest.Latest)
   612  	vm.ctx.Lock.Lock()
   613  	defer vm.ctx.Lock.Unlock()
   614  
   615  	// Fast forward clock to time for genesis validators to leave
   616  	vm.clock.Set(genesistest.DefaultValidatorEndTime)
   617  
   618  	// Advance time and create proposal to reward a genesis validator
   619  	blk, err := vm.Builder.BuildBlock(context.Background())
   620  	require.NoError(err)
   621  	require.NoError(blk.Verify(context.Background()))
   622  
   623  	// Assert preferences are correct
   624  	options, err := blk.(smcon.OracleBlock).Options(context.Background())
   625  	require.NoError(err)
   626  
   627  	commit := options[0].(*blockexecutor.Block)
   628  	require.IsType(&block.BanffCommitBlock{}, commit.Block)
   629  	abort := options[1].(*blockexecutor.Block)
   630  	require.IsType(&block.BanffAbortBlock{}, abort.Block)
   631  
   632  	// Assert block tries to reward a genesis validator
   633  	rewardTx := blk.(block.Block).Txs()[0].Unsigned
   634  	require.IsType(&txs.RewardValidatorTx{}, rewardTx)
   635  
   636  	// Verify options and accept commmit block
   637  	require.NoError(commit.Verify(context.Background()))
   638  	require.NoError(abort.Verify(context.Background()))
   639  	txID := blk.(block.Block).Txs()[0].ID()
   640  	{
   641  		onAbort, ok := vm.manager.GetState(abort.ID())
   642  		require.True(ok)
   643  
   644  		_, txStatus, err := onAbort.GetTx(txID)
   645  		require.NoError(err)
   646  		require.Equal(status.Aborted, txStatus)
   647  	}
   648  
   649  	require.NoError(blk.Accept(context.Background()))
   650  	require.NoError(commit.Accept(context.Background()))
   651  
   652  	// Verify that chain's timestamp has advanced
   653  	timestamp := vm.state.GetTimestamp()
   654  	require.Equal(genesistest.DefaultValidatorEndTimeUnix, uint64(timestamp.Unix()))
   655  
   656  	// Verify that rewarded validator has been removed.
   657  	// Note that test genesis has multiple validators
   658  	// terminating at the same time. The rewarded validator
   659  	// will the first by txID. To make the test more stable
   660  	// (txID changes every time we change any parameter
   661  	// of the tx creating the validator), we explicitly
   662  	//  check that rewarded validator is removed from staker set.
   663  	_, txStatus, err := vm.state.GetTx(txID)
   664  	require.NoError(err)
   665  	require.Equal(status.Committed, txStatus)
   666  
   667  	tx, _, err := vm.state.GetTx(rewardTx.(*txs.RewardValidatorTx).TxID)
   668  	require.NoError(err)
   669  	require.IsType(&txs.AddValidatorTx{}, tx.Unsigned)
   670  
   671  	valTx, _ := tx.Unsigned.(*txs.AddValidatorTx)
   672  	_, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, valTx.NodeID())
   673  	require.ErrorIs(err, database.ErrNotFound)
   674  }
   675  
   676  // Test case where primary network validator not rewarded
   677  func TestRewardValidatorReject(t *testing.T) {
   678  	require := require.New(t)
   679  	vm, _, _ := defaultVM(t, upgradetest.Latest)
   680  	vm.ctx.Lock.Lock()
   681  	defer vm.ctx.Lock.Unlock()
   682  
   683  	// Fast forward clock to time for genesis validators to leave
   684  	vm.clock.Set(genesistest.DefaultValidatorEndTime)
   685  
   686  	// Advance time and create proposal to reward a genesis validator
   687  	blk, err := vm.Builder.BuildBlock(context.Background())
   688  	require.NoError(err)
   689  	require.NoError(blk.Verify(context.Background()))
   690  
   691  	// Assert preferences are correct
   692  	oracleBlk := blk.(smcon.OracleBlock)
   693  	options, err := oracleBlk.Options(context.Background())
   694  	require.NoError(err)
   695  
   696  	commit := options[0].(*blockexecutor.Block)
   697  	require.IsType(&block.BanffCommitBlock{}, commit.Block)
   698  
   699  	abort := options[1].(*blockexecutor.Block)
   700  	require.IsType(&block.BanffAbortBlock{}, abort.Block)
   701  
   702  	// Assert block tries to reward a genesis validator
   703  	rewardTx := oracleBlk.(block.Block).Txs()[0].Unsigned
   704  	require.IsType(&txs.RewardValidatorTx{}, rewardTx)
   705  
   706  	// Verify options and accept abort block
   707  	require.NoError(commit.Verify(context.Background()))
   708  	require.NoError(abort.Verify(context.Background()))
   709  	txID := blk.(block.Block).Txs()[0].ID()
   710  	{
   711  		onAccept, ok := vm.manager.GetState(commit.ID())
   712  		require.True(ok)
   713  
   714  		_, txStatus, err := onAccept.GetTx(txID)
   715  		require.NoError(err)
   716  		require.Equal(status.Committed, txStatus)
   717  	}
   718  
   719  	require.NoError(blk.Accept(context.Background()))
   720  	require.NoError(abort.Accept(context.Background()))
   721  
   722  	// Verify that chain's timestamp has advanced
   723  	timestamp := vm.state.GetTimestamp()
   724  	require.Equal(genesistest.DefaultValidatorEndTimeUnix, uint64(timestamp.Unix()))
   725  
   726  	// Verify that rewarded validator has been removed.
   727  	// Note that test genesis has multiple validators
   728  	// terminating at the same time. The rewarded validator
   729  	// will the first by txID. To make the test more stable
   730  	// (txID changes every time we change any parameter
   731  	// of the tx creating the validator), we explicitly
   732  	//  check that rewarded validator is removed from staker set.
   733  	_, txStatus, err := vm.state.GetTx(txID)
   734  	require.NoError(err)
   735  	require.Equal(status.Aborted, txStatus)
   736  
   737  	tx, _, err := vm.state.GetTx(rewardTx.(*txs.RewardValidatorTx).TxID)
   738  	require.NoError(err)
   739  	require.IsType(&txs.AddValidatorTx{}, tx.Unsigned)
   740  
   741  	valTx, _ := tx.Unsigned.(*txs.AddValidatorTx)
   742  	_, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, valTx.NodeID())
   743  	require.ErrorIs(err, database.ErrNotFound)
   744  }
   745  
   746  // Ensure BuildBlock errors when there is no block to build
   747  func TestUnneededBuildBlock(t *testing.T) {
   748  	require := require.New(t)
   749  	vm, _, _ := defaultVM(t, upgradetest.Latest)
   750  	vm.ctx.Lock.Lock()
   751  	defer vm.ctx.Lock.Unlock()
   752  
   753  	_, err := vm.Builder.BuildBlock(context.Background())
   754  	require.ErrorIs(err, blockbuilder.ErrNoPendingBlocks)
   755  }
   756  
   757  // test acceptance of proposal to create a new chain
   758  func TestCreateChain(t *testing.T) {
   759  	require := require.New(t)
   760  	vm, _, _ := defaultVM(t, upgradetest.Latest)
   761  	vm.ctx.Lock.Lock()
   762  	defer vm.ctx.Lock.Unlock()
   763  
   764  	subnetID := testSubnet1.ID()
   765  	wallet := newWallet(t, vm, walletConfig{
   766  		subnetIDs: []ids.ID{subnetID},
   767  	})
   768  
   769  	tx, err := wallet.IssueCreateChainTx(
   770  		subnetID,
   771  		nil,
   772  		ids.ID{'t', 'e', 's', 't', 'v', 'm'},
   773  		nil,
   774  		"name",
   775  	)
   776  	require.NoError(err)
   777  
   778  	vm.ctx.Lock.Unlock()
   779  	require.NoError(vm.issueTxFromRPC(tx))
   780  	vm.ctx.Lock.Lock()
   781  	require.NoError(buildAndAcceptStandardBlock(vm))
   782  
   783  	_, txStatus, err := vm.state.GetTx(tx.ID())
   784  	require.NoError(err)
   785  	require.Equal(status.Committed, txStatus)
   786  
   787  	// Verify chain was created
   788  	chains, err := vm.state.GetChains(subnetID)
   789  	require.NoError(err)
   790  
   791  	foundNewChain := false
   792  	for _, chain := range chains {
   793  		if bytes.Equal(chain.Bytes(), tx.Bytes()) {
   794  			foundNewChain = true
   795  		}
   796  	}
   797  	require.True(foundNewChain)
   798  }
   799  
   800  // test where we:
   801  // 1) Create a subnet
   802  // 2) Add a validator to the subnet's current validator set
   803  // 3) Advance timestamp to validator's end time (removing validator from current)
   804  func TestCreateSubnet(t *testing.T) {
   805  	require := require.New(t)
   806  	vm, _, _ := defaultVM(t, upgradetest.Latest)
   807  	vm.ctx.Lock.Lock()
   808  	defer vm.ctx.Lock.Unlock()
   809  
   810  	wallet := newWallet(t, vm, walletConfig{})
   811  	createSubnetTx, err := wallet.IssueCreateSubnetTx(
   812  		&secp256k1fx.OutputOwners{
   813  			Threshold: 1,
   814  			Addrs: []ids.ShortID{
   815  				genesistest.DefaultFundedKeys[0].Address(),
   816  				genesistest.DefaultFundedKeys[1].Address(),
   817  			},
   818  		},
   819  	)
   820  	require.NoError(err)
   821  
   822  	vm.ctx.Lock.Unlock()
   823  	require.NoError(vm.issueTxFromRPC(createSubnetTx))
   824  	vm.ctx.Lock.Lock()
   825  	require.NoError(buildAndAcceptStandardBlock(vm))
   826  
   827  	subnetID := createSubnetTx.ID()
   828  	_, txStatus, err := vm.state.GetTx(subnetID)
   829  	require.NoError(err)
   830  	require.Equal(status.Committed, txStatus)
   831  
   832  	subnetIDs, err := vm.state.GetSubnetIDs()
   833  	require.NoError(err)
   834  	require.Contains(subnetIDs, subnetID)
   835  
   836  	// Now that we've created a new subnet, add a validator to that subnet
   837  	nodeID := genesistest.DefaultNodeIDs[0]
   838  	startTime := vm.clock.Time().Add(txexecutor.SyncBound).Add(1 * time.Second)
   839  	endTime := startTime.Add(defaultMinStakingDuration)
   840  	// [startTime, endTime] is subset of time keys[0] validates default subnet so tx is valid
   841  	addValidatorTx, err := wallet.IssueAddSubnetValidatorTx(
   842  		&txs.SubnetValidator{
   843  			Validator: txs.Validator{
   844  				NodeID: nodeID,
   845  				Start:  uint64(startTime.Unix()),
   846  				End:    uint64(endTime.Unix()),
   847  				Wght:   genesistest.DefaultValidatorWeight,
   848  			},
   849  			Subnet: subnetID,
   850  		},
   851  	)
   852  	require.NoError(err)
   853  
   854  	vm.ctx.Lock.Unlock()
   855  	require.NoError(vm.issueTxFromRPC(addValidatorTx))
   856  	vm.ctx.Lock.Lock()
   857  	require.NoError(buildAndAcceptStandardBlock(vm))
   858  
   859  	txID := addValidatorTx.ID()
   860  	_, txStatus, err = vm.state.GetTx(txID)
   861  	require.NoError(err)
   862  	require.Equal(status.Committed, txStatus)
   863  
   864  	_, err = vm.state.GetPendingValidator(subnetID, nodeID)
   865  	require.ErrorIs(err, database.ErrNotFound)
   866  
   867  	_, err = vm.state.GetCurrentValidator(subnetID, nodeID)
   868  	require.NoError(err)
   869  
   870  	// remove validator from current validator set
   871  	vm.clock.Set(endTime)
   872  	require.NoError(buildAndAcceptStandardBlock(vm))
   873  
   874  	_, err = vm.state.GetPendingValidator(subnetID, nodeID)
   875  	require.ErrorIs(err, database.ErrNotFound)
   876  
   877  	_, err = vm.state.GetCurrentValidator(subnetID, nodeID)
   878  	require.ErrorIs(err, database.ErrNotFound)
   879  }
   880  
   881  // test asset import
   882  func TestAtomicImport(t *testing.T) {
   883  	require := require.New(t)
   884  	vm, baseDB, mutableSharedMemory := defaultVM(t, upgradetest.Latest)
   885  	vm.ctx.Lock.Lock()
   886  	defer vm.ctx.Lock.Unlock()
   887  
   888  	recipientKey := genesistest.DefaultFundedKeys[1]
   889  	importOwners := &secp256k1fx.OutputOwners{
   890  		Threshold: 1,
   891  		Addrs:     []ids.ShortID{recipientKey.Address()},
   892  	}
   893  
   894  	m := atomic.NewMemory(prefixdb.New([]byte{5}, baseDB))
   895  	mutableSharedMemory.SharedMemory = m.NewSharedMemory(vm.ctx.ChainID)
   896  
   897  	wallet := newWallet(t, vm, walletConfig{})
   898  	_, err := wallet.IssueImportTx(
   899  		vm.ctx.XChainID,
   900  		importOwners,
   901  	)
   902  	require.ErrorIs(err, walletbuilder.ErrInsufficientFunds)
   903  
   904  	// Provide the avm UTXO
   905  	peerSharedMemory := m.NewSharedMemory(vm.ctx.XChainID)
   906  	utxoID := avax.UTXOID{
   907  		TxID:        ids.GenerateTestID(),
   908  		OutputIndex: 1,
   909  	}
   910  	utxo := &avax.UTXO{
   911  		UTXOID: utxoID,
   912  		Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
   913  		Out: &secp256k1fx.TransferOutput{
   914  			Amt:          50 * units.MicroAvax,
   915  			OutputOwners: *importOwners,
   916  		},
   917  	}
   918  	utxoBytes, err := txs.Codec.Marshal(txs.CodecVersion, utxo)
   919  	require.NoError(err)
   920  
   921  	inputID := utxo.InputID()
   922  	require.NoError(peerSharedMemory.Apply(map[ids.ID]*atomic.Requests{
   923  		vm.ctx.ChainID: {
   924  			PutRequests: []*atomic.Element{
   925  				{
   926  					Key:   inputID[:],
   927  					Value: utxoBytes,
   928  					Traits: [][]byte{
   929  						recipientKey.Address().Bytes(),
   930  					},
   931  				},
   932  			},
   933  		},
   934  	}))
   935  
   936  	// The wallet must be re-loaded because the shared memory has changed
   937  	wallet = newWallet(t, vm, walletConfig{})
   938  	tx, err := wallet.IssueImportTx(
   939  		vm.ctx.XChainID,
   940  		importOwners,
   941  	)
   942  	require.NoError(err)
   943  
   944  	vm.ctx.Lock.Unlock()
   945  	require.NoError(vm.issueTxFromRPC(tx))
   946  	vm.ctx.Lock.Lock()
   947  	require.NoError(buildAndAcceptStandardBlock(vm))
   948  
   949  	_, txStatus, err := vm.state.GetTx(tx.ID())
   950  	require.NoError(err)
   951  	require.Equal(status.Committed, txStatus)
   952  
   953  	inputID = utxoID.InputID()
   954  	_, err = vm.ctx.SharedMemory.Get(vm.ctx.XChainID, [][]byte{inputID[:]})
   955  	require.ErrorIs(err, database.ErrNotFound)
   956  }
   957  
   958  // test optimistic asset import
   959  func TestOptimisticAtomicImport(t *testing.T) {
   960  	require := require.New(t)
   961  	vm, _, _ := defaultVM(t, upgradetest.ApricotPhase3)
   962  	vm.ctx.Lock.Lock()
   963  	defer vm.ctx.Lock.Unlock()
   964  
   965  	tx := &txs.Tx{Unsigned: &txs.ImportTx{
   966  		BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
   967  			NetworkID:    vm.ctx.NetworkID,
   968  			BlockchainID: vm.ctx.ChainID,
   969  		}},
   970  		SourceChain: vm.ctx.XChainID,
   971  		ImportedInputs: []*avax.TransferableInput{{
   972  			UTXOID: avax.UTXOID{
   973  				TxID:        ids.Empty.Prefix(1),
   974  				OutputIndex: 1,
   975  			},
   976  			Asset: avax.Asset{ID: vm.ctx.AVAXAssetID},
   977  			In: &secp256k1fx.TransferInput{
   978  				Amt: 50000,
   979  			},
   980  		}},
   981  	}}
   982  	require.NoError(tx.Initialize(txs.Codec))
   983  
   984  	preferredID := vm.manager.Preferred()
   985  	preferred, err := vm.manager.GetBlock(preferredID)
   986  	require.NoError(err)
   987  	preferredHeight := preferred.Height()
   988  
   989  	statelessBlk, err := block.NewApricotAtomicBlock(
   990  		preferredID,
   991  		preferredHeight+1,
   992  		tx,
   993  	)
   994  	require.NoError(err)
   995  
   996  	blk := vm.manager.NewBlock(statelessBlk)
   997  
   998  	err = blk.Verify(context.Background())
   999  	require.ErrorIs(err, database.ErrNotFound) // erred due to missing shared memory UTXOs
  1000  
  1001  	require.NoError(vm.SetState(context.Background(), snow.Bootstrapping))
  1002  
  1003  	require.NoError(blk.Verify(context.Background())) // skips shared memory UTXO verification during bootstrapping
  1004  
  1005  	require.NoError(blk.Accept(context.Background()))
  1006  
  1007  	require.NoError(vm.SetState(context.Background(), snow.NormalOp))
  1008  
  1009  	_, txStatus, err := vm.state.GetTx(tx.ID())
  1010  	require.NoError(err)
  1011  
  1012  	require.Equal(status.Committed, txStatus)
  1013  }
  1014  
  1015  // test restarting the node
  1016  func TestRestartFullyAccepted(t *testing.T) {
  1017  	require := require.New(t)
  1018  	db := memdb.New()
  1019  
  1020  	firstDB := prefixdb.New([]byte{}, db)
  1021  	firstVM := &VM{Config: config.Config{
  1022  		Chains:                 chains.TestManager,
  1023  		Validators:             validators.NewManager(),
  1024  		UptimeLockedCalculator: uptime.NewLockedCalculator(),
  1025  		MinStakeDuration:       defaultMinStakingDuration,
  1026  		MaxStakeDuration:       defaultMaxStakingDuration,
  1027  		RewardConfig:           defaultRewardConfig,
  1028  		UpgradeConfig:          upgradetest.GetConfigWithUpgradeTime(upgradetest.Durango, latestForkTime),
  1029  	}}
  1030  
  1031  	firstCtx := snowtest.Context(t, snowtest.PChainID)
  1032  
  1033  	genesisBytes := genesistest.NewBytes(t, genesistest.Config{})
  1034  
  1035  	baseDB := memdb.New()
  1036  	atomicDB := prefixdb.New([]byte{1}, baseDB)
  1037  	m := atomic.NewMemory(atomicDB)
  1038  	firstCtx.SharedMemory = m.NewSharedMemory(firstCtx.ChainID)
  1039  
  1040  	initialClkTime := latestForkTime.Add(time.Second)
  1041  	firstVM.clock.Set(initialClkTime)
  1042  	firstCtx.Lock.Lock()
  1043  
  1044  	firstMsgChan := make(chan common.Message, 1)
  1045  	require.NoError(firstVM.Initialize(
  1046  		context.Background(),
  1047  		firstCtx,
  1048  		firstDB,
  1049  		genesisBytes,
  1050  		nil,
  1051  		nil,
  1052  		firstMsgChan,
  1053  		nil,
  1054  		nil,
  1055  	))
  1056  
  1057  	genesisID, err := firstVM.LastAccepted(context.Background())
  1058  	require.NoError(err)
  1059  
  1060  	// include a tx to make the block be accepted
  1061  	tx := &txs.Tx{Unsigned: &txs.ImportTx{
  1062  		BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
  1063  			NetworkID:    firstVM.ctx.NetworkID,
  1064  			BlockchainID: firstVM.ctx.ChainID,
  1065  		}},
  1066  		SourceChain: firstVM.ctx.XChainID,
  1067  		ImportedInputs: []*avax.TransferableInput{{
  1068  			UTXOID: avax.UTXOID{
  1069  				TxID:        ids.Empty.Prefix(1),
  1070  				OutputIndex: 1,
  1071  			},
  1072  			Asset: avax.Asset{ID: firstVM.ctx.AVAXAssetID},
  1073  			In: &secp256k1fx.TransferInput{
  1074  				Amt: 50000,
  1075  			},
  1076  		}},
  1077  	}}
  1078  	require.NoError(tx.Initialize(txs.Codec))
  1079  
  1080  	nextChainTime := initialClkTime.Add(time.Second)
  1081  	firstVM.clock.Set(initialClkTime)
  1082  
  1083  	preferredID := firstVM.manager.Preferred()
  1084  	preferred, err := firstVM.manager.GetBlock(preferredID)
  1085  	require.NoError(err)
  1086  	preferredHeight := preferred.Height()
  1087  
  1088  	statelessBlk, err := block.NewBanffStandardBlock(
  1089  		nextChainTime,
  1090  		preferredID,
  1091  		preferredHeight+1,
  1092  		[]*txs.Tx{tx},
  1093  	)
  1094  	require.NoError(err)
  1095  
  1096  	firstAdvanceTimeBlk := firstVM.manager.NewBlock(statelessBlk)
  1097  
  1098  	nextChainTime = nextChainTime.Add(2 * time.Second)
  1099  	firstVM.clock.Set(nextChainTime)
  1100  	require.NoError(firstAdvanceTimeBlk.Verify(context.Background()))
  1101  	require.NoError(firstAdvanceTimeBlk.Accept(context.Background()))
  1102  
  1103  	require.NoError(firstVM.Shutdown(context.Background()))
  1104  	firstCtx.Lock.Unlock()
  1105  
  1106  	secondVM := &VM{Config: config.Config{
  1107  		Chains:                 chains.TestManager,
  1108  		Validators:             validators.NewManager(),
  1109  		UptimeLockedCalculator: uptime.NewLockedCalculator(),
  1110  		MinStakeDuration:       defaultMinStakingDuration,
  1111  		MaxStakeDuration:       defaultMaxStakingDuration,
  1112  		RewardConfig:           defaultRewardConfig,
  1113  		UpgradeConfig:          upgradetest.GetConfigWithUpgradeTime(upgradetest.Durango, latestForkTime),
  1114  	}}
  1115  
  1116  	secondCtx := snowtest.Context(t, snowtest.PChainID)
  1117  	secondCtx.SharedMemory = firstCtx.SharedMemory
  1118  	secondVM.clock.Set(initialClkTime)
  1119  	secondCtx.Lock.Lock()
  1120  	defer func() {
  1121  		require.NoError(secondVM.Shutdown(context.Background()))
  1122  		secondCtx.Lock.Unlock()
  1123  	}()
  1124  
  1125  	secondDB := prefixdb.New([]byte{}, db)
  1126  	secondMsgChan := make(chan common.Message, 1)
  1127  	require.NoError(secondVM.Initialize(
  1128  		context.Background(),
  1129  		secondCtx,
  1130  		secondDB,
  1131  		genesisBytes,
  1132  		nil,
  1133  		nil,
  1134  		secondMsgChan,
  1135  		nil,
  1136  		nil,
  1137  	))
  1138  
  1139  	lastAccepted, err := secondVM.LastAccepted(context.Background())
  1140  	require.NoError(err)
  1141  	require.Equal(genesisID, lastAccepted)
  1142  }
  1143  
  1144  // test bootstrapping the node
  1145  func TestBootstrapPartiallyAccepted(t *testing.T) {
  1146  	require := require.New(t)
  1147  
  1148  	baseDB := memdb.New()
  1149  	vmDB := prefixdb.New(chains.VMDBPrefix, baseDB)
  1150  	bootstrappingDB := prefixdb.New(chains.ChainBootstrappingDBPrefix, baseDB)
  1151  
  1152  	vm := &VM{Config: config.Config{
  1153  		Chains:                 chains.TestManager,
  1154  		Validators:             validators.NewManager(),
  1155  		UptimeLockedCalculator: uptime.NewLockedCalculator(),
  1156  		MinStakeDuration:       defaultMinStakingDuration,
  1157  		MaxStakeDuration:       defaultMaxStakingDuration,
  1158  		RewardConfig:           defaultRewardConfig,
  1159  		UpgradeConfig:          upgradetest.GetConfigWithUpgradeTime(upgradetest.Durango, latestForkTime),
  1160  	}}
  1161  
  1162  	initialClkTime := latestForkTime.Add(time.Second)
  1163  	vm.clock.Set(initialClkTime)
  1164  	ctx := snowtest.Context(t, snowtest.PChainID)
  1165  
  1166  	atomicDB := prefixdb.New([]byte{1}, baseDB)
  1167  	m := atomic.NewMemory(atomicDB)
  1168  	ctx.SharedMemory = m.NewSharedMemory(ctx.ChainID)
  1169  
  1170  	consensusCtx := snowtest.ConsensusContext(ctx)
  1171  	ctx.Lock.Lock()
  1172  
  1173  	msgChan := make(chan common.Message, 1)
  1174  	require.NoError(vm.Initialize(
  1175  		context.Background(),
  1176  		ctx,
  1177  		vmDB,
  1178  		genesistest.NewBytes(t, genesistest.Config{}),
  1179  		nil,
  1180  		nil,
  1181  		msgChan,
  1182  		nil,
  1183  		nil,
  1184  	))
  1185  
  1186  	// include a tx to make the block be accepted
  1187  	tx := &txs.Tx{Unsigned: &txs.ImportTx{
  1188  		BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
  1189  			NetworkID:    vm.ctx.NetworkID,
  1190  			BlockchainID: vm.ctx.ChainID,
  1191  		}},
  1192  		SourceChain: vm.ctx.XChainID,
  1193  		ImportedInputs: []*avax.TransferableInput{{
  1194  			UTXOID: avax.UTXOID{
  1195  				TxID:        ids.Empty.Prefix(1),
  1196  				OutputIndex: 1,
  1197  			},
  1198  			Asset: avax.Asset{ID: vm.ctx.AVAXAssetID},
  1199  			In: &secp256k1fx.TransferInput{
  1200  				Amt: 50000,
  1201  			},
  1202  		}},
  1203  	}}
  1204  	require.NoError(tx.Initialize(txs.Codec))
  1205  
  1206  	nextChainTime := initialClkTime.Add(time.Second)
  1207  
  1208  	preferredID := vm.manager.Preferred()
  1209  	preferred, err := vm.manager.GetBlock(preferredID)
  1210  	require.NoError(err)
  1211  	preferredHeight := preferred.Height()
  1212  
  1213  	statelessBlk, err := block.NewBanffStandardBlock(
  1214  		nextChainTime,
  1215  		preferredID,
  1216  		preferredHeight+1,
  1217  		[]*txs.Tx{tx},
  1218  	)
  1219  	require.NoError(err)
  1220  
  1221  	advanceTimeBlk := vm.manager.NewBlock(statelessBlk)
  1222  	require.NoError(err)
  1223  
  1224  	advanceTimeBlkID := advanceTimeBlk.ID()
  1225  	advanceTimeBlkBytes := advanceTimeBlk.Bytes()
  1226  
  1227  	peerID := ids.BuildTestNodeID([]byte{1, 2, 3, 4, 5, 4, 3, 2, 1})
  1228  	beacons := validators.NewManager()
  1229  	require.NoError(beacons.AddStaker(ctx.SubnetID, peerID, nil, ids.Empty, 1))
  1230  
  1231  	benchlist := benchlist.NewNoBenchlist()
  1232  	timeoutManager, err := timeout.NewManager(
  1233  		&timer.AdaptiveTimeoutConfig{
  1234  			InitialTimeout:     time.Millisecond,
  1235  			MinimumTimeout:     time.Millisecond,
  1236  			MaximumTimeout:     10 * time.Second,
  1237  			TimeoutHalflife:    5 * time.Minute,
  1238  			TimeoutCoefficient: 1.25,
  1239  		},
  1240  		benchlist,
  1241  		prometheus.NewRegistry(),
  1242  		prometheus.NewRegistry(),
  1243  	)
  1244  	require.NoError(err)
  1245  
  1246  	go timeoutManager.Dispatch()
  1247  	defer timeoutManager.Stop()
  1248  
  1249  	chainRouter := &router.ChainRouter{}
  1250  
  1251  	metrics := prometheus.NewRegistry()
  1252  	mc, err := message.NewCreator(logging.NoLog{}, metrics, constants.DefaultNetworkCompressionType, 10*time.Second)
  1253  	require.NoError(err)
  1254  
  1255  	require.NoError(chainRouter.Initialize(
  1256  		ids.EmptyNodeID,
  1257  		logging.NoLog{},
  1258  		timeoutManager,
  1259  		time.Second,
  1260  		set.Set[ids.ID]{},
  1261  		true,
  1262  		set.Set[ids.ID]{},
  1263  		nil,
  1264  		router.HealthConfig{},
  1265  		prometheus.NewRegistry(),
  1266  	))
  1267  
  1268  	externalSender := &sendertest.External{TB: t}
  1269  	externalSender.Default(true)
  1270  
  1271  	// Passes messages from the consensus engine to the network
  1272  	sender, err := sender.New(
  1273  		consensusCtx,
  1274  		mc,
  1275  		externalSender,
  1276  		chainRouter,
  1277  		timeoutManager,
  1278  		p2ppb.EngineType_ENGINE_TYPE_SNOWMAN,
  1279  		subnets.New(consensusCtx.NodeID, subnets.Config{}),
  1280  		prometheus.NewRegistry(),
  1281  	)
  1282  	require.NoError(err)
  1283  
  1284  	isBootstrapped := false
  1285  	bootstrapTracker := &enginetest.BootstrapTracker{
  1286  		T: t,
  1287  		IsBootstrappedF: func() bool {
  1288  			return isBootstrapped
  1289  		},
  1290  		BootstrappedF: func(ids.ID) {
  1291  			isBootstrapped = true
  1292  		},
  1293  	}
  1294  
  1295  	peers := tracker.NewPeers()
  1296  	totalWeight, err := beacons.TotalWeight(ctx.SubnetID)
  1297  	require.NoError(err)
  1298  	startup := tracker.NewStartup(peers, (totalWeight+1)/2)
  1299  	beacons.RegisterSetCallbackListener(ctx.SubnetID, startup)
  1300  
  1301  	// The engine handles consensus
  1302  	snowGetHandler, err := snowgetter.New(
  1303  		vm,
  1304  		sender,
  1305  		consensusCtx.Log,
  1306  		time.Second,
  1307  		2000,
  1308  		consensusCtx.Registerer,
  1309  	)
  1310  	require.NoError(err)
  1311  
  1312  	peerTracker, err := p2p.NewPeerTracker(
  1313  		ctx.Log,
  1314  		"peer_tracker",
  1315  		consensusCtx.Registerer,
  1316  		set.Of(ctx.NodeID),
  1317  		nil,
  1318  	)
  1319  	require.NoError(err)
  1320  
  1321  	bootstrapConfig := bootstrap.Config{
  1322  		NonVerifyingParse:              vm.ParseBlock,
  1323  		AllGetsServer:                  snowGetHandler,
  1324  		Ctx:                            consensusCtx,
  1325  		Beacons:                        beacons,
  1326  		SampleK:                        beacons.Count(ctx.SubnetID),
  1327  		StartupTracker:                 startup,
  1328  		PeerTracker:                    peerTracker,
  1329  		Sender:                         sender,
  1330  		BootstrapTracker:               bootstrapTracker,
  1331  		AncestorsMaxContainersReceived: 2000,
  1332  		DB:                             bootstrappingDB,
  1333  		VM:                             vm,
  1334  	}
  1335  
  1336  	// Asynchronously passes messages from the network to the consensus engine
  1337  	cpuTracker, err := timetracker.NewResourceTracker(
  1338  		prometheus.NewRegistry(),
  1339  		resource.NoUsage,
  1340  		meter.ContinuousFactory{},
  1341  		time.Second,
  1342  	)
  1343  	require.NoError(err)
  1344  
  1345  	h, err := handler.New(
  1346  		bootstrapConfig.Ctx,
  1347  		beacons,
  1348  		msgChan,
  1349  		time.Hour,
  1350  		2,
  1351  		cpuTracker,
  1352  		vm,
  1353  		subnets.New(ctx.NodeID, subnets.Config{}),
  1354  		tracker.NewPeers(),
  1355  		peerTracker,
  1356  		prometheus.NewRegistry(),
  1357  	)
  1358  	require.NoError(err)
  1359  
  1360  	engineConfig := smeng.Config{
  1361  		Ctx:           bootstrapConfig.Ctx,
  1362  		AllGetsServer: snowGetHandler,
  1363  		VM:            bootstrapConfig.VM,
  1364  		Sender:        bootstrapConfig.Sender,
  1365  		Validators:    beacons,
  1366  		Params: snowball.Parameters{
  1367  			K:                     1,
  1368  			AlphaPreference:       1,
  1369  			AlphaConfidence:       1,
  1370  			Beta:                  20,
  1371  			ConcurrentRepolls:     1,
  1372  			OptimalProcessing:     1,
  1373  			MaxOutstandingItems:   1,
  1374  			MaxItemProcessingTime: 1,
  1375  		},
  1376  		Consensus: &smcon.Topological{},
  1377  	}
  1378  	engine, err := smeng.New(engineConfig)
  1379  	require.NoError(err)
  1380  
  1381  	bootstrapper, err := bootstrap.New(
  1382  		bootstrapConfig,
  1383  		engine.Start,
  1384  	)
  1385  	require.NoError(err)
  1386  
  1387  	h.SetEngineManager(&handler.EngineManager{
  1388  		Avalanche: &handler.Engine{
  1389  			StateSyncer:  nil,
  1390  			Bootstrapper: bootstrapper,
  1391  			Consensus:    engine,
  1392  		},
  1393  		Snowman: &handler.Engine{
  1394  			StateSyncer:  nil,
  1395  			Bootstrapper: bootstrapper,
  1396  			Consensus:    engine,
  1397  		},
  1398  	})
  1399  
  1400  	consensusCtx.State.Set(snow.EngineState{
  1401  		Type:  p2ppb.EngineType_ENGINE_TYPE_SNOWMAN,
  1402  		State: snow.NormalOp,
  1403  	})
  1404  
  1405  	// Allow incoming messages to be routed to the new chain
  1406  	chainRouter.AddChain(context.Background(), h)
  1407  	ctx.Lock.Unlock()
  1408  
  1409  	h.Start(context.Background(), false)
  1410  
  1411  	ctx.Lock.Lock()
  1412  	var reqID uint32
  1413  	externalSender.SendF = func(msg message.OutboundMessage, config common.SendConfig, _ ids.ID, _ subnets.Allower) set.Set[ids.NodeID] {
  1414  		inMsg, err := mc.Parse(msg.Bytes(), ctx.NodeID, func() {})
  1415  		require.NoError(err)
  1416  		require.Equal(message.GetAcceptedFrontierOp, inMsg.Op())
  1417  
  1418  		requestID, ok := message.GetRequestID(inMsg.Message())
  1419  		require.True(ok)
  1420  
  1421  		reqID = requestID
  1422  		return config.NodeIDs
  1423  	}
  1424  
  1425  	peerTracker.Connected(peerID, version.CurrentApp)
  1426  	require.NoError(bootstrapper.Connected(context.Background(), peerID, version.CurrentApp))
  1427  
  1428  	externalSender.SendF = func(msg message.OutboundMessage, config common.SendConfig, _ ids.ID, _ subnets.Allower) set.Set[ids.NodeID] {
  1429  		inMsgIntf, err := mc.Parse(msg.Bytes(), ctx.NodeID, func() {})
  1430  		require.NoError(err)
  1431  		require.Equal(message.GetAcceptedOp, inMsgIntf.Op())
  1432  		inMsg := inMsgIntf.Message().(*p2ppb.GetAccepted)
  1433  
  1434  		reqID = inMsg.RequestId
  1435  		return config.NodeIDs
  1436  	}
  1437  
  1438  	require.NoError(bootstrapper.AcceptedFrontier(context.Background(), peerID, reqID, advanceTimeBlkID))
  1439  
  1440  	externalSender.SendF = func(msg message.OutboundMessage, config common.SendConfig, _ ids.ID, _ subnets.Allower) set.Set[ids.NodeID] {
  1441  		inMsgIntf, err := mc.Parse(msg.Bytes(), ctx.NodeID, func() {})
  1442  		require.NoError(err)
  1443  		require.Equal(message.GetAncestorsOp, inMsgIntf.Op())
  1444  		inMsg := inMsgIntf.Message().(*p2ppb.GetAncestors)
  1445  
  1446  		reqID = inMsg.RequestId
  1447  
  1448  		containerID, err := ids.ToID(inMsg.ContainerId)
  1449  		require.NoError(err)
  1450  		require.Equal(advanceTimeBlkID, containerID)
  1451  		return config.NodeIDs
  1452  	}
  1453  
  1454  	frontier := set.Of(advanceTimeBlkID)
  1455  	require.NoError(bootstrapper.Accepted(context.Background(), peerID, reqID, frontier))
  1456  
  1457  	externalSender.SendF = func(msg message.OutboundMessage, config common.SendConfig, _ ids.ID, _ subnets.Allower) set.Set[ids.NodeID] {
  1458  		inMsg, err := mc.Parse(msg.Bytes(), ctx.NodeID, func() {})
  1459  		require.NoError(err)
  1460  		require.Equal(message.GetAcceptedFrontierOp, inMsg.Op())
  1461  
  1462  		requestID, ok := message.GetRequestID(inMsg.Message())
  1463  		require.True(ok)
  1464  
  1465  		reqID = requestID
  1466  		return config.NodeIDs
  1467  	}
  1468  
  1469  	require.NoError(bootstrapper.Ancestors(context.Background(), peerID, reqID, [][]byte{advanceTimeBlkBytes}))
  1470  
  1471  	externalSender.SendF = func(msg message.OutboundMessage, config common.SendConfig, _ ids.ID, _ subnets.Allower) set.Set[ids.NodeID] {
  1472  		inMsgIntf, err := mc.Parse(msg.Bytes(), ctx.NodeID, func() {})
  1473  		require.NoError(err)
  1474  		require.Equal(message.GetAcceptedOp, inMsgIntf.Op())
  1475  		inMsg := inMsgIntf.Message().(*p2ppb.GetAccepted)
  1476  
  1477  		reqID = inMsg.RequestId
  1478  		return config.NodeIDs
  1479  	}
  1480  
  1481  	require.NoError(bootstrapper.AcceptedFrontier(context.Background(), peerID, reqID, advanceTimeBlkID))
  1482  
  1483  	externalSender.SendF = nil
  1484  	externalSender.CantSend = false
  1485  
  1486  	require.NoError(bootstrapper.Accepted(context.Background(), peerID, reqID, frontier))
  1487  	require.Equal(advanceTimeBlk.ID(), vm.manager.Preferred())
  1488  
  1489  	ctx.Lock.Unlock()
  1490  	chainRouter.Shutdown(context.Background())
  1491  }
  1492  
  1493  func TestUnverifiedParent(t *testing.T) {
  1494  	require := require.New(t)
  1495  
  1496  	vm := &VM{Config: config.Config{
  1497  		Chains:                 chains.TestManager,
  1498  		Validators:             validators.NewManager(),
  1499  		UptimeLockedCalculator: uptime.NewLockedCalculator(),
  1500  		MinStakeDuration:       defaultMinStakingDuration,
  1501  		MaxStakeDuration:       defaultMaxStakingDuration,
  1502  		RewardConfig:           defaultRewardConfig,
  1503  		UpgradeConfig:          upgradetest.GetConfigWithUpgradeTime(upgradetest.Durango, latestForkTime),
  1504  	}}
  1505  
  1506  	initialClkTime := latestForkTime.Add(time.Second)
  1507  	vm.clock.Set(initialClkTime)
  1508  	ctx := snowtest.Context(t, snowtest.PChainID)
  1509  	ctx.Lock.Lock()
  1510  	defer func() {
  1511  		require.NoError(vm.Shutdown(context.Background()))
  1512  		ctx.Lock.Unlock()
  1513  	}()
  1514  
  1515  	msgChan := make(chan common.Message, 1)
  1516  	require.NoError(vm.Initialize(
  1517  		context.Background(),
  1518  		ctx,
  1519  		memdb.New(),
  1520  		genesistest.NewBytes(t, genesistest.Config{}),
  1521  		nil,
  1522  		nil,
  1523  		msgChan,
  1524  		nil,
  1525  		nil,
  1526  	))
  1527  
  1528  	// include a tx1 to make the block be accepted
  1529  	tx1 := &txs.Tx{Unsigned: &txs.ImportTx{
  1530  		BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
  1531  			NetworkID:    vm.ctx.NetworkID,
  1532  			BlockchainID: vm.ctx.ChainID,
  1533  		}},
  1534  		SourceChain: vm.ctx.XChainID,
  1535  		ImportedInputs: []*avax.TransferableInput{{
  1536  			UTXOID: avax.UTXOID{
  1537  				TxID:        ids.Empty.Prefix(1),
  1538  				OutputIndex: 1,
  1539  			},
  1540  			Asset: avax.Asset{ID: vm.ctx.AVAXAssetID},
  1541  			In: &secp256k1fx.TransferInput{
  1542  				Amt: 50000,
  1543  			},
  1544  		}},
  1545  	}}
  1546  	require.NoError(tx1.Initialize(txs.Codec))
  1547  
  1548  	nextChainTime := initialClkTime.Add(time.Second)
  1549  
  1550  	preferredID := vm.manager.Preferred()
  1551  	preferred, err := vm.manager.GetBlock(preferredID)
  1552  	require.NoError(err)
  1553  	preferredHeight := preferred.Height()
  1554  
  1555  	statelessBlk, err := block.NewBanffStandardBlock(
  1556  		nextChainTime,
  1557  		preferredID,
  1558  		preferredHeight+1,
  1559  		[]*txs.Tx{tx1},
  1560  	)
  1561  	require.NoError(err)
  1562  	firstAdvanceTimeBlk := vm.manager.NewBlock(statelessBlk)
  1563  	require.NoError(firstAdvanceTimeBlk.Verify(context.Background()))
  1564  
  1565  	// include a tx2 to make the block be accepted
  1566  	tx2 := &txs.Tx{Unsigned: &txs.ImportTx{
  1567  		BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
  1568  			NetworkID:    vm.ctx.NetworkID,
  1569  			BlockchainID: vm.ctx.ChainID,
  1570  		}},
  1571  		SourceChain: vm.ctx.XChainID,
  1572  		ImportedInputs: []*avax.TransferableInput{{
  1573  			UTXOID: avax.UTXOID{
  1574  				TxID:        ids.Empty.Prefix(2),
  1575  				OutputIndex: 2,
  1576  			},
  1577  			Asset: avax.Asset{ID: vm.ctx.AVAXAssetID},
  1578  			In: &secp256k1fx.TransferInput{
  1579  				Amt: 50000,
  1580  			},
  1581  		}},
  1582  	}}
  1583  	require.NoError(tx2.Initialize(txs.Codec))
  1584  	nextChainTime = nextChainTime.Add(time.Second)
  1585  	vm.clock.Set(nextChainTime)
  1586  	statelessSecondAdvanceTimeBlk, err := block.NewBanffStandardBlock(
  1587  		nextChainTime,
  1588  		firstAdvanceTimeBlk.ID(),
  1589  		firstAdvanceTimeBlk.Height()+1,
  1590  		[]*txs.Tx{tx2},
  1591  	)
  1592  	require.NoError(err)
  1593  	secondAdvanceTimeBlk := vm.manager.NewBlock(statelessSecondAdvanceTimeBlk)
  1594  
  1595  	require.Equal(secondAdvanceTimeBlk.Parent(), firstAdvanceTimeBlk.ID())
  1596  	require.NoError(secondAdvanceTimeBlk.Verify(context.Background()))
  1597  }
  1598  
  1599  func TestMaxStakeAmount(t *testing.T) {
  1600  	vm, _, _ := defaultVM(t, upgradetest.Latest)
  1601  	vm.ctx.Lock.Lock()
  1602  	defer vm.ctx.Lock.Unlock()
  1603  
  1604  	nodeID := genesistest.DefaultNodeIDs[0]
  1605  
  1606  	tests := []struct {
  1607  		description string
  1608  		startTime   time.Time
  1609  		endTime     time.Time
  1610  	}{
  1611  		{
  1612  			description: "[validator.StartTime] == [startTime] < [endTime] == [validator.EndTime]",
  1613  			startTime:   genesistest.DefaultValidatorStartTime,
  1614  			endTime:     genesistest.DefaultValidatorEndTime,
  1615  		},
  1616  		{
  1617  			description: "[validator.StartTime] < [startTime] < [endTime] == [validator.EndTime]",
  1618  			startTime:   genesistest.DefaultValidatorStartTime.Add(time.Minute),
  1619  			endTime:     genesistest.DefaultValidatorEndTime,
  1620  		},
  1621  		{
  1622  			description: "[validator.StartTime] == [startTime] < [endTime] < [validator.EndTime]",
  1623  			startTime:   genesistest.DefaultValidatorStartTime,
  1624  			endTime:     genesistest.DefaultValidatorEndTime.Add(-time.Minute),
  1625  		},
  1626  		{
  1627  			description: "[validator.StartTime] < [startTime] < [endTime] < [validator.EndTime]",
  1628  			startTime:   genesistest.DefaultValidatorStartTime.Add(time.Minute),
  1629  			endTime:     genesistest.DefaultValidatorEndTime.Add(-time.Minute),
  1630  		},
  1631  	}
  1632  
  1633  	for _, test := range tests {
  1634  		t.Run(test.description, func(t *testing.T) {
  1635  			require := require.New(t)
  1636  			staker, err := txexecutor.GetValidator(vm.state, constants.PrimaryNetworkID, nodeID)
  1637  			require.NoError(err)
  1638  
  1639  			amount, err := txexecutor.GetMaxWeight(vm.state, staker, test.startTime, test.endTime)
  1640  			require.NoError(err)
  1641  			require.Equal(genesistest.DefaultValidatorWeight, amount)
  1642  		})
  1643  	}
  1644  }
  1645  
  1646  func TestUptimeDisallowedWithRestart(t *testing.T) {
  1647  	require := require.New(t)
  1648  	latestForkTime = genesistest.DefaultValidatorStartTime.Add(defaultMinStakingDuration)
  1649  	db := memdb.New()
  1650  
  1651  	firstDB := prefixdb.New([]byte{}, db)
  1652  	const firstUptimePercentage = 20 // 20%
  1653  	firstVM := &VM{Config: config.Config{
  1654  		Chains:                 chains.TestManager,
  1655  		UptimePercentage:       firstUptimePercentage / 100.,
  1656  		RewardConfig:           defaultRewardConfig,
  1657  		Validators:             validators.NewManager(),
  1658  		UptimeLockedCalculator: uptime.NewLockedCalculator(),
  1659  		UpgradeConfig:          upgradetest.GetConfigWithUpgradeTime(upgradetest.Durango, latestForkTime),
  1660  	}}
  1661  
  1662  	firstCtx := snowtest.Context(t, snowtest.PChainID)
  1663  	firstCtx.Lock.Lock()
  1664  
  1665  	genesisBytes := genesistest.NewBytes(t, genesistest.Config{})
  1666  
  1667  	firstMsgChan := make(chan common.Message, 1)
  1668  	require.NoError(firstVM.Initialize(
  1669  		context.Background(),
  1670  		firstCtx,
  1671  		firstDB,
  1672  		genesisBytes,
  1673  		nil,
  1674  		nil,
  1675  		firstMsgChan,
  1676  		nil,
  1677  		nil,
  1678  	))
  1679  
  1680  	initialClkTime := latestForkTime.Add(time.Second)
  1681  	firstVM.clock.Set(initialClkTime)
  1682  
  1683  	// Set VM state to NormalOp, to start tracking validators' uptime
  1684  	require.NoError(firstVM.SetState(context.Background(), snow.Bootstrapping))
  1685  	require.NoError(firstVM.SetState(context.Background(), snow.NormalOp))
  1686  
  1687  	// Fast forward clock so that validators meet 20% uptime required for reward
  1688  	durationForReward := genesistest.DefaultValidatorEndTime.Sub(genesistest.DefaultValidatorStartTime) * firstUptimePercentage / 100
  1689  	vmStopTime := genesistest.DefaultValidatorStartTime.Add(durationForReward)
  1690  	firstVM.clock.Set(vmStopTime)
  1691  
  1692  	// Shutdown VM to stop all genesis validator uptime.
  1693  	// At this point they have been validating for the 20% uptime needed to be rewarded
  1694  	require.NoError(firstVM.Shutdown(context.Background()))
  1695  	firstCtx.Lock.Unlock()
  1696  
  1697  	// Restart the VM with a larger uptime requirement
  1698  	secondDB := prefixdb.New([]byte{}, db)
  1699  	const secondUptimePercentage = 21 // 21% > firstUptimePercentage, so uptime for reward is not met now
  1700  	secondVM := &VM{Config: config.Config{
  1701  		Chains:                 chains.TestManager,
  1702  		UptimePercentage:       secondUptimePercentage / 100.,
  1703  		Validators:             validators.NewManager(),
  1704  		UptimeLockedCalculator: uptime.NewLockedCalculator(),
  1705  		UpgradeConfig:          upgradetest.GetConfigWithUpgradeTime(upgradetest.Durango, latestForkTime),
  1706  	}}
  1707  
  1708  	secondCtx := snowtest.Context(t, snowtest.PChainID)
  1709  	secondCtx.Lock.Lock()
  1710  	defer func() {
  1711  		require.NoError(secondVM.Shutdown(context.Background()))
  1712  		secondCtx.Lock.Unlock()
  1713  	}()
  1714  
  1715  	atomicDB := prefixdb.New([]byte{1}, db)
  1716  	m := atomic.NewMemory(atomicDB)
  1717  	secondCtx.SharedMemory = m.NewSharedMemory(secondCtx.ChainID)
  1718  
  1719  	secondMsgChan := make(chan common.Message, 1)
  1720  	require.NoError(secondVM.Initialize(
  1721  		context.Background(),
  1722  		secondCtx,
  1723  		secondDB,
  1724  		genesisBytes,
  1725  		nil,
  1726  		nil,
  1727  		secondMsgChan,
  1728  		nil,
  1729  		nil,
  1730  	))
  1731  
  1732  	secondVM.clock.Set(vmStopTime)
  1733  
  1734  	// Set VM state to NormalOp, to start tracking validators' uptime
  1735  	require.NoError(secondVM.SetState(context.Background(), snow.Bootstrapping))
  1736  	require.NoError(secondVM.SetState(context.Background(), snow.NormalOp))
  1737  
  1738  	// after restart and change of uptime required for reward, push validators to their end of life
  1739  	secondVM.clock.Set(genesistest.DefaultValidatorEndTime)
  1740  
  1741  	// evaluate a genesis validator for reward
  1742  	blk, err := secondVM.Builder.BuildBlock(context.Background())
  1743  	require.NoError(err)
  1744  	require.NoError(blk.Verify(context.Background()))
  1745  
  1746  	// Assert preferences are correct.
  1747  	// secondVM should prefer abort since uptime requirements are not met anymore
  1748  	oracleBlk := blk.(smcon.OracleBlock)
  1749  	options, err := oracleBlk.Options(context.Background())
  1750  	require.NoError(err)
  1751  
  1752  	abort := options[0].(*blockexecutor.Block)
  1753  	require.IsType(&block.BanffAbortBlock{}, abort.Block)
  1754  
  1755  	commit := options[1].(*blockexecutor.Block)
  1756  	require.IsType(&block.BanffCommitBlock{}, commit.Block)
  1757  
  1758  	// Assert block tries to reward a genesis validator
  1759  	rewardTx := oracleBlk.(block.Block).Txs()[0].Unsigned
  1760  	require.IsType(&txs.RewardValidatorTx{}, rewardTx)
  1761  	txID := blk.(block.Block).Txs()[0].ID()
  1762  
  1763  	// Verify options and accept abort block
  1764  	require.NoError(commit.Verify(context.Background()))
  1765  	require.NoError(abort.Verify(context.Background()))
  1766  	require.NoError(blk.Accept(context.Background()))
  1767  	require.NoError(abort.Accept(context.Background()))
  1768  	require.NoError(secondVM.SetPreference(context.Background(), secondVM.manager.LastAccepted()))
  1769  
  1770  	// Verify that rewarded validator has been removed.
  1771  	// Note that test genesis has multiple validators
  1772  	// terminating at the same time. The rewarded validator
  1773  	// will the first by txID. To make the test more stable
  1774  	// (txID changes every time we change any parameter
  1775  	// of the tx creating the validator), we explicitly
  1776  	//  check that rewarded validator is removed from staker set.
  1777  	_, txStatus, err := secondVM.state.GetTx(txID)
  1778  	require.NoError(err)
  1779  	require.Equal(status.Aborted, txStatus)
  1780  
  1781  	tx, _, err := secondVM.state.GetTx(rewardTx.(*txs.RewardValidatorTx).TxID)
  1782  	require.NoError(err)
  1783  	require.IsType(&txs.AddValidatorTx{}, tx.Unsigned)
  1784  
  1785  	valTx, _ := tx.Unsigned.(*txs.AddValidatorTx)
  1786  	_, err = secondVM.state.GetCurrentValidator(constants.PrimaryNetworkID, valTx.NodeID())
  1787  	require.ErrorIs(err, database.ErrNotFound)
  1788  }
  1789  
  1790  func TestUptimeDisallowedAfterNeverConnecting(t *testing.T) {
  1791  	require := require.New(t)
  1792  	latestForkTime = genesistest.DefaultValidatorStartTime.Add(defaultMinStakingDuration)
  1793  
  1794  	db := memdb.New()
  1795  
  1796  	vm := &VM{Config: config.Config{
  1797  		Chains:                 chains.TestManager,
  1798  		UptimePercentage:       .2,
  1799  		RewardConfig:           defaultRewardConfig,
  1800  		Validators:             validators.NewManager(),
  1801  		UptimeLockedCalculator: uptime.NewLockedCalculator(),
  1802  		UpgradeConfig:          upgradetest.GetConfigWithUpgradeTime(upgradetest.Durango, latestForkTime),
  1803  	}}
  1804  
  1805  	ctx := snowtest.Context(t, snowtest.PChainID)
  1806  	ctx.Lock.Lock()
  1807  
  1808  	atomicDB := prefixdb.New([]byte{1}, db)
  1809  	m := atomic.NewMemory(atomicDB)
  1810  	ctx.SharedMemory = m.NewSharedMemory(ctx.ChainID)
  1811  
  1812  	msgChan := make(chan common.Message, 1)
  1813  	appSender := &enginetest.Sender{T: t}
  1814  	require.NoError(vm.Initialize(
  1815  		context.Background(),
  1816  		ctx,
  1817  		db,
  1818  		genesistest.NewBytes(t, genesistest.Config{}),
  1819  		nil,
  1820  		nil,
  1821  		msgChan,
  1822  		nil,
  1823  		appSender,
  1824  	))
  1825  
  1826  	defer func() {
  1827  		require.NoError(vm.Shutdown(context.Background()))
  1828  		ctx.Lock.Unlock()
  1829  	}()
  1830  
  1831  	initialClkTime := latestForkTime.Add(time.Second)
  1832  	vm.clock.Set(initialClkTime)
  1833  
  1834  	// Set VM state to NormalOp, to start tracking validators' uptime
  1835  	require.NoError(vm.SetState(context.Background(), snow.Bootstrapping))
  1836  	require.NoError(vm.SetState(context.Background(), snow.NormalOp))
  1837  
  1838  	// Fast forward clock to time for genesis validators to leave
  1839  	vm.clock.Set(genesistest.DefaultValidatorEndTime)
  1840  
  1841  	// evaluate a genesis validator for reward
  1842  	blk, err := vm.Builder.BuildBlock(context.Background())
  1843  	require.NoError(err)
  1844  	require.NoError(blk.Verify(context.Background()))
  1845  
  1846  	// Assert preferences are correct.
  1847  	// vm should prefer abort since uptime requirements are not met.
  1848  	oracleBlk := blk.(smcon.OracleBlock)
  1849  	options, err := oracleBlk.Options(context.Background())
  1850  	require.NoError(err)
  1851  
  1852  	abort := options[0].(*blockexecutor.Block)
  1853  	require.IsType(&block.BanffAbortBlock{}, abort.Block)
  1854  
  1855  	commit := options[1].(*blockexecutor.Block)
  1856  	require.IsType(&block.BanffCommitBlock{}, commit.Block)
  1857  
  1858  	// Assert block tries to reward a genesis validator
  1859  	rewardTx := oracleBlk.(block.Block).Txs()[0].Unsigned
  1860  	require.IsType(&txs.RewardValidatorTx{}, rewardTx)
  1861  	txID := blk.(block.Block).Txs()[0].ID()
  1862  
  1863  	// Verify options and accept abort block
  1864  	require.NoError(commit.Verify(context.Background()))
  1865  	require.NoError(abort.Verify(context.Background()))
  1866  	require.NoError(blk.Accept(context.Background()))
  1867  	require.NoError(abort.Accept(context.Background()))
  1868  	require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted()))
  1869  
  1870  	// Verify that rewarded validator has been removed.
  1871  	// Note that test genesis has multiple validators
  1872  	// terminating at the same time. The rewarded validator
  1873  	// will the first by txID. To make the test more stable
  1874  	// (txID changes every time we change any parameter
  1875  	// of the tx creating the validator), we explicitly
  1876  	//  check that rewarded validator is removed from staker set.
  1877  	_, txStatus, err := vm.state.GetTx(txID)
  1878  	require.NoError(err)
  1879  	require.Equal(status.Aborted, txStatus)
  1880  
  1881  	tx, _, err := vm.state.GetTx(rewardTx.(*txs.RewardValidatorTx).TxID)
  1882  	require.NoError(err)
  1883  	require.IsType(&txs.AddValidatorTx{}, tx.Unsigned)
  1884  
  1885  	valTx, _ := tx.Unsigned.(*txs.AddValidatorTx)
  1886  	_, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, valTx.NodeID())
  1887  	require.ErrorIs(err, database.ErrNotFound)
  1888  }
  1889  
  1890  func TestRemovePermissionedValidatorDuringAddPending(t *testing.T) {
  1891  	require := require.New(t)
  1892  
  1893  	validatorStartTime := latestForkTime.Add(txexecutor.SyncBound).Add(1 * time.Second)
  1894  	validatorEndTime := validatorStartTime.Add(360 * 24 * time.Hour)
  1895  
  1896  	vm, _, _ := defaultVM(t, upgradetest.Latest)
  1897  	vm.ctx.Lock.Lock()
  1898  	defer vm.ctx.Lock.Unlock()
  1899  
  1900  	wallet := newWallet(t, vm, walletConfig{})
  1901  
  1902  	nodeID := ids.GenerateTestNodeID()
  1903  	sk, err := bls.NewSecretKey()
  1904  	require.NoError(err)
  1905  	rewardsOwner := &secp256k1fx.OutputOwners{
  1906  		Threshold: 1,
  1907  		Addrs:     []ids.ShortID{ids.GenerateTestShortID()},
  1908  	}
  1909  
  1910  	addValidatorTx, err := wallet.IssueAddPermissionlessValidatorTx(
  1911  		&txs.SubnetValidator{
  1912  			Validator: txs.Validator{
  1913  				NodeID: nodeID,
  1914  				Start:  uint64(validatorStartTime.Unix()),
  1915  				End:    uint64(validatorEndTime.Unix()),
  1916  				Wght:   defaultMaxValidatorStake,
  1917  			},
  1918  			Subnet: constants.PrimaryNetworkID,
  1919  		},
  1920  		signer.NewProofOfPossession(sk),
  1921  		vm.ctx.AVAXAssetID,
  1922  		rewardsOwner,
  1923  		rewardsOwner,
  1924  		reward.PercentDenominator,
  1925  	)
  1926  	require.NoError(err)
  1927  
  1928  	vm.ctx.Lock.Unlock()
  1929  	require.NoError(vm.issueTxFromRPC(addValidatorTx))
  1930  	vm.ctx.Lock.Lock()
  1931  	require.NoError(buildAndAcceptStandardBlock(vm))
  1932  
  1933  	createSubnetTx, err := wallet.IssueCreateSubnetTx(
  1934  		&secp256k1fx.OutputOwners{
  1935  			Threshold: 1,
  1936  			Addrs:     []ids.ShortID{genesistest.DefaultFundedKeys[0].Address()},
  1937  		},
  1938  	)
  1939  	require.NoError(err)
  1940  
  1941  	vm.ctx.Lock.Unlock()
  1942  	require.NoError(vm.issueTxFromRPC(createSubnetTx))
  1943  	vm.ctx.Lock.Lock()
  1944  	require.NoError(buildAndAcceptStandardBlock(vm))
  1945  
  1946  	subnetID := createSubnetTx.ID()
  1947  	addSubnetValidatorTx, err := wallet.IssueAddSubnetValidatorTx(
  1948  		&txs.SubnetValidator{
  1949  			Validator: txs.Validator{
  1950  				NodeID: nodeID,
  1951  				Start:  uint64(validatorStartTime.Unix()),
  1952  				End:    uint64(validatorEndTime.Unix()),
  1953  				Wght:   defaultMaxValidatorStake,
  1954  			},
  1955  			Subnet: subnetID,
  1956  		},
  1957  	)
  1958  	require.NoError(err)
  1959  
  1960  	removeSubnetValidatorTx, err := wallet.IssueRemoveSubnetValidatorTx(
  1961  		nodeID,
  1962  		subnetID,
  1963  	)
  1964  	require.NoError(err)
  1965  
  1966  	lastAcceptedID := vm.state.GetLastAccepted()
  1967  	lastAcceptedHeight, err := vm.GetCurrentHeight(context.Background())
  1968  	require.NoError(err)
  1969  	statelessBlock, err := block.NewBanffStandardBlock(
  1970  		vm.state.GetTimestamp(),
  1971  		lastAcceptedID,
  1972  		lastAcceptedHeight+1,
  1973  		[]*txs.Tx{
  1974  			addSubnetValidatorTx,
  1975  			removeSubnetValidatorTx,
  1976  		},
  1977  	)
  1978  	require.NoError(err)
  1979  
  1980  	blockBytes := statelessBlock.Bytes()
  1981  	block, err := vm.ParseBlock(context.Background(), blockBytes)
  1982  	require.NoError(err)
  1983  	require.NoError(block.Verify(context.Background()))
  1984  	require.NoError(block.Accept(context.Background()))
  1985  	require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted()))
  1986  
  1987  	_, err = vm.state.GetPendingValidator(subnetID, nodeID)
  1988  	require.ErrorIs(err, database.ErrNotFound)
  1989  }
  1990  
  1991  func TestTransferSubnetOwnershipTx(t *testing.T) {
  1992  	require := require.New(t)
  1993  	vm, _, _ := defaultVM(t, upgradetest.Latest)
  1994  	vm.ctx.Lock.Lock()
  1995  	defer vm.ctx.Lock.Unlock()
  1996  
  1997  	wallet := newWallet(t, vm, walletConfig{})
  1998  
  1999  	expectedSubnetOwner := &secp256k1fx.OutputOwners{
  2000  		Threshold: 1,
  2001  		Addrs:     []ids.ShortID{genesistest.DefaultFundedKeys[0].Address()},
  2002  	}
  2003  	createSubnetTx, err := wallet.IssueCreateSubnetTx(
  2004  		expectedSubnetOwner,
  2005  	)
  2006  	require.NoError(err)
  2007  
  2008  	vm.ctx.Lock.Unlock()
  2009  	require.NoError(vm.issueTxFromRPC(createSubnetTx))
  2010  	vm.ctx.Lock.Lock()
  2011  	require.NoError(buildAndAcceptStandardBlock(vm))
  2012  
  2013  	subnetID := createSubnetTx.ID()
  2014  	subnetOwner, err := vm.state.GetSubnetOwner(subnetID)
  2015  	require.NoError(err)
  2016  	require.Equal(expectedSubnetOwner, subnetOwner)
  2017  
  2018  	expectedSubnetOwner = &secp256k1fx.OutputOwners{
  2019  		Threshold: 1,
  2020  		Addrs:     []ids.ShortID{ids.GenerateTestShortID()},
  2021  	}
  2022  	transferSubnetOwnershipTx, err := wallet.IssueTransferSubnetOwnershipTx(
  2023  		subnetID,
  2024  		expectedSubnetOwner,
  2025  	)
  2026  	require.NoError(err)
  2027  
  2028  	vm.ctx.Lock.Unlock()
  2029  	require.NoError(vm.issueTxFromRPC(transferSubnetOwnershipTx))
  2030  	vm.ctx.Lock.Lock()
  2031  	require.NoError(buildAndAcceptStandardBlock(vm))
  2032  
  2033  	subnetOwner, err = vm.state.GetSubnetOwner(subnetID)
  2034  	require.NoError(err)
  2035  	require.Equal(expectedSubnetOwner, subnetOwner)
  2036  }
  2037  
  2038  func TestBaseTx(t *testing.T) {
  2039  	require := require.New(t)
  2040  	vm, _, _ := defaultVM(t, upgradetest.Durango)
  2041  	vm.ctx.Lock.Lock()
  2042  	defer vm.ctx.Lock.Unlock()
  2043  
  2044  	wallet := newWallet(t, vm, walletConfig{})
  2045  
  2046  	baseTx, err := wallet.IssueBaseTx(
  2047  		[]*avax.TransferableOutput{
  2048  			{
  2049  				Asset: avax.Asset{ID: vm.ctx.AVAXAssetID},
  2050  				Out: &secp256k1fx.TransferOutput{
  2051  					Amt: 100 * units.MicroAvax,
  2052  					OutputOwners: secp256k1fx.OutputOwners{
  2053  						Threshold: 1,
  2054  						Addrs: []ids.ShortID{
  2055  							ids.GenerateTestShortID(),
  2056  						},
  2057  					},
  2058  				},
  2059  			},
  2060  		},
  2061  	)
  2062  	require.NoError(err)
  2063  
  2064  	vm.ctx.Lock.Unlock()
  2065  	require.NoError(vm.issueTxFromRPC(baseTx))
  2066  	vm.ctx.Lock.Lock()
  2067  	require.NoError(buildAndAcceptStandardBlock(vm))
  2068  
  2069  	_, txStatus, err := vm.state.GetTx(baseTx.ID())
  2070  	require.NoError(err)
  2071  	require.Equal(status.Committed, txStatus)
  2072  }
  2073  
  2074  func TestPruneMempool(t *testing.T) {
  2075  	require := require.New(t)
  2076  	vm, _, _ := defaultVM(t, upgradetest.Latest)
  2077  	vm.ctx.Lock.Lock()
  2078  	defer vm.ctx.Lock.Unlock()
  2079  
  2080  	wallet := newWallet(t, vm, walletConfig{})
  2081  
  2082  	// Create a tx that will be valid regardless of timestamp.
  2083  	baseTx, err := wallet.IssueBaseTx(
  2084  		[]*avax.TransferableOutput{
  2085  			{
  2086  				Asset: avax.Asset{ID: vm.ctx.AVAXAssetID},
  2087  				Out: &secp256k1fx.TransferOutput{
  2088  					Amt: 100 * units.MicroAvax,
  2089  					OutputOwners: secp256k1fx.OutputOwners{
  2090  						Threshold: 1,
  2091  						Addrs: []ids.ShortID{
  2092  							genesistest.DefaultFundedKeys[0].Address(),
  2093  						},
  2094  					},
  2095  				},
  2096  			},
  2097  		},
  2098  		walletcommon.WithCustomAddresses(set.Of(
  2099  			genesistest.DefaultFundedKeys[0].Address(),
  2100  		)),
  2101  	)
  2102  	require.NoError(err)
  2103  
  2104  	vm.ctx.Lock.Unlock()
  2105  	require.NoError(vm.issueTxFromRPC(baseTx))
  2106  	vm.ctx.Lock.Lock()
  2107  
  2108  	// [baseTx] should be in the mempool.
  2109  	baseTxID := baseTx.ID()
  2110  	_, ok := vm.Builder.Get(baseTxID)
  2111  	require.True(ok)
  2112  
  2113  	// Create a tx that will be invalid after time advancement.
  2114  	var (
  2115  		startTime = vm.clock.Time()
  2116  		endTime   = startTime.Add(vm.MinStakeDuration)
  2117  	)
  2118  
  2119  	sk, err := bls.NewSecretKey()
  2120  	require.NoError(err)
  2121  
  2122  	rewardsOwner := &secp256k1fx.OutputOwners{
  2123  		Threshold: 1,
  2124  		Addrs:     []ids.ShortID{ids.GenerateTestShortID()},
  2125  	}
  2126  	addValidatorTx, err := wallet.IssueAddPermissionlessValidatorTx(
  2127  		&txs.SubnetValidator{
  2128  			Validator: txs.Validator{
  2129  				NodeID: ids.GenerateTestNodeID(),
  2130  				Start:  uint64(startTime.Unix()),
  2131  				End:    uint64(endTime.Unix()),
  2132  				Wght:   defaultMinValidatorStake,
  2133  			},
  2134  			Subnet: constants.PrimaryNetworkID,
  2135  		},
  2136  		signer.NewProofOfPossession(sk),
  2137  		vm.ctx.AVAXAssetID,
  2138  		rewardsOwner,
  2139  		rewardsOwner,
  2140  		20000,
  2141  		walletcommon.WithCustomAddresses(set.Of(
  2142  			genesistest.DefaultFundedKeys[1].Address(),
  2143  		)),
  2144  	)
  2145  	require.NoError(err)
  2146  
  2147  	vm.ctx.Lock.Unlock()
  2148  	require.NoError(vm.issueTxFromRPC(addValidatorTx))
  2149  	vm.ctx.Lock.Lock()
  2150  
  2151  	// [addValidatorTx] and [baseTx] should be in the mempool.
  2152  	addValidatorTxID := addValidatorTx.ID()
  2153  	_, ok = vm.Builder.Get(addValidatorTxID)
  2154  	require.True(ok)
  2155  	_, ok = vm.Builder.Get(baseTxID)
  2156  	require.True(ok)
  2157  
  2158  	// Advance clock to [endTime], making [addValidatorTx] invalid.
  2159  	vm.clock.Set(endTime)
  2160  
  2161  	vm.ctx.Lock.Unlock()
  2162  	require.NoError(vm.pruneMempool())
  2163  	vm.ctx.Lock.Lock()
  2164  
  2165  	// [addValidatorTx] should be ejected from the mempool.
  2166  	// [baseTx] should still be in the mempool.
  2167  	_, ok = vm.Builder.Get(addValidatorTxID)
  2168  	require.False(ok)
  2169  	_, ok = vm.Builder.Get(baseTxID)
  2170  	require.True(ok)
  2171  }