github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/state/state_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 state
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"math"
    10  	"math/rand"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/prometheus/client_golang/prometheus"
    16  	"github.com/stretchr/testify/require"
    17  	"go.uber.org/mock/gomock"
    18  
    19  	"github.com/ava-labs/avalanchego/codec"
    20  	"github.com/ava-labs/avalanchego/database"
    21  	"github.com/ava-labs/avalanchego/database/memdb"
    22  	"github.com/ava-labs/avalanchego/ids"
    23  	"github.com/ava-labs/avalanchego/snow"
    24  	"github.com/ava-labs/avalanchego/snow/choices"
    25  	"github.com/ava-labs/avalanchego/snow/validators"
    26  	"github.com/ava-labs/avalanchego/upgrade/upgradetest"
    27  	"github.com/ava-labs/avalanchego/utils/constants"
    28  	"github.com/ava-labs/avalanchego/utils/crypto/bls"
    29  	"github.com/ava-labs/avalanchego/utils/iterator"
    30  	"github.com/ava-labs/avalanchego/utils/logging"
    31  	"github.com/ava-labs/avalanchego/utils/units"
    32  	"github.com/ava-labs/avalanchego/utils/wrappers"
    33  	"github.com/ava-labs/avalanchego/vms/components/avax"
    34  	"github.com/ava-labs/avalanchego/vms/components/gas"
    35  	"github.com/ava-labs/avalanchego/vms/platformvm/block"
    36  	"github.com/ava-labs/avalanchego/vms/platformvm/config"
    37  	"github.com/ava-labs/avalanchego/vms/platformvm/fx/fxmock"
    38  	"github.com/ava-labs/avalanchego/vms/platformvm/genesis/genesistest"
    39  	"github.com/ava-labs/avalanchego/vms/platformvm/metrics"
    40  	"github.com/ava-labs/avalanchego/vms/platformvm/reward"
    41  	"github.com/ava-labs/avalanchego/vms/platformvm/signer"
    42  	"github.com/ava-labs/avalanchego/vms/platformvm/status"
    43  	"github.com/ava-labs/avalanchego/vms/platformvm/txs"
    44  	"github.com/ava-labs/avalanchego/vms/secp256k1fx"
    45  	"github.com/ava-labs/avalanchego/vms/types"
    46  
    47  	safemath "github.com/ava-labs/avalanchego/utils/math"
    48  )
    49  
    50  var defaultValidatorNodeID = ids.GenerateTestNodeID()
    51  
    52  func newTestState(t testing.TB, db database.Database) *state {
    53  	s, err := New(
    54  		db,
    55  		genesistest.NewBytes(t, genesistest.Config{
    56  			NodeIDs: []ids.NodeID{defaultValidatorNodeID},
    57  		}),
    58  		prometheus.NewRegistry(),
    59  		validators.NewManager(),
    60  		upgradetest.GetConfig(upgradetest.Latest),
    61  		&config.DefaultExecutionConfig,
    62  		&snow.Context{
    63  			NetworkID: constants.UnitTestID,
    64  			NodeID:    ids.GenerateTestNodeID(),
    65  			Log:       logging.NoLog{},
    66  		},
    67  		metrics.Noop,
    68  		reward.NewCalculator(reward.Config{
    69  			MaxConsumptionRate: .12 * reward.PercentDenominator,
    70  			MinConsumptionRate: .1 * reward.PercentDenominator,
    71  			MintingPeriod:      365 * 24 * time.Hour,
    72  			SupplyCap:          720 * units.MegaAvax,
    73  		}),
    74  	)
    75  	require.NoError(t, err)
    76  	require.IsType(t, (*state)(nil), s)
    77  	return s.(*state)
    78  }
    79  
    80  func TestStateSyncGenesis(t *testing.T) {
    81  	require := require.New(t)
    82  	state := newTestState(t, memdb.New())
    83  
    84  	staker, err := state.GetCurrentValidator(constants.PrimaryNetworkID, defaultValidatorNodeID)
    85  	require.NoError(err)
    86  	require.NotNil(staker)
    87  	require.Equal(defaultValidatorNodeID, staker.NodeID)
    88  
    89  	delegatorIterator, err := state.GetCurrentDelegatorIterator(constants.PrimaryNetworkID, defaultValidatorNodeID)
    90  	require.NoError(err)
    91  	assertIteratorsEqual(t, iterator.Empty[*Staker]{}, delegatorIterator)
    92  
    93  	stakerIterator, err := state.GetCurrentStakerIterator()
    94  	require.NoError(err)
    95  	assertIteratorsEqual(t, iterator.FromSlice(staker), stakerIterator)
    96  
    97  	_, err = state.GetPendingValidator(constants.PrimaryNetworkID, defaultValidatorNodeID)
    98  	require.ErrorIs(err, database.ErrNotFound)
    99  
   100  	delegatorIterator, err = state.GetPendingDelegatorIterator(constants.PrimaryNetworkID, defaultValidatorNodeID)
   101  	require.NoError(err)
   102  	assertIteratorsEqual(t, iterator.Empty[*Staker]{}, delegatorIterator)
   103  }
   104  
   105  // Whenever we store a staker, a whole bunch a data structures are updated
   106  // This test is meant to capture which updates are carried out
   107  func TestPersistStakers(t *testing.T) {
   108  	tests := map[string]struct {
   109  		// Insert or delete a staker to state and store it
   110  		storeStaker func(*require.Assertions, ids.ID /*=subnetID*/, *state) *Staker
   111  
   112  		// Check that the staker is duly stored/removed in P-chain state
   113  		checkStakerInState func(*require.Assertions, *state, *Staker)
   114  
   115  		// Check whether validators are duly reported in the validator set,
   116  		// with the right weight and showing the BLS key
   117  		checkValidatorsSet func(*require.Assertions, *state, *Staker)
   118  
   119  		// Check that node duly track stakers uptimes
   120  		checkValidatorUptimes func(*require.Assertions, *state, *Staker)
   121  
   122  		// Check whether weight/bls keys diffs are duly stored
   123  		checkDiffs func(*require.Assertions, *state, *Staker, uint64)
   124  	}{
   125  		"add current validator": {
   126  			storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker {
   127  				var (
   128  					startTime = time.Now().Unix()
   129  					endTime   = time.Now().Add(14 * 24 * time.Hour).Unix()
   130  
   131  					validatorsData = txs.Validator{
   132  						NodeID: ids.GenerateTestNodeID(),
   133  						End:    uint64(endTime),
   134  						Wght:   1234,
   135  					}
   136  					validatorReward uint64 = 5678
   137  				)
   138  
   139  				utx := createPermissionlessValidatorTx(r, subnetID, validatorsData)
   140  				addPermValTx := &txs.Tx{Unsigned: utx}
   141  				r.NoError(addPermValTx.Initialize(txs.Codec))
   142  
   143  				staker, err := NewCurrentStaker(
   144  					addPermValTx.ID(),
   145  					utx,
   146  					time.Unix(startTime, 0),
   147  					validatorReward,
   148  				)
   149  				r.NoError(err)
   150  
   151  				r.NoError(s.PutCurrentValidator(staker))
   152  				s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker
   153  				r.NoError(s.Commit())
   154  				return staker
   155  			},
   156  			checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) {
   157  				retrievedStaker, err := s.GetCurrentValidator(staker.SubnetID, staker.NodeID)
   158  				r.NoError(err)
   159  				r.Equal(staker, retrievedStaker)
   160  			},
   161  			checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) {
   162  				valsMap := s.validators.GetMap(staker.SubnetID)
   163  				r.Contains(valsMap, staker.NodeID)
   164  				r.Equal(
   165  					&validators.GetValidatorOutput{
   166  						NodeID:    staker.NodeID,
   167  						PublicKey: staker.PublicKey,
   168  						Weight:    staker.Weight,
   169  					},
   170  					valsMap[staker.NodeID],
   171  				)
   172  			},
   173  			checkValidatorUptimes: func(r *require.Assertions, s *state, staker *Staker) {
   174  				upDuration, lastUpdated, err := s.GetUptime(staker.NodeID, staker.SubnetID)
   175  				r.NoError(err)
   176  				r.Equal(upDuration, time.Duration(0))
   177  				r.Equal(lastUpdated, staker.StartTime)
   178  			},
   179  			checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) {
   180  				weightDiffBytes, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID))
   181  				r.NoError(err)
   182  				weightDiff, err := unmarshalWeightDiff(weightDiffBytes)
   183  				r.NoError(err)
   184  				r.Equal(&ValidatorWeightDiff{
   185  					Decrease: false,
   186  					Amount:   staker.Weight,
   187  				}, weightDiff)
   188  
   189  				blsDiffBytes, err := s.validatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID))
   190  				if staker.SubnetID == constants.PrimaryNetworkID {
   191  					r.NoError(err)
   192  					r.Nil(blsDiffBytes)
   193  				} else {
   194  					r.ErrorIs(err, database.ErrNotFound)
   195  				}
   196  			},
   197  		},
   198  		"add current delegator": {
   199  			storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker {
   200  				// insert the delegator and its validator
   201  				var (
   202  					valStartTime = time.Now().Truncate(time.Second).Unix()
   203  					delStartTime = time.Unix(valStartTime, 0).Add(time.Hour).Unix()
   204  					delEndTime   = time.Unix(delStartTime, 0).Add(30 * 24 * time.Hour).Unix()
   205  					valEndTime   = time.Unix(valStartTime, 0).Add(365 * 24 * time.Hour).Unix()
   206  
   207  					validatorsData = txs.Validator{
   208  						NodeID: ids.GenerateTestNodeID(),
   209  						End:    uint64(valEndTime),
   210  						Wght:   1234,
   211  					}
   212  					validatorReward uint64 = 5678
   213  
   214  					delegatorData = txs.Validator{
   215  						NodeID: validatorsData.NodeID,
   216  						End:    uint64(delEndTime),
   217  						Wght:   validatorsData.Wght / 2,
   218  					}
   219  					delegatorReward uint64 = 5432
   220  				)
   221  
   222  				utxVal := createPermissionlessValidatorTx(r, subnetID, validatorsData)
   223  				addPermValTx := &txs.Tx{Unsigned: utxVal}
   224  				r.NoError(addPermValTx.Initialize(txs.Codec))
   225  
   226  				val, err := NewCurrentStaker(
   227  					addPermValTx.ID(),
   228  					utxVal,
   229  					time.Unix(valStartTime, 0),
   230  					validatorReward,
   231  				)
   232  				r.NoError(err)
   233  
   234  				utxDel := createPermissionlessDelegatorTx(subnetID, delegatorData)
   235  				addPermDelTx := &txs.Tx{Unsigned: utxDel}
   236  				r.NoError(addPermDelTx.Initialize(txs.Codec))
   237  
   238  				del, err := NewCurrentStaker(
   239  					addPermDelTx.ID(),
   240  					utxDel,
   241  					time.Unix(delStartTime, 0),
   242  					delegatorReward,
   243  				)
   244  				r.NoError(err)
   245  
   246  				r.NoError(s.PutCurrentValidator(val))
   247  				s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker
   248  				r.NoError(s.Commit())
   249  
   250  				s.PutCurrentDelegator(del)
   251  				s.AddTx(addPermDelTx, status.Committed) // this is currently needed to reload the staker
   252  				r.NoError(s.Commit())
   253  				return del
   254  			},
   255  			checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) {
   256  				delIt, err := s.GetCurrentDelegatorIterator(staker.SubnetID, staker.NodeID)
   257  				r.NoError(err)
   258  				r.True(delIt.Next())
   259  				retrievedDelegator := delIt.Value()
   260  				r.False(delIt.Next())
   261  				delIt.Release()
   262  				r.Equal(staker, retrievedDelegator)
   263  			},
   264  			checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) {
   265  				val, err := s.GetCurrentValidator(staker.SubnetID, staker.NodeID)
   266  				r.NoError(err)
   267  
   268  				valsMap := s.validators.GetMap(staker.SubnetID)
   269  				r.Contains(valsMap, staker.NodeID)
   270  				valOut := valsMap[staker.NodeID]
   271  				r.Equal(valOut.NodeID, staker.NodeID)
   272  				r.Equal(valOut.Weight, val.Weight+staker.Weight)
   273  			},
   274  			checkValidatorUptimes: func(*require.Assertions, *state, *Staker) {},
   275  			checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) {
   276  				// validator's weight must increase of delegator's weight amount
   277  				weightDiffBytes, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID))
   278  				r.NoError(err)
   279  				weightDiff, err := unmarshalWeightDiff(weightDiffBytes)
   280  				r.NoError(err)
   281  				r.Equal(&ValidatorWeightDiff{
   282  					Decrease: false,
   283  					Amount:   staker.Weight,
   284  				}, weightDiff)
   285  			},
   286  		},
   287  		"add pending validator": {
   288  			storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker {
   289  				var (
   290  					startTime = time.Now().Unix()
   291  					endTime   = time.Now().Add(14 * 24 * time.Hour).Unix()
   292  
   293  					validatorsData = txs.Validator{
   294  						NodeID: ids.GenerateTestNodeID(),
   295  						Start:  uint64(startTime),
   296  						End:    uint64(endTime),
   297  						Wght:   1234,
   298  					}
   299  				)
   300  
   301  				utx := createPermissionlessValidatorTx(r, subnetID, validatorsData)
   302  				addPermValTx := &txs.Tx{Unsigned: utx}
   303  				r.NoError(addPermValTx.Initialize(txs.Codec))
   304  
   305  				staker, err := NewPendingStaker(
   306  					addPermValTx.ID(),
   307  					utx,
   308  				)
   309  				r.NoError(err)
   310  
   311  				r.NoError(s.PutPendingValidator(staker))
   312  				s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker
   313  				r.NoError(s.Commit())
   314  				return staker
   315  			},
   316  			checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) {
   317  				retrievedStaker, err := s.GetPendingValidator(staker.SubnetID, staker.NodeID)
   318  				r.NoError(err)
   319  				r.Equal(staker, retrievedStaker)
   320  			},
   321  			checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) {
   322  				// pending validators are not showed in validators set
   323  				valsMap := s.validators.GetMap(staker.SubnetID)
   324  				r.NotContains(valsMap, staker.NodeID)
   325  			},
   326  			checkValidatorUptimes: func(r *require.Assertions, s *state, staker *Staker) {
   327  				// pending validators uptime is not tracked
   328  				_, _, err := s.GetUptime(staker.NodeID, staker.SubnetID)
   329  				r.ErrorIs(err, database.ErrNotFound)
   330  			},
   331  			checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) {
   332  				// pending validators weight diff and bls diffs are not stored
   333  				_, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID))
   334  				r.ErrorIs(err, database.ErrNotFound)
   335  
   336  				_, err = s.validatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID))
   337  				r.ErrorIs(err, database.ErrNotFound)
   338  			},
   339  		},
   340  		"add pending delegator": {
   341  			storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker {
   342  				// insert the delegator and its validator
   343  				var (
   344  					valStartTime = time.Now().Truncate(time.Second).Unix()
   345  					delStartTime = time.Unix(valStartTime, 0).Add(time.Hour).Unix()
   346  					delEndTime   = time.Unix(delStartTime, 0).Add(30 * 24 * time.Hour).Unix()
   347  					valEndTime   = time.Unix(valStartTime, 0).Add(365 * 24 * time.Hour).Unix()
   348  
   349  					validatorsData = txs.Validator{
   350  						NodeID: ids.GenerateTestNodeID(),
   351  						Start:  uint64(valStartTime),
   352  						End:    uint64(valEndTime),
   353  						Wght:   1234,
   354  					}
   355  
   356  					delegatorData = txs.Validator{
   357  						NodeID: validatorsData.NodeID,
   358  						Start:  uint64(delStartTime),
   359  						End:    uint64(delEndTime),
   360  						Wght:   validatorsData.Wght / 2,
   361  					}
   362  				)
   363  
   364  				utxVal := createPermissionlessValidatorTx(r, subnetID, validatorsData)
   365  				addPermValTx := &txs.Tx{Unsigned: utxVal}
   366  				r.NoError(addPermValTx.Initialize(txs.Codec))
   367  
   368  				val, err := NewPendingStaker(addPermValTx.ID(), utxVal)
   369  				r.NoError(err)
   370  
   371  				utxDel := createPermissionlessDelegatorTx(subnetID, delegatorData)
   372  				addPermDelTx := &txs.Tx{Unsigned: utxDel}
   373  				r.NoError(addPermDelTx.Initialize(txs.Codec))
   374  
   375  				del, err := NewPendingStaker(addPermDelTx.ID(), utxDel)
   376  				r.NoError(err)
   377  
   378  				r.NoError(s.PutPendingValidator(val))
   379  				s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker
   380  				r.NoError(s.Commit())
   381  
   382  				s.PutPendingDelegator(del)
   383  				s.AddTx(addPermDelTx, status.Committed) // this is currently needed to reload the staker
   384  				r.NoError(s.Commit())
   385  
   386  				return del
   387  			},
   388  			checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) {
   389  				delIt, err := s.GetPendingDelegatorIterator(staker.SubnetID, staker.NodeID)
   390  				r.NoError(err)
   391  				r.True(delIt.Next())
   392  				retrievedDelegator := delIt.Value()
   393  				r.False(delIt.Next())
   394  				delIt.Release()
   395  				r.Equal(staker, retrievedDelegator)
   396  			},
   397  			checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) {
   398  				valsMap := s.validators.GetMap(staker.SubnetID)
   399  				r.NotContains(valsMap, staker.NodeID)
   400  			},
   401  			checkValidatorUptimes: func(*require.Assertions, *state, *Staker) {},
   402  			checkDiffs:            func(*require.Assertions, *state, *Staker, uint64) {},
   403  		},
   404  		"delete current validator": {
   405  			storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker {
   406  				// add them remove the validator
   407  				var (
   408  					startTime = time.Now().Unix()
   409  					endTime   = time.Now().Add(14 * 24 * time.Hour).Unix()
   410  
   411  					validatorsData = txs.Validator{
   412  						NodeID: ids.GenerateTestNodeID(),
   413  						End:    uint64(endTime),
   414  						Wght:   1234,
   415  					}
   416  					validatorReward uint64 = 5678
   417  				)
   418  
   419  				utx := createPermissionlessValidatorTx(r, subnetID, validatorsData)
   420  				addPermValTx := &txs.Tx{Unsigned: utx}
   421  				r.NoError(addPermValTx.Initialize(txs.Codec))
   422  
   423  				staker, err := NewCurrentStaker(
   424  					addPermValTx.ID(),
   425  					utx,
   426  					time.Unix(startTime, 0),
   427  					validatorReward,
   428  				)
   429  				r.NoError(err)
   430  
   431  				r.NoError(s.PutCurrentValidator(staker))
   432  				s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker
   433  				r.NoError(s.Commit())
   434  
   435  				s.DeleteCurrentValidator(staker)
   436  				r.NoError(s.Commit())
   437  				return staker
   438  			},
   439  			checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) {
   440  				_, err := s.GetCurrentValidator(staker.SubnetID, staker.NodeID)
   441  				r.ErrorIs(err, database.ErrNotFound)
   442  			},
   443  			checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) {
   444  				// deleted validators are not showed in the validators set anymore
   445  				valsMap := s.validators.GetMap(staker.SubnetID)
   446  				r.NotContains(valsMap, staker.NodeID)
   447  			},
   448  			checkValidatorUptimes: func(r *require.Assertions, s *state, staker *Staker) {
   449  				// uptimes of delete validators are dropped
   450  				_, _, err := s.GetUptime(staker.NodeID, staker.SubnetID)
   451  				r.ErrorIs(err, database.ErrNotFound)
   452  			},
   453  			checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) {
   454  				weightDiffBytes, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID))
   455  				r.NoError(err)
   456  				weightDiff, err := unmarshalWeightDiff(weightDiffBytes)
   457  				r.NoError(err)
   458  				r.Equal(&ValidatorWeightDiff{
   459  					Decrease: true,
   460  					Amount:   staker.Weight,
   461  				}, weightDiff)
   462  
   463  				blsDiffBytes, err := s.validatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID))
   464  				if staker.SubnetID == constants.PrimaryNetworkID {
   465  					r.NoError(err)
   466  					r.Equal(bls.PublicKeyFromValidUncompressedBytes(blsDiffBytes), staker.PublicKey)
   467  				} else {
   468  					r.ErrorIs(err, database.ErrNotFound)
   469  				}
   470  			},
   471  		},
   472  		"delete current delegator": {
   473  			storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker {
   474  				// insert validator and delegator, then remove the delegator
   475  				var (
   476  					valStartTime = time.Now().Truncate(time.Second).Unix()
   477  					delStartTime = time.Unix(valStartTime, 0).Add(time.Hour).Unix()
   478  					delEndTime   = time.Unix(delStartTime, 0).Add(30 * 24 * time.Hour).Unix()
   479  					valEndTime   = time.Unix(valStartTime, 0).Add(365 * 24 * time.Hour).Unix()
   480  
   481  					validatorsData = txs.Validator{
   482  						NodeID: ids.GenerateTestNodeID(),
   483  						End:    uint64(valEndTime),
   484  						Wght:   1234,
   485  					}
   486  					validatorReward uint64 = 5678
   487  
   488  					delegatorData = txs.Validator{
   489  						NodeID: validatorsData.NodeID,
   490  						End:    uint64(delEndTime),
   491  						Wght:   validatorsData.Wght / 2,
   492  					}
   493  					delegatorReward uint64 = 5432
   494  				)
   495  
   496  				utxVal := createPermissionlessValidatorTx(r, subnetID, validatorsData)
   497  				addPermValTx := &txs.Tx{Unsigned: utxVal}
   498  				r.NoError(addPermValTx.Initialize(txs.Codec))
   499  
   500  				val, err := NewCurrentStaker(
   501  					addPermValTx.ID(),
   502  					utxVal,
   503  					time.Unix(valStartTime, 0),
   504  					validatorReward,
   505  				)
   506  				r.NoError(err)
   507  
   508  				utxDel := createPermissionlessDelegatorTx(subnetID, delegatorData)
   509  				addPermDelTx := &txs.Tx{Unsigned: utxDel}
   510  				r.NoError(addPermDelTx.Initialize(txs.Codec))
   511  
   512  				del, err := NewCurrentStaker(
   513  					addPermDelTx.ID(),
   514  					utxDel,
   515  					time.Unix(delStartTime, 0),
   516  					delegatorReward,
   517  				)
   518  				r.NoError(err)
   519  
   520  				r.NoError(s.PutCurrentValidator(val))
   521  				s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker
   522  
   523  				s.PutCurrentDelegator(del)
   524  				s.AddTx(addPermDelTx, status.Committed) // this is currently needed to reload the staker
   525  				r.NoError(s.Commit())
   526  
   527  				s.DeleteCurrentDelegator(del)
   528  				r.NoError(s.Commit())
   529  
   530  				return del
   531  			},
   532  			checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) {
   533  				delIt, err := s.GetCurrentDelegatorIterator(staker.SubnetID, staker.NodeID)
   534  				r.NoError(err)
   535  				r.False(delIt.Next())
   536  				delIt.Release()
   537  			},
   538  			checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) {
   539  				val, err := s.GetCurrentValidator(staker.SubnetID, staker.NodeID)
   540  				r.NoError(err)
   541  
   542  				valsMap := s.validators.GetMap(staker.SubnetID)
   543  				r.Contains(valsMap, staker.NodeID)
   544  				valOut := valsMap[staker.NodeID]
   545  				r.Equal(valOut.NodeID, staker.NodeID)
   546  				r.Equal(valOut.Weight, val.Weight)
   547  			},
   548  			checkValidatorUptimes: func(*require.Assertions, *state, *Staker) {},
   549  			checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) {
   550  				// validator's weight must decrease of delegator's weight amount
   551  				weightDiffBytes, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID))
   552  				r.NoError(err)
   553  				weightDiff, err := unmarshalWeightDiff(weightDiffBytes)
   554  				r.NoError(err)
   555  				r.Equal(&ValidatorWeightDiff{
   556  					Decrease: true,
   557  					Amount:   staker.Weight,
   558  				}, weightDiff)
   559  			},
   560  		},
   561  		"delete pending validator": {
   562  			storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker {
   563  				var (
   564  					startTime = time.Now().Unix()
   565  					endTime   = time.Now().Add(14 * 24 * time.Hour).Unix()
   566  
   567  					validatorsData = txs.Validator{
   568  						NodeID: ids.GenerateTestNodeID(),
   569  						Start:  uint64(startTime),
   570  						End:    uint64(endTime),
   571  						Wght:   1234,
   572  					}
   573  				)
   574  
   575  				utx := createPermissionlessValidatorTx(r, subnetID, validatorsData)
   576  				addPermValTx := &txs.Tx{Unsigned: utx}
   577  				r.NoError(addPermValTx.Initialize(txs.Codec))
   578  
   579  				staker, err := NewPendingStaker(
   580  					addPermValTx.ID(),
   581  					utx,
   582  				)
   583  				r.NoError(err)
   584  
   585  				r.NoError(s.PutPendingValidator(staker))
   586  				s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker
   587  				r.NoError(s.Commit())
   588  
   589  				s.DeletePendingValidator(staker)
   590  				r.NoError(s.Commit())
   591  
   592  				return staker
   593  			},
   594  			checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) {
   595  				_, err := s.GetPendingValidator(staker.SubnetID, staker.NodeID)
   596  				r.ErrorIs(err, database.ErrNotFound)
   597  			},
   598  			checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) {
   599  				valsMap := s.validators.GetMap(staker.SubnetID)
   600  				r.NotContains(valsMap, staker.NodeID)
   601  			},
   602  			checkValidatorUptimes: func(r *require.Assertions, s *state, staker *Staker) {
   603  				_, _, err := s.GetUptime(staker.NodeID, staker.SubnetID)
   604  				r.ErrorIs(err, database.ErrNotFound)
   605  			},
   606  			checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) {
   607  				_, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID))
   608  				r.ErrorIs(err, database.ErrNotFound)
   609  
   610  				_, err = s.validatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID))
   611  				r.ErrorIs(err, database.ErrNotFound)
   612  			},
   613  		},
   614  		"delete pending delegator": {
   615  			storeStaker: func(r *require.Assertions, subnetID ids.ID, s *state) *Staker {
   616  				// insert validator and delegator the remove the validator
   617  				var (
   618  					valStartTime = time.Now().Truncate(time.Second).Unix()
   619  					delStartTime = time.Unix(valStartTime, 0).Add(time.Hour).Unix()
   620  					delEndTime   = time.Unix(delStartTime, 0).Add(30 * 24 * time.Hour).Unix()
   621  					valEndTime   = time.Unix(valStartTime, 0).Add(365 * 24 * time.Hour).Unix()
   622  
   623  					validatorsData = txs.Validator{
   624  						NodeID: ids.GenerateTestNodeID(),
   625  						Start:  uint64(valStartTime),
   626  						End:    uint64(valEndTime),
   627  						Wght:   1234,
   628  					}
   629  
   630  					delegatorData = txs.Validator{
   631  						NodeID: validatorsData.NodeID,
   632  						Start:  uint64(delStartTime),
   633  						End:    uint64(delEndTime),
   634  						Wght:   validatorsData.Wght / 2,
   635  					}
   636  				)
   637  
   638  				utxVal := createPermissionlessValidatorTx(r, subnetID, validatorsData)
   639  				addPermValTx := &txs.Tx{Unsigned: utxVal}
   640  				r.NoError(addPermValTx.Initialize(txs.Codec))
   641  
   642  				val, err := NewPendingStaker(addPermValTx.ID(), utxVal)
   643  				r.NoError(err)
   644  
   645  				utxDel := createPermissionlessDelegatorTx(subnetID, delegatorData)
   646  				addPermDelTx := &txs.Tx{Unsigned: utxDel}
   647  				r.NoError(addPermDelTx.Initialize(txs.Codec))
   648  
   649  				del, err := NewPendingStaker(addPermDelTx.ID(), utxDel)
   650  				r.NoError(err)
   651  
   652  				r.NoError(s.PutPendingValidator(val))
   653  				s.AddTx(addPermValTx, status.Committed) // this is currently needed to reload the staker
   654  
   655  				s.PutPendingDelegator(del)
   656  				s.AddTx(addPermDelTx, status.Committed) // this is currently needed to reload the staker
   657  				r.NoError(s.Commit())
   658  
   659  				s.DeletePendingDelegator(del)
   660  				r.NoError(s.Commit())
   661  				return del
   662  			},
   663  			checkStakerInState: func(r *require.Assertions, s *state, staker *Staker) {
   664  				delIt, err := s.GetPendingDelegatorIterator(staker.SubnetID, staker.NodeID)
   665  				r.NoError(err)
   666  				r.False(delIt.Next())
   667  				delIt.Release()
   668  			},
   669  			checkValidatorsSet: func(r *require.Assertions, s *state, staker *Staker) {
   670  				valsMap := s.validators.GetMap(staker.SubnetID)
   671  				r.NotContains(valsMap, staker.NodeID)
   672  			},
   673  			checkValidatorUptimes: func(*require.Assertions, *state, *Staker) {},
   674  			checkDiffs:            func(*require.Assertions, *state, *Staker, uint64) {},
   675  		},
   676  	}
   677  
   678  	subnetIDs := []ids.ID{constants.PrimaryNetworkID, ids.GenerateTestID()}
   679  	for _, subnetID := range subnetIDs {
   680  		for name, test := range tests {
   681  			t.Run(fmt.Sprintf("%s - subnetID %s", name, subnetID), func(t *testing.T) {
   682  				require := require.New(t)
   683  
   684  				db := memdb.New()
   685  				state := newTestState(t, db)
   686  
   687  				// create and store the staker
   688  				staker := test.storeStaker(require, subnetID, state)
   689  
   690  				// check all relevant data are stored
   691  				test.checkStakerInState(require, state, staker)
   692  				test.checkValidatorsSet(require, state, staker)
   693  				test.checkValidatorUptimes(require, state, staker)
   694  				test.checkDiffs(require, state, staker, 0 /*height*/)
   695  
   696  				// rebuild the state
   697  				rebuiltState := newTestState(t, db)
   698  
   699  				// check again that all relevant data are still available in rebuilt state
   700  				test.checkStakerInState(require, rebuiltState, staker)
   701  				test.checkValidatorsSet(require, rebuiltState, staker)
   702  				test.checkValidatorUptimes(require, rebuiltState, staker)
   703  				test.checkDiffs(require, rebuiltState, staker, 0 /*height*/)
   704  			})
   705  		}
   706  	}
   707  }
   708  
   709  func createPermissionlessValidatorTx(r *require.Assertions, subnetID ids.ID, validatorsData txs.Validator) *txs.AddPermissionlessValidatorTx {
   710  	var sig signer.Signer = &signer.Empty{}
   711  	if subnetID == constants.PrimaryNetworkID {
   712  		sk, err := bls.NewSecretKey()
   713  		r.NoError(err)
   714  		sig = signer.NewProofOfPossession(sk)
   715  	}
   716  
   717  	return &txs.AddPermissionlessValidatorTx{
   718  		BaseTx: txs.BaseTx{
   719  			BaseTx: avax.BaseTx{
   720  				NetworkID:    constants.MainnetID,
   721  				BlockchainID: constants.PlatformChainID,
   722  				Outs:         []*avax.TransferableOutput{},
   723  				Ins: []*avax.TransferableInput{
   724  					{
   725  						UTXOID: avax.UTXOID{
   726  							TxID:        ids.GenerateTestID(),
   727  							OutputIndex: 1,
   728  						},
   729  						Asset: avax.Asset{
   730  							ID: ids.GenerateTestID(),
   731  						},
   732  						In: &secp256k1fx.TransferInput{
   733  							Amt: 2 * units.KiloAvax,
   734  							Input: secp256k1fx.Input{
   735  								SigIndices: []uint32{1},
   736  							},
   737  						},
   738  					},
   739  				},
   740  				Memo: types.JSONByteSlice{},
   741  			},
   742  		},
   743  		Validator: validatorsData,
   744  		Subnet:    subnetID,
   745  		Signer:    sig,
   746  
   747  		StakeOuts: []*avax.TransferableOutput{
   748  			{
   749  				Asset: avax.Asset{
   750  					ID: ids.GenerateTestID(),
   751  				},
   752  				Out: &secp256k1fx.TransferOutput{
   753  					Amt: 2 * units.KiloAvax,
   754  					OutputOwners: secp256k1fx.OutputOwners{
   755  						Locktime:  0,
   756  						Threshold: 1,
   757  						Addrs: []ids.ShortID{
   758  							ids.GenerateTestShortID(),
   759  						},
   760  					},
   761  				},
   762  			},
   763  		},
   764  		ValidatorRewardsOwner: &secp256k1fx.OutputOwners{
   765  			Locktime:  0,
   766  			Threshold: 1,
   767  			Addrs: []ids.ShortID{
   768  				ids.GenerateTestShortID(),
   769  			},
   770  		},
   771  		DelegatorRewardsOwner: &secp256k1fx.OutputOwners{
   772  			Locktime:  0,
   773  			Threshold: 1,
   774  			Addrs: []ids.ShortID{
   775  				ids.GenerateTestShortID(),
   776  			},
   777  		},
   778  		DelegationShares: reward.PercentDenominator,
   779  	}
   780  }
   781  
   782  func createPermissionlessDelegatorTx(subnetID ids.ID, delegatorData txs.Validator) *txs.AddPermissionlessDelegatorTx {
   783  	return &txs.AddPermissionlessDelegatorTx{
   784  		BaseTx: txs.BaseTx{
   785  			BaseTx: avax.BaseTx{
   786  				NetworkID:    constants.MainnetID,
   787  				BlockchainID: constants.PlatformChainID,
   788  				Outs:         []*avax.TransferableOutput{},
   789  				Ins: []*avax.TransferableInput{
   790  					{
   791  						UTXOID: avax.UTXOID{
   792  							TxID:        ids.GenerateTestID(),
   793  							OutputIndex: 1,
   794  						},
   795  						Asset: avax.Asset{
   796  							ID: ids.GenerateTestID(),
   797  						},
   798  						In: &secp256k1fx.TransferInput{
   799  							Amt: 2 * units.KiloAvax,
   800  							Input: secp256k1fx.Input{
   801  								SigIndices: []uint32{1},
   802  							},
   803  						},
   804  					},
   805  				},
   806  				Memo: types.JSONByteSlice{},
   807  			},
   808  		},
   809  		Validator: delegatorData,
   810  		Subnet:    subnetID,
   811  
   812  		StakeOuts: []*avax.TransferableOutput{
   813  			{
   814  				Asset: avax.Asset{
   815  					ID: ids.GenerateTestID(),
   816  				},
   817  				Out: &secp256k1fx.TransferOutput{
   818  					Amt: 2 * units.KiloAvax,
   819  					OutputOwners: secp256k1fx.OutputOwners{
   820  						Locktime:  0,
   821  						Threshold: 1,
   822  						Addrs: []ids.ShortID{
   823  							ids.GenerateTestShortID(),
   824  						},
   825  					},
   826  				},
   827  			},
   828  		},
   829  		DelegationRewardsOwner: &secp256k1fx.OutputOwners{
   830  			Locktime:  0,
   831  			Threshold: 1,
   832  			Addrs: []ids.ShortID{
   833  				ids.GenerateTestShortID(),
   834  			},
   835  		},
   836  	}
   837  }
   838  
   839  func TestValidatorWeightDiff(t *testing.T) {
   840  	type test struct {
   841  		name        string
   842  		ops         []func(*ValidatorWeightDiff) error
   843  		expected    *ValidatorWeightDiff
   844  		expectedErr error
   845  	}
   846  
   847  	tests := []test{
   848  		{
   849  			name:        "no ops",
   850  			ops:         []func(*ValidatorWeightDiff) error{},
   851  			expected:    &ValidatorWeightDiff{},
   852  			expectedErr: nil,
   853  		},
   854  		{
   855  			name: "simple decrease",
   856  			ops: []func(*ValidatorWeightDiff) error{
   857  				func(d *ValidatorWeightDiff) error {
   858  					return d.Add(true, 1)
   859  				},
   860  				func(d *ValidatorWeightDiff) error {
   861  					return d.Add(true, 1)
   862  				},
   863  			},
   864  			expected: &ValidatorWeightDiff{
   865  				Decrease: true,
   866  				Amount:   2,
   867  			},
   868  			expectedErr: nil,
   869  		},
   870  		{
   871  			name: "decrease overflow",
   872  			ops: []func(*ValidatorWeightDiff) error{
   873  				func(d *ValidatorWeightDiff) error {
   874  					return d.Add(true, math.MaxUint64)
   875  				},
   876  				func(d *ValidatorWeightDiff) error {
   877  					return d.Add(true, 1)
   878  				},
   879  			},
   880  			expected:    &ValidatorWeightDiff{},
   881  			expectedErr: safemath.ErrOverflow,
   882  		},
   883  		{
   884  			name: "simple increase",
   885  			ops: []func(*ValidatorWeightDiff) error{
   886  				func(d *ValidatorWeightDiff) error {
   887  					return d.Add(false, 1)
   888  				},
   889  				func(d *ValidatorWeightDiff) error {
   890  					return d.Add(false, 1)
   891  				},
   892  			},
   893  			expected: &ValidatorWeightDiff{
   894  				Decrease: false,
   895  				Amount:   2,
   896  			},
   897  			expectedErr: nil,
   898  		},
   899  		{
   900  			name: "increase overflow",
   901  			ops: []func(*ValidatorWeightDiff) error{
   902  				func(d *ValidatorWeightDiff) error {
   903  					return d.Add(false, math.MaxUint64)
   904  				},
   905  				func(d *ValidatorWeightDiff) error {
   906  					return d.Add(false, 1)
   907  				},
   908  			},
   909  			expected:    &ValidatorWeightDiff{},
   910  			expectedErr: safemath.ErrOverflow,
   911  		},
   912  		{
   913  			name: "varied use",
   914  			ops: []func(*ValidatorWeightDiff) error{
   915  				// Add to 0
   916  				func(d *ValidatorWeightDiff) error {
   917  					return d.Add(false, 2) // Value 2
   918  				},
   919  				// Subtract from positive number
   920  				func(d *ValidatorWeightDiff) error {
   921  					return d.Add(true, 1) // Value 1
   922  				},
   923  				// Subtract from positive number
   924  				// to make it negative
   925  				func(d *ValidatorWeightDiff) error {
   926  					return d.Add(true, 3) // Value -2
   927  				},
   928  				// Subtract from a negative number
   929  				func(d *ValidatorWeightDiff) error {
   930  					return d.Add(true, 3) // Value -5
   931  				},
   932  				// Add to a negative number
   933  				func(d *ValidatorWeightDiff) error {
   934  					return d.Add(false, 1) // Value -4
   935  				},
   936  				// Add to a negative number
   937  				// to make it positive
   938  				func(d *ValidatorWeightDiff) error {
   939  					return d.Add(false, 5) // Value 1
   940  				},
   941  				// Add to a positive number
   942  				func(d *ValidatorWeightDiff) error {
   943  					return d.Add(false, 1) // Value 2
   944  				},
   945  				// Get to zero
   946  				func(d *ValidatorWeightDiff) error {
   947  					return d.Add(true, 2) // Value 0
   948  				},
   949  				// Subtract from zero
   950  				func(d *ValidatorWeightDiff) error {
   951  					return d.Add(true, 2) // Value -2
   952  				},
   953  			},
   954  			expected: &ValidatorWeightDiff{
   955  				Decrease: true,
   956  				Amount:   2,
   957  			},
   958  			expectedErr: nil,
   959  		},
   960  	}
   961  
   962  	for _, tt := range tests {
   963  		t.Run(tt.name, func(t *testing.T) {
   964  			require := require.New(t)
   965  			diff := &ValidatorWeightDiff{}
   966  			errs := wrappers.Errs{}
   967  			for _, op := range tt.ops {
   968  				errs.Add(op(diff))
   969  			}
   970  			require.ErrorIs(errs.Err, tt.expectedErr)
   971  			if tt.expectedErr != nil {
   972  				return
   973  			}
   974  			require.Equal(tt.expected, diff)
   975  		})
   976  	}
   977  }
   978  
   979  // Tests PutCurrentValidator, DeleteCurrentValidator, GetCurrentValidator,
   980  // ApplyValidatorWeightDiffs, ApplyValidatorPublicKeyDiffs
   981  func TestStateAddRemoveValidator(t *testing.T) {
   982  	require := require.New(t)
   983  
   984  	state := newTestState(t, memdb.New())
   985  
   986  	var (
   987  		numNodes  = 3
   988  		subnetID  = ids.GenerateTestID()
   989  		startTime = time.Now()
   990  		endTime   = startTime.Add(24 * time.Hour)
   991  		stakers   = make([]Staker, numNodes)
   992  	)
   993  	for i := 0; i < numNodes; i++ {
   994  		stakers[i] = Staker{
   995  			TxID:            ids.GenerateTestID(),
   996  			NodeID:          ids.GenerateTestNodeID(),
   997  			Weight:          uint64(i + 1),
   998  			StartTime:       startTime.Add(time.Duration(i) * time.Second),
   999  			EndTime:         endTime.Add(time.Duration(i) * time.Second),
  1000  			PotentialReward: uint64(i + 1),
  1001  		}
  1002  		if i%2 == 0 {
  1003  			stakers[i].SubnetID = subnetID
  1004  		} else {
  1005  			sk, err := bls.NewSecretKey()
  1006  			require.NoError(err)
  1007  			stakers[i].PublicKey = bls.PublicFromSecretKey(sk)
  1008  			stakers[i].SubnetID = constants.PrimaryNetworkID
  1009  		}
  1010  	}
  1011  
  1012  	type diff struct {
  1013  		addedValidators   []Staker
  1014  		addedDelegators   []Staker
  1015  		removedDelegators []Staker
  1016  		removedValidators []Staker
  1017  
  1018  		expectedPrimaryValidatorSet map[ids.NodeID]*validators.GetValidatorOutput
  1019  		expectedSubnetValidatorSet  map[ids.NodeID]*validators.GetValidatorOutput
  1020  	}
  1021  	diffs := []diff{
  1022  		{
  1023  			// Do nothing
  1024  			expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{},
  1025  			expectedSubnetValidatorSet:  map[ids.NodeID]*validators.GetValidatorOutput{},
  1026  		},
  1027  		{
  1028  			// Add a subnet validator
  1029  			addedValidators:             []Staker{stakers[0]},
  1030  			expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{},
  1031  			expectedSubnetValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{
  1032  				stakers[0].NodeID: {
  1033  					NodeID: stakers[0].NodeID,
  1034  					Weight: stakers[0].Weight,
  1035  				},
  1036  			},
  1037  		},
  1038  		{
  1039  			// Remove a subnet validator
  1040  			removedValidators:           []Staker{stakers[0]},
  1041  			expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{},
  1042  			expectedSubnetValidatorSet:  map[ids.NodeID]*validators.GetValidatorOutput{},
  1043  		},
  1044  		{ // Add a primary network validator
  1045  			addedValidators: []Staker{stakers[1]},
  1046  			expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{
  1047  				stakers[1].NodeID: {
  1048  					NodeID:    stakers[1].NodeID,
  1049  					PublicKey: stakers[1].PublicKey,
  1050  					Weight:    stakers[1].Weight,
  1051  				},
  1052  			},
  1053  			expectedSubnetValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{},
  1054  		},
  1055  		{
  1056  			// Do nothing
  1057  			expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{
  1058  				stakers[1].NodeID: {
  1059  					NodeID:    stakers[1].NodeID,
  1060  					PublicKey: stakers[1].PublicKey,
  1061  					Weight:    stakers[1].Weight,
  1062  				},
  1063  			},
  1064  			expectedSubnetValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{},
  1065  		},
  1066  		{ // Remove a primary network validator
  1067  			removedValidators:           []Staker{stakers[1]},
  1068  			expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{},
  1069  			expectedSubnetValidatorSet:  map[ids.NodeID]*validators.GetValidatorOutput{},
  1070  		},
  1071  		{
  1072  			// Add 2 subnet validators and a primary network validator
  1073  			addedValidators: []Staker{stakers[0], stakers[1], stakers[2]},
  1074  			expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{
  1075  				stakers[1].NodeID: {
  1076  					NodeID:    stakers[1].NodeID,
  1077  					PublicKey: stakers[1].PublicKey,
  1078  					Weight:    stakers[1].Weight,
  1079  				},
  1080  			},
  1081  			expectedSubnetValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{
  1082  				stakers[0].NodeID: {
  1083  					NodeID: stakers[0].NodeID,
  1084  					Weight: stakers[0].Weight,
  1085  				},
  1086  				stakers[2].NodeID: {
  1087  					NodeID: stakers[2].NodeID,
  1088  					Weight: stakers[2].Weight,
  1089  				},
  1090  			},
  1091  		},
  1092  		{
  1093  			// Remove 2 subnet validators and a primary network validator.
  1094  			removedValidators:           []Staker{stakers[0], stakers[1], stakers[2]},
  1095  			expectedPrimaryValidatorSet: map[ids.NodeID]*validators.GetValidatorOutput{},
  1096  			expectedSubnetValidatorSet:  map[ids.NodeID]*validators.GetValidatorOutput{},
  1097  		},
  1098  	}
  1099  	for currentIndex, diff := range diffs {
  1100  		for _, added := range diff.addedValidators {
  1101  			added := added
  1102  			require.NoError(state.PutCurrentValidator(&added))
  1103  		}
  1104  		for _, added := range diff.addedDelegators {
  1105  			added := added
  1106  			state.PutCurrentDelegator(&added)
  1107  		}
  1108  		for _, removed := range diff.removedDelegators {
  1109  			removed := removed
  1110  			state.DeleteCurrentDelegator(&removed)
  1111  		}
  1112  		for _, removed := range diff.removedValidators {
  1113  			removed := removed
  1114  			state.DeleteCurrentValidator(&removed)
  1115  		}
  1116  
  1117  		currentHeight := uint64(currentIndex + 1)
  1118  		state.SetHeight(currentHeight)
  1119  
  1120  		require.NoError(state.Commit())
  1121  
  1122  		for _, added := range diff.addedValidators {
  1123  			gotValidator, err := state.GetCurrentValidator(added.SubnetID, added.NodeID)
  1124  			require.NoError(err)
  1125  			require.Equal(added, *gotValidator)
  1126  		}
  1127  
  1128  		for _, removed := range diff.removedValidators {
  1129  			_, err := state.GetCurrentValidator(removed.SubnetID, removed.NodeID)
  1130  			require.ErrorIs(err, database.ErrNotFound)
  1131  		}
  1132  
  1133  		for i := 0; i < currentIndex; i++ {
  1134  			prevDiff := diffs[i]
  1135  			prevHeight := uint64(i + 1)
  1136  
  1137  			primaryValidatorSet := copyValidatorSet(diff.expectedPrimaryValidatorSet)
  1138  			require.NoError(state.ApplyValidatorWeightDiffs(
  1139  				context.Background(),
  1140  				primaryValidatorSet,
  1141  				currentHeight,
  1142  				prevHeight+1,
  1143  				constants.PrimaryNetworkID,
  1144  			))
  1145  			requireEqualWeightsValidatorSet(require, prevDiff.expectedPrimaryValidatorSet, primaryValidatorSet)
  1146  
  1147  			require.NoError(state.ApplyValidatorPublicKeyDiffs(
  1148  				context.Background(),
  1149  				primaryValidatorSet,
  1150  				currentHeight,
  1151  				prevHeight+1,
  1152  			))
  1153  			requireEqualPublicKeysValidatorSet(require, prevDiff.expectedPrimaryValidatorSet, primaryValidatorSet)
  1154  
  1155  			subnetValidatorSet := copyValidatorSet(diff.expectedSubnetValidatorSet)
  1156  			require.NoError(state.ApplyValidatorWeightDiffs(
  1157  				context.Background(),
  1158  				subnetValidatorSet,
  1159  				currentHeight,
  1160  				prevHeight+1,
  1161  				subnetID,
  1162  			))
  1163  			requireEqualWeightsValidatorSet(require, prevDiff.expectedSubnetValidatorSet, subnetValidatorSet)
  1164  		}
  1165  	}
  1166  }
  1167  
  1168  func copyValidatorSet(
  1169  	input map[ids.NodeID]*validators.GetValidatorOutput,
  1170  ) map[ids.NodeID]*validators.GetValidatorOutput {
  1171  	result := make(map[ids.NodeID]*validators.GetValidatorOutput, len(input))
  1172  	for nodeID, vdr := range input {
  1173  		vdrCopy := *vdr
  1174  		result[nodeID] = &vdrCopy
  1175  	}
  1176  	return result
  1177  }
  1178  
  1179  func requireEqualWeightsValidatorSet(
  1180  	require *require.Assertions,
  1181  	expected map[ids.NodeID]*validators.GetValidatorOutput,
  1182  	actual map[ids.NodeID]*validators.GetValidatorOutput,
  1183  ) {
  1184  	require.Len(actual, len(expected))
  1185  	for nodeID, expectedVdr := range expected {
  1186  		require.Contains(actual, nodeID)
  1187  
  1188  		actualVdr := actual[nodeID]
  1189  		require.Equal(expectedVdr.NodeID, actualVdr.NodeID)
  1190  		require.Equal(expectedVdr.Weight, actualVdr.Weight)
  1191  	}
  1192  }
  1193  
  1194  func requireEqualPublicKeysValidatorSet(
  1195  	require *require.Assertions,
  1196  	expected map[ids.NodeID]*validators.GetValidatorOutput,
  1197  	actual map[ids.NodeID]*validators.GetValidatorOutput,
  1198  ) {
  1199  	require.Len(actual, len(expected))
  1200  	for nodeID, expectedVdr := range expected {
  1201  		require.Contains(actual, nodeID)
  1202  
  1203  		actualVdr := actual[nodeID]
  1204  		require.Equal(expectedVdr.NodeID, actualVdr.NodeID)
  1205  		require.Equal(expectedVdr.PublicKey, actualVdr.PublicKey)
  1206  	}
  1207  }
  1208  
  1209  func TestParsedStateBlock(t *testing.T) {
  1210  	var (
  1211  		require = require.New(t)
  1212  		blks    = makeBlocks(require)
  1213  	)
  1214  
  1215  	for _, blk := range blks {
  1216  		stBlk := stateBlk{
  1217  			Bytes:  blk.Bytes(),
  1218  			Status: choices.Accepted,
  1219  		}
  1220  
  1221  		stBlkBytes, err := block.GenesisCodec.Marshal(block.CodecVersion, &stBlk)
  1222  		require.NoError(err)
  1223  
  1224  		gotBlk, isStateBlk, err := parseStoredBlock(stBlkBytes)
  1225  		require.NoError(err)
  1226  		require.True(isStateBlk)
  1227  		require.Equal(blk.ID(), gotBlk.ID())
  1228  
  1229  		gotBlk, isStateBlk, err = parseStoredBlock(blk.Bytes())
  1230  		require.NoError(err)
  1231  		require.False(isStateBlk)
  1232  		require.Equal(blk.ID(), gotBlk.ID())
  1233  	}
  1234  }
  1235  
  1236  func TestReindexBlocks(t *testing.T) {
  1237  	var (
  1238  		require = require.New(t)
  1239  		s       = newTestState(t, memdb.New())
  1240  		blks    = makeBlocks(require)
  1241  	)
  1242  
  1243  	// Populate the blocks using the legacy format.
  1244  	for _, blk := range blks {
  1245  		stBlk := stateBlk{
  1246  			Bytes:  blk.Bytes(),
  1247  			Status: choices.Accepted,
  1248  		}
  1249  		stBlkBytes, err := block.GenesisCodec.Marshal(block.CodecVersion, &stBlk)
  1250  		require.NoError(err)
  1251  
  1252  		blkID := blk.ID()
  1253  		require.NoError(s.blockDB.Put(blkID[:], stBlkBytes))
  1254  	}
  1255  
  1256  	// Convert the indices to the new format.
  1257  	require.NoError(s.ReindexBlocks(&sync.Mutex{}, logging.NoLog{}))
  1258  
  1259  	// Verify that the blocks are stored in the new format.
  1260  	for _, blk := range blks {
  1261  		blkID := blk.ID()
  1262  		blkBytes, err := s.blockDB.Get(blkID[:])
  1263  		require.NoError(err)
  1264  
  1265  		parsedBlk, err := block.Parse(block.GenesisCodec, blkBytes)
  1266  		require.NoError(err)
  1267  		require.Equal(blkID, parsedBlk.ID())
  1268  	}
  1269  
  1270  	// Verify that the flag has been written to disk to allow skipping future
  1271  	// reindexings.
  1272  	reindexed, err := s.singletonDB.Has(BlocksReindexedKey)
  1273  	require.NoError(err)
  1274  	require.True(reindexed)
  1275  }
  1276  
  1277  func TestStateSubnetOwner(t *testing.T) {
  1278  	require := require.New(t)
  1279  
  1280  	state := newTestState(t, memdb.New())
  1281  	ctrl := gomock.NewController(t)
  1282  
  1283  	var (
  1284  		owner1 = fxmock.NewOwner(ctrl)
  1285  		owner2 = fxmock.NewOwner(ctrl)
  1286  
  1287  		createSubnetTx = &txs.Tx{
  1288  			Unsigned: &txs.CreateSubnetTx{
  1289  				BaseTx: txs.BaseTx{},
  1290  				Owner:  owner1,
  1291  			},
  1292  		}
  1293  
  1294  		subnetID = createSubnetTx.ID()
  1295  	)
  1296  
  1297  	owner, err := state.GetSubnetOwner(subnetID)
  1298  	require.ErrorIs(err, database.ErrNotFound)
  1299  	require.Nil(owner)
  1300  
  1301  	state.AddSubnet(subnetID)
  1302  	state.SetSubnetOwner(subnetID, owner1)
  1303  
  1304  	owner, err = state.GetSubnetOwner(subnetID)
  1305  	require.NoError(err)
  1306  	require.Equal(owner1, owner)
  1307  
  1308  	state.SetSubnetOwner(subnetID, owner2)
  1309  	owner, err = state.GetSubnetOwner(subnetID)
  1310  	require.NoError(err)
  1311  	require.Equal(owner2, owner)
  1312  }
  1313  
  1314  func TestStateSubnetManager(t *testing.T) {
  1315  	tests := []struct {
  1316  		name  string
  1317  		setup func(t *testing.T, s State, subnetID ids.ID, chainID ids.ID, addr []byte)
  1318  	}{
  1319  		{
  1320  			name: "in-memory",
  1321  			setup: func(_ *testing.T, s State, subnetID ids.ID, chainID ids.ID, addr []byte) {
  1322  				s.SetSubnetManager(subnetID, chainID, addr)
  1323  			},
  1324  		},
  1325  		{
  1326  			name: "cache",
  1327  			setup: func(t *testing.T, s State, subnetID ids.ID, chainID ids.ID, addr []byte) {
  1328  				subnetManagerCache := s.(*state).subnetManagerCache
  1329  
  1330  				require.Zero(t, subnetManagerCache.Len())
  1331  				subnetManagerCache.Put(subnetID, chainIDAndAddr{
  1332  					ChainID: chainID,
  1333  					Addr:    addr,
  1334  				})
  1335  				require.Equal(t, 1, subnetManagerCache.Len())
  1336  			},
  1337  		},
  1338  	}
  1339  	for _, test := range tests {
  1340  		t.Run(test.name, func(t *testing.T) {
  1341  			require := require.New(t)
  1342  
  1343  			initializedState := newTestState(t, memdb.New())
  1344  
  1345  			subnetID := ids.GenerateTestID()
  1346  			chainID, addr, err := initializedState.GetSubnetManager(subnetID)
  1347  			require.ErrorIs(err, database.ErrNotFound)
  1348  			require.Equal(ids.Empty, chainID)
  1349  			require.Nil(addr)
  1350  
  1351  			expectedChainID := ids.GenerateTestID()
  1352  			expectedAddr := []byte{'a', 'd', 'd', 'r'}
  1353  
  1354  			test.setup(t, initializedState, subnetID, expectedChainID, expectedAddr)
  1355  
  1356  			chainID, addr, err = initializedState.GetSubnetManager(subnetID)
  1357  			require.NoError(err)
  1358  			require.Equal(expectedChainID, chainID)
  1359  			require.Equal(expectedAddr, addr)
  1360  		})
  1361  	}
  1362  }
  1363  
  1364  func makeBlocks(require *require.Assertions) []block.Block {
  1365  	var blks []block.Block
  1366  	{
  1367  		blk, err := block.NewApricotAbortBlock(ids.GenerateTestID(), 1000)
  1368  		require.NoError(err)
  1369  		blks = append(blks, blk)
  1370  	}
  1371  
  1372  	{
  1373  		blk, err := block.NewApricotAtomicBlock(ids.GenerateTestID(), 1000, &txs.Tx{
  1374  			Unsigned: &txs.AdvanceTimeTx{
  1375  				Time: 1000,
  1376  			},
  1377  		})
  1378  		require.NoError(err)
  1379  		blks = append(blks, blk)
  1380  	}
  1381  
  1382  	{
  1383  		blk, err := block.NewApricotCommitBlock(ids.GenerateTestID(), 1000)
  1384  		require.NoError(err)
  1385  		blks = append(blks, blk)
  1386  	}
  1387  
  1388  	{
  1389  		tx := &txs.Tx{
  1390  			Unsigned: &txs.RewardValidatorTx{
  1391  				TxID: ids.GenerateTestID(),
  1392  			},
  1393  		}
  1394  		require.NoError(tx.Initialize(txs.Codec))
  1395  		blk, err := block.NewApricotProposalBlock(ids.GenerateTestID(), 1000, tx)
  1396  		require.NoError(err)
  1397  		blks = append(blks, blk)
  1398  	}
  1399  
  1400  	{
  1401  		tx := &txs.Tx{
  1402  			Unsigned: &txs.RewardValidatorTx{
  1403  				TxID: ids.GenerateTestID(),
  1404  			},
  1405  		}
  1406  		require.NoError(tx.Initialize(txs.Codec))
  1407  		blk, err := block.NewApricotStandardBlock(ids.GenerateTestID(), 1000, []*txs.Tx{tx})
  1408  		require.NoError(err)
  1409  		blks = append(blks, blk)
  1410  	}
  1411  
  1412  	{
  1413  		blk, err := block.NewBanffAbortBlock(time.Now(), ids.GenerateTestID(), 1000)
  1414  		require.NoError(err)
  1415  		blks = append(blks, blk)
  1416  	}
  1417  
  1418  	{
  1419  		blk, err := block.NewBanffCommitBlock(time.Now(), ids.GenerateTestID(), 1000)
  1420  		require.NoError(err)
  1421  		blks = append(blks, blk)
  1422  	}
  1423  
  1424  	{
  1425  		tx := &txs.Tx{
  1426  			Unsigned: &txs.RewardValidatorTx{
  1427  				TxID: ids.GenerateTestID(),
  1428  			},
  1429  		}
  1430  		require.NoError(tx.Initialize(txs.Codec))
  1431  
  1432  		blk, err := block.NewBanffProposalBlock(time.Now(), ids.GenerateTestID(), 1000, tx, []*txs.Tx{})
  1433  		require.NoError(err)
  1434  		blks = append(blks, blk)
  1435  	}
  1436  
  1437  	{
  1438  		tx := &txs.Tx{
  1439  			Unsigned: &txs.RewardValidatorTx{
  1440  				TxID: ids.GenerateTestID(),
  1441  			},
  1442  		}
  1443  		require.NoError(tx.Initialize(txs.Codec))
  1444  
  1445  		blk, err := block.NewBanffStandardBlock(time.Now(), ids.GenerateTestID(), 1000, []*txs.Tx{tx})
  1446  		require.NoError(err)
  1447  		blks = append(blks, blk)
  1448  	}
  1449  	return blks
  1450  }
  1451  
  1452  // Verify that committing the state writes the fee state to the database and
  1453  // that loading the state fetches the fee state from the database.
  1454  func TestStateFeeStateCommitAndLoad(t *testing.T) {
  1455  	require := require.New(t)
  1456  
  1457  	db := memdb.New()
  1458  	s := newTestState(t, db)
  1459  
  1460  	expectedFeeState := gas.State{
  1461  		Capacity: 1,
  1462  		Excess:   2,
  1463  	}
  1464  	s.SetFeeState(expectedFeeState)
  1465  	require.NoError(s.Commit())
  1466  
  1467  	s = newTestState(t, db)
  1468  	require.Equal(expectedFeeState, s.GetFeeState())
  1469  }
  1470  
  1471  func TestMarkAndIsInitialized(t *testing.T) {
  1472  	require := require.New(t)
  1473  
  1474  	db := memdb.New()
  1475  	defaultIsInitialized, err := isInitialized(db)
  1476  	require.NoError(err)
  1477  	require.False(defaultIsInitialized)
  1478  
  1479  	require.NoError(markInitialized(db))
  1480  
  1481  	isInitializedAfterMarking, err := isInitialized(db)
  1482  	require.NoError(err)
  1483  	require.True(isInitializedAfterMarking)
  1484  }
  1485  
  1486  // Verify that reading from the database returns the same value that was written
  1487  // to it.
  1488  func TestPutAndGetFeeState(t *testing.T) {
  1489  	require := require.New(t)
  1490  
  1491  	db := memdb.New()
  1492  	defaultFeeState, err := getFeeState(db)
  1493  	require.NoError(err)
  1494  	require.Equal(gas.State{}, defaultFeeState)
  1495  
  1496  	//nolint:gosec // This does not require a secure random number generator
  1497  	expectedFeeState := gas.State{
  1498  		Capacity: gas.Gas(rand.Uint64()),
  1499  		Excess:   gas.Gas(rand.Uint64()),
  1500  	}
  1501  	require.NoError(putFeeState(db, expectedFeeState))
  1502  
  1503  	actualFeeState, err := getFeeState(db)
  1504  	require.NoError(err)
  1505  	require.Equal(expectedFeeState, actualFeeState)
  1506  }
  1507  
  1508  func TestGetFeeStateErrors(t *testing.T) {
  1509  	tests := []struct {
  1510  		value       []byte
  1511  		expectedErr error
  1512  	}{
  1513  		{
  1514  			value: []byte{
  1515  				// truncated codec version
  1516  				0x00,
  1517  			},
  1518  			expectedErr: codec.ErrCantUnpackVersion,
  1519  		},
  1520  		{
  1521  			value: []byte{
  1522  				// codec version
  1523  				0x00, 0x00,
  1524  				// truncated capacity
  1525  				0x12, 0x34, 0x56, 0x78,
  1526  			},
  1527  			expectedErr: wrappers.ErrInsufficientLength,
  1528  		},
  1529  		{
  1530  			value: []byte{
  1531  				// codec version
  1532  				0x00, 0x00,
  1533  				// capacity
  1534  				0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78,
  1535  				// excess
  1536  				0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78,
  1537  				// extra bytes
  1538  				0x00,
  1539  			},
  1540  			expectedErr: codec.ErrExtraSpace,
  1541  		},
  1542  	}
  1543  	for _, test := range tests {
  1544  		t.Run(test.expectedErr.Error(), func(t *testing.T) {
  1545  			var (
  1546  				require = require.New(t)
  1547  				db      = memdb.New()
  1548  			)
  1549  			require.NoError(db.Put(FeeStateKey, test.value))
  1550  
  1551  			actualState, err := getFeeState(db)
  1552  			require.Equal(gas.State{}, actualState)
  1553  			require.ErrorIs(err, test.expectedErr)
  1554  		})
  1555  	}
  1556  }