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