github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/state/diff_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  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/require"
    11  	"go.uber.org/mock/gomock"
    12  
    13  	"github.com/ava-labs/avalanchego/database"
    14  	"github.com/ava-labs/avalanchego/database/memdb"
    15  	"github.com/ava-labs/avalanchego/ids"
    16  	"github.com/ava-labs/avalanchego/utils"
    17  	"github.com/ava-labs/avalanchego/utils/constants"
    18  	"github.com/ava-labs/avalanchego/utils/iterator/iteratormock"
    19  	"github.com/ava-labs/avalanchego/vms/components/avax"
    20  	"github.com/ava-labs/avalanchego/vms/components/gas"
    21  	"github.com/ava-labs/avalanchego/vms/platformvm/fx/fxmock"
    22  	"github.com/ava-labs/avalanchego/vms/platformvm/status"
    23  	"github.com/ava-labs/avalanchego/vms/platformvm/txs"
    24  )
    25  
    26  type nilStateGetter struct{}
    27  
    28  func (nilStateGetter) GetState(ids.ID) (Chain, bool) {
    29  	return nil, false
    30  }
    31  
    32  func TestDiffMissingState(t *testing.T) {
    33  	parentID := ids.GenerateTestID()
    34  	_, err := NewDiff(parentID, nilStateGetter{})
    35  	require.ErrorIs(t, err, ErrMissingParentState)
    36  }
    37  
    38  func TestNewDiffOn(t *testing.T) {
    39  	require := require.New(t)
    40  
    41  	state := newTestState(t, memdb.New())
    42  
    43  	d, err := NewDiffOn(state)
    44  	require.NoError(err)
    45  
    46  	assertChainsEqual(t, state, d)
    47  }
    48  
    49  func TestDiffFeeState(t *testing.T) {
    50  	require := require.New(t)
    51  
    52  	state := newTestState(t, memdb.New())
    53  
    54  	d, err := NewDiffOn(state)
    55  	require.NoError(err)
    56  
    57  	initialFeeState := state.GetFeeState()
    58  	newFeeState := gas.State{
    59  		Capacity: initialFeeState.Capacity + 1,
    60  		Excess:   initialFeeState.Excess + 1,
    61  	}
    62  	d.SetFeeState(newFeeState)
    63  	require.Equal(newFeeState, d.GetFeeState())
    64  	require.Equal(initialFeeState, state.GetFeeState())
    65  
    66  	require.NoError(d.Apply(state))
    67  	assertChainsEqual(t, state, d)
    68  }
    69  
    70  func TestDiffCurrentSupply(t *testing.T) {
    71  	require := require.New(t)
    72  
    73  	state := newTestState(t, memdb.New())
    74  
    75  	d, err := NewDiffOn(state)
    76  	require.NoError(err)
    77  
    78  	initialCurrentSupply, err := d.GetCurrentSupply(constants.PrimaryNetworkID)
    79  	require.NoError(err)
    80  
    81  	newCurrentSupply := initialCurrentSupply + 1
    82  	d.SetCurrentSupply(constants.PrimaryNetworkID, newCurrentSupply)
    83  
    84  	returnedNewCurrentSupply, err := d.GetCurrentSupply(constants.PrimaryNetworkID)
    85  	require.NoError(err)
    86  	require.Equal(newCurrentSupply, returnedNewCurrentSupply)
    87  
    88  	returnedBaseCurrentSupply, err := state.GetCurrentSupply(constants.PrimaryNetworkID)
    89  	require.NoError(err)
    90  	require.Equal(initialCurrentSupply, returnedBaseCurrentSupply)
    91  
    92  	require.NoError(d.Apply(state))
    93  	assertChainsEqual(t, state, d)
    94  }
    95  
    96  func TestDiffCurrentValidator(t *testing.T) {
    97  	require := require.New(t)
    98  	ctrl := gomock.NewController(t)
    99  
   100  	state := NewMockState(ctrl)
   101  	// Called in NewDiffOn
   102  	state.EXPECT().GetTimestamp().Return(time.Now()).Times(1)
   103  	state.EXPECT().GetFeeState().Return(gas.State{}).Times(1)
   104  
   105  	d, err := NewDiffOn(state)
   106  	require.NoError(err)
   107  
   108  	// Put a current validator
   109  	currentValidator := &Staker{
   110  		TxID:     ids.GenerateTestID(),
   111  		SubnetID: ids.GenerateTestID(),
   112  		NodeID:   ids.GenerateTestNodeID(),
   113  	}
   114  	require.NoError(d.PutCurrentValidator(currentValidator))
   115  
   116  	// Assert that we get the current validator back
   117  	gotCurrentValidator, err := d.GetCurrentValidator(currentValidator.SubnetID, currentValidator.NodeID)
   118  	require.NoError(err)
   119  	require.Equal(currentValidator, gotCurrentValidator)
   120  
   121  	// Delete the current validator
   122  	d.DeleteCurrentValidator(currentValidator)
   123  
   124  	// Make sure the deletion worked
   125  	state.EXPECT().GetCurrentValidator(currentValidator.SubnetID, currentValidator.NodeID).Return(nil, database.ErrNotFound).Times(1)
   126  	_, err = d.GetCurrentValidator(currentValidator.SubnetID, currentValidator.NodeID)
   127  	require.ErrorIs(err, database.ErrNotFound)
   128  }
   129  
   130  func TestDiffPendingValidator(t *testing.T) {
   131  	require := require.New(t)
   132  	ctrl := gomock.NewController(t)
   133  
   134  	state := NewMockState(ctrl)
   135  	// Called in NewDiffOn
   136  	state.EXPECT().GetTimestamp().Return(time.Now()).Times(1)
   137  	state.EXPECT().GetFeeState().Return(gas.State{}).Times(1)
   138  
   139  	d, err := NewDiffOn(state)
   140  	require.NoError(err)
   141  
   142  	// Put a pending validator
   143  	pendingValidator := &Staker{
   144  		TxID:     ids.GenerateTestID(),
   145  		SubnetID: ids.GenerateTestID(),
   146  		NodeID:   ids.GenerateTestNodeID(),
   147  	}
   148  	require.NoError(d.PutPendingValidator(pendingValidator))
   149  
   150  	// Assert that we get the pending validator back
   151  	gotPendingValidator, err := d.GetPendingValidator(pendingValidator.SubnetID, pendingValidator.NodeID)
   152  	require.NoError(err)
   153  	require.Equal(pendingValidator, gotPendingValidator)
   154  
   155  	// Delete the pending validator
   156  	d.DeletePendingValidator(pendingValidator)
   157  
   158  	// Make sure the deletion worked
   159  	state.EXPECT().GetPendingValidator(pendingValidator.SubnetID, pendingValidator.NodeID).Return(nil, database.ErrNotFound).Times(1)
   160  	_, err = d.GetPendingValidator(pendingValidator.SubnetID, pendingValidator.NodeID)
   161  	require.ErrorIs(err, database.ErrNotFound)
   162  }
   163  
   164  func TestDiffCurrentDelegator(t *testing.T) {
   165  	require := require.New(t)
   166  	ctrl := gomock.NewController(t)
   167  
   168  	currentDelegator := &Staker{
   169  		TxID:     ids.GenerateTestID(),
   170  		SubnetID: ids.GenerateTestID(),
   171  		NodeID:   ids.GenerateTestNodeID(),
   172  	}
   173  
   174  	state := NewMockState(ctrl)
   175  	// Called in NewDiffOn
   176  	state.EXPECT().GetTimestamp().Return(time.Now()).Times(1)
   177  	state.EXPECT().GetFeeState().Return(gas.State{}).Times(1)
   178  
   179  	d, err := NewDiffOn(state)
   180  	require.NoError(err)
   181  
   182  	// Put a current delegator
   183  	d.PutCurrentDelegator(currentDelegator)
   184  
   185  	// Assert that we get the current delegator back
   186  	// Mock iterator for [state] returns no delegators.
   187  	stateCurrentDelegatorIter := iteratormock.NewIterator[*Staker](ctrl)
   188  	stateCurrentDelegatorIter.EXPECT().Next().Return(false).Times(2)
   189  	stateCurrentDelegatorIter.EXPECT().Release().Times(2)
   190  	state.EXPECT().GetCurrentDelegatorIterator(
   191  		currentDelegator.SubnetID,
   192  		currentDelegator.NodeID,
   193  	).Return(stateCurrentDelegatorIter, nil).Times(2)
   194  	gotCurrentDelegatorIter, err := d.GetCurrentDelegatorIterator(currentDelegator.SubnetID, currentDelegator.NodeID)
   195  	require.NoError(err)
   196  	// The iterator should have the 1 delegator we put in [d]
   197  	require.True(gotCurrentDelegatorIter.Next())
   198  	require.Equal(gotCurrentDelegatorIter.Value(), currentDelegator)
   199  
   200  	// Delete the current delegator
   201  	d.DeleteCurrentDelegator(currentDelegator)
   202  
   203  	// Make sure the deletion worked.
   204  	// The iterator should have no elements.
   205  	gotCurrentDelegatorIter, err = d.GetCurrentDelegatorIterator(currentDelegator.SubnetID, currentDelegator.NodeID)
   206  	require.NoError(err)
   207  	require.False(gotCurrentDelegatorIter.Next())
   208  }
   209  
   210  func TestDiffPendingDelegator(t *testing.T) {
   211  	require := require.New(t)
   212  	ctrl := gomock.NewController(t)
   213  
   214  	pendingDelegator := &Staker{
   215  		TxID:     ids.GenerateTestID(),
   216  		SubnetID: ids.GenerateTestID(),
   217  		NodeID:   ids.GenerateTestNodeID(),
   218  	}
   219  
   220  	state := NewMockState(ctrl)
   221  	// Called in NewDiffOn
   222  	state.EXPECT().GetTimestamp().Return(time.Now()).Times(1)
   223  	state.EXPECT().GetFeeState().Return(gas.State{}).Times(1)
   224  
   225  	d, err := NewDiffOn(state)
   226  	require.NoError(err)
   227  
   228  	// Put a pending delegator
   229  	d.PutPendingDelegator(pendingDelegator)
   230  
   231  	// Assert that we get the pending delegator back
   232  	// Mock iterator for [state] returns no delegators.
   233  	statePendingDelegatorIter := iteratormock.NewIterator[*Staker](ctrl)
   234  	statePendingDelegatorIter.EXPECT().Next().Return(false).Times(2)
   235  	statePendingDelegatorIter.EXPECT().Release().Times(2)
   236  	state.EXPECT().GetPendingDelegatorIterator(
   237  		pendingDelegator.SubnetID,
   238  		pendingDelegator.NodeID,
   239  	).Return(statePendingDelegatorIter, nil).Times(2)
   240  	gotPendingDelegatorIter, err := d.GetPendingDelegatorIterator(pendingDelegator.SubnetID, pendingDelegator.NodeID)
   241  	require.NoError(err)
   242  	// The iterator should have the 1 delegator we put in [d]
   243  	require.True(gotPendingDelegatorIter.Next())
   244  	require.Equal(gotPendingDelegatorIter.Value(), pendingDelegator)
   245  
   246  	// Delete the pending delegator
   247  	d.DeletePendingDelegator(pendingDelegator)
   248  
   249  	// Make sure the deletion worked.
   250  	// The iterator should have no elements.
   251  	gotPendingDelegatorIter, err = d.GetPendingDelegatorIterator(pendingDelegator.SubnetID, pendingDelegator.NodeID)
   252  	require.NoError(err)
   253  	require.False(gotPendingDelegatorIter.Next())
   254  }
   255  
   256  func TestDiffSubnet(t *testing.T) {
   257  	require := require.New(t)
   258  	ctrl := gomock.NewController(t)
   259  
   260  	state := newTestState(t, memdb.New())
   261  
   262  	// Initialize parent with one subnet
   263  	parentStateCreateSubnetTx := &txs.Tx{
   264  		Unsigned: &txs.CreateSubnetTx{
   265  			Owner: fxmock.NewOwner(ctrl),
   266  		},
   267  	}
   268  	state.AddSubnet(parentStateCreateSubnetTx.ID())
   269  
   270  	// Verify parent returns one subnet
   271  	subnetIDs, err := state.GetSubnetIDs()
   272  	require.NoError(err)
   273  	require.Equal(
   274  		[]ids.ID{
   275  			parentStateCreateSubnetTx.ID(),
   276  		},
   277  		subnetIDs,
   278  	)
   279  
   280  	diff, err := NewDiffOn(state)
   281  	require.NoError(err)
   282  
   283  	// Put a subnet
   284  	createSubnetTx := &txs.Tx{
   285  		Unsigned: &txs.CreateSubnetTx{
   286  			Owner: fxmock.NewOwner(ctrl),
   287  		},
   288  	}
   289  	diff.AddSubnet(createSubnetTx.ID())
   290  
   291  	// Apply diff to parent state
   292  	require.NoError(diff.Apply(state))
   293  
   294  	// Verify parent now returns two subnets
   295  	subnetIDs, err = state.GetSubnetIDs()
   296  	require.NoError(err)
   297  	require.Equal(
   298  		[]ids.ID{
   299  			parentStateCreateSubnetTx.ID(),
   300  			createSubnetTx.ID(),
   301  		},
   302  		subnetIDs,
   303  	)
   304  }
   305  
   306  func TestDiffChain(t *testing.T) {
   307  	require := require.New(t)
   308  
   309  	state := newTestState(t, memdb.New())
   310  	subnetID := ids.GenerateTestID()
   311  
   312  	// Initialize parent with one chain
   313  	parentStateCreateChainTx := &txs.Tx{
   314  		Unsigned: &txs.CreateChainTx{
   315  			SubnetID: subnetID,
   316  		},
   317  	}
   318  	state.AddChain(parentStateCreateChainTx)
   319  
   320  	// Verify parent returns one chain
   321  	chains, err := state.GetChains(subnetID)
   322  	require.NoError(err)
   323  	require.Equal(
   324  		[]*txs.Tx{
   325  			parentStateCreateChainTx,
   326  		},
   327  		chains,
   328  	)
   329  
   330  	diff, err := NewDiffOn(state)
   331  	require.NoError(err)
   332  
   333  	// Put a chain
   334  	createChainTx := &txs.Tx{
   335  		Unsigned: &txs.CreateChainTx{
   336  			SubnetID: subnetID, // note this is the same subnet as [parentStateCreateChainTx]
   337  		},
   338  	}
   339  	diff.AddChain(createChainTx)
   340  
   341  	// Apply diff to parent state
   342  	require.NoError(diff.Apply(state))
   343  
   344  	// Verify parent now returns two chains
   345  	chains, err = state.GetChains(subnetID)
   346  	require.NoError(err)
   347  	require.Equal(
   348  		[]*txs.Tx{
   349  			parentStateCreateChainTx,
   350  			createChainTx,
   351  		},
   352  		chains,
   353  	)
   354  }
   355  
   356  func TestDiffTx(t *testing.T) {
   357  	require := require.New(t)
   358  	ctrl := gomock.NewController(t)
   359  
   360  	state := NewMockState(ctrl)
   361  	// Called in NewDiffOn
   362  	state.EXPECT().GetTimestamp().Return(time.Now()).Times(1)
   363  	state.EXPECT().GetFeeState().Return(gas.State{}).Times(1)
   364  
   365  	d, err := NewDiffOn(state)
   366  	require.NoError(err)
   367  
   368  	// Put a tx
   369  	subnetID := ids.GenerateTestID()
   370  	tx := &txs.Tx{
   371  		Unsigned: &txs.CreateChainTx{
   372  			SubnetID: subnetID,
   373  		},
   374  	}
   375  	tx.SetBytes(utils.RandomBytes(16), utils.RandomBytes(16))
   376  	d.AddTx(tx, status.Committed)
   377  
   378  	{
   379  		// Assert that we get the tx back
   380  		gotTx, gotStatus, err := d.GetTx(tx.ID())
   381  		require.NoError(err)
   382  		require.Equal(status.Committed, gotStatus)
   383  		require.Equal(tx, gotTx)
   384  	}
   385  
   386  	{
   387  		// Assert that we can get a tx from the parent state
   388  		// [state] returns 1 tx.
   389  		parentTx := &txs.Tx{
   390  			Unsigned: &txs.CreateChainTx{
   391  				SubnetID: subnetID,
   392  			},
   393  		}
   394  		parentTx.SetBytes(utils.RandomBytes(16), utils.RandomBytes(16))
   395  		state.EXPECT().GetTx(parentTx.ID()).Return(parentTx, status.Committed, nil).Times(1)
   396  		gotParentTx, gotStatus, err := d.GetTx(parentTx.ID())
   397  		require.NoError(err)
   398  		require.Equal(status.Committed, gotStatus)
   399  		require.Equal(parentTx, gotParentTx)
   400  	}
   401  }
   402  
   403  func TestDiffRewardUTXO(t *testing.T) {
   404  	require := require.New(t)
   405  
   406  	state := newTestState(t, memdb.New())
   407  
   408  	// Initialize parent with one reward UTXO
   409  	var (
   410  		txID             = ids.GenerateTestID()
   411  		parentRewardUTXO = &avax.UTXO{
   412  			UTXOID: avax.UTXOID{
   413  				TxID: txID,
   414  			},
   415  		}
   416  	)
   417  	state.AddRewardUTXO(txID, parentRewardUTXO)
   418  
   419  	// Verify parent returns the reward UTXO
   420  	rewardUTXOs, err := state.GetRewardUTXOs(txID)
   421  	require.NoError(err)
   422  	require.Equal(
   423  		[]*avax.UTXO{
   424  			parentRewardUTXO,
   425  		},
   426  		rewardUTXOs,
   427  	)
   428  
   429  	diff, err := NewDiffOn(state)
   430  	require.NoError(err)
   431  
   432  	// Put a reward UTXO
   433  	rewardUTXO := &avax.UTXO{
   434  		UTXOID: avax.UTXOID{TxID: txID},
   435  	}
   436  	diff.AddRewardUTXO(txID, rewardUTXO)
   437  
   438  	// Apply diff to parent state
   439  	require.NoError(diff.Apply(state))
   440  
   441  	// Verify parent now returns two reward UTXOs
   442  	rewardUTXOs, err = state.GetRewardUTXOs(txID)
   443  	require.NoError(err)
   444  	require.Equal(
   445  		[]*avax.UTXO{
   446  			parentRewardUTXO,
   447  			rewardUTXO,
   448  		},
   449  		rewardUTXOs,
   450  	)
   451  }
   452  
   453  func TestDiffUTXO(t *testing.T) {
   454  	require := require.New(t)
   455  	ctrl := gomock.NewController(t)
   456  
   457  	state := NewMockState(ctrl)
   458  	// Called in NewDiffOn
   459  	state.EXPECT().GetTimestamp().Return(time.Now()).Times(1)
   460  	state.EXPECT().GetFeeState().Return(gas.State{}).Times(1)
   461  
   462  	d, err := NewDiffOn(state)
   463  	require.NoError(err)
   464  
   465  	// Put a UTXO
   466  	utxo := &avax.UTXO{
   467  		UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()},
   468  	}
   469  	d.AddUTXO(utxo)
   470  
   471  	{
   472  		// Assert that we get the UTXO back
   473  		gotUTXO, err := d.GetUTXO(utxo.InputID())
   474  		require.NoError(err)
   475  		require.Equal(utxo, gotUTXO)
   476  	}
   477  
   478  	{
   479  		// Assert that we can get a UTXO from the parent state
   480  		// [state] returns 1 UTXO.
   481  		parentUTXO := &avax.UTXO{
   482  			UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()},
   483  		}
   484  		state.EXPECT().GetUTXO(parentUTXO.InputID()).Return(parentUTXO, nil).Times(1)
   485  		gotParentUTXO, err := d.GetUTXO(parentUTXO.InputID())
   486  		require.NoError(err)
   487  		require.Equal(parentUTXO, gotParentUTXO)
   488  	}
   489  
   490  	{
   491  		// Delete the UTXO
   492  		d.DeleteUTXO(utxo.InputID())
   493  
   494  		// Make sure it's gone
   495  		_, err = d.GetUTXO(utxo.InputID())
   496  		require.ErrorIs(err, database.ErrNotFound)
   497  	}
   498  }
   499  
   500  func assertChainsEqual(t *testing.T, expected, actual Chain) {
   501  	require := require.New(t)
   502  
   503  	t.Helper()
   504  
   505  	expectedCurrentStakerIterator, expectedErr := expected.GetCurrentStakerIterator()
   506  	actualCurrentStakerIterator, actualErr := actual.GetCurrentStakerIterator()
   507  	require.Equal(expectedErr, actualErr)
   508  	if expectedErr == nil {
   509  		assertIteratorsEqual(t, expectedCurrentStakerIterator, actualCurrentStakerIterator)
   510  	}
   511  
   512  	expectedPendingStakerIterator, expectedErr := expected.GetPendingStakerIterator()
   513  	actualPendingStakerIterator, actualErr := actual.GetPendingStakerIterator()
   514  	require.Equal(expectedErr, actualErr)
   515  	if expectedErr == nil {
   516  		assertIteratorsEqual(t, expectedPendingStakerIterator, actualPendingStakerIterator)
   517  	}
   518  
   519  	require.Equal(expected.GetTimestamp(), actual.GetTimestamp())
   520  	require.Equal(expected.GetFeeState(), actual.GetFeeState())
   521  
   522  	expectedCurrentSupply, err := expected.GetCurrentSupply(constants.PrimaryNetworkID)
   523  	require.NoError(err)
   524  
   525  	actualCurrentSupply, err := actual.GetCurrentSupply(constants.PrimaryNetworkID)
   526  	require.NoError(err)
   527  
   528  	require.Equal(expectedCurrentSupply, actualCurrentSupply)
   529  }
   530  
   531  func TestDiffSubnetOwner(t *testing.T) {
   532  	require := require.New(t)
   533  	ctrl := gomock.NewController(t)
   534  
   535  	state := newTestState(t, memdb.New())
   536  
   537  	var (
   538  		owner1 = fxmock.NewOwner(ctrl)
   539  		owner2 = fxmock.NewOwner(ctrl)
   540  
   541  		createSubnetTx = &txs.Tx{
   542  			Unsigned: &txs.CreateSubnetTx{
   543  				BaseTx: txs.BaseTx{},
   544  				Owner:  owner1,
   545  			},
   546  		}
   547  
   548  		subnetID = createSubnetTx.ID()
   549  	)
   550  
   551  	// Create subnet on base state
   552  	owner, err := state.GetSubnetOwner(subnetID)
   553  	require.ErrorIs(err, database.ErrNotFound)
   554  	require.Nil(owner)
   555  
   556  	state.AddSubnet(subnetID)
   557  	state.SetSubnetOwner(subnetID, owner1)
   558  
   559  	owner, err = state.GetSubnetOwner(subnetID)
   560  	require.NoError(err)
   561  	require.Equal(owner1, owner)
   562  
   563  	// Create diff and verify that subnet owner returns correctly
   564  	d, err := NewDiffOn(state)
   565  	require.NoError(err)
   566  
   567  	owner, err = d.GetSubnetOwner(subnetID)
   568  	require.NoError(err)
   569  	require.Equal(owner1, owner)
   570  
   571  	// Transferring subnet ownership on diff should be reflected on diff not state
   572  	d.SetSubnetOwner(subnetID, owner2)
   573  	owner, err = d.GetSubnetOwner(subnetID)
   574  	require.NoError(err)
   575  	require.Equal(owner2, owner)
   576  
   577  	owner, err = state.GetSubnetOwner(subnetID)
   578  	require.NoError(err)
   579  	require.Equal(owner1, owner)
   580  
   581  	// State should reflect new subnet owner after diff is applied.
   582  	require.NoError(d.Apply(state))
   583  
   584  	owner, err = state.GetSubnetOwner(subnetID)
   585  	require.NoError(err)
   586  	require.Equal(owner2, owner)
   587  }
   588  
   589  func TestDiffSubnetManager(t *testing.T) {
   590  	var (
   591  		require    = require.New(t)
   592  		state      = newTestState(t, memdb.New())
   593  		newManager = chainIDAndAddr{ids.GenerateTestID(), []byte{1, 2, 3, 4}}
   594  		subnetID   = ids.GenerateTestID()
   595  	)
   596  
   597  	chainID, addr, err := state.GetSubnetManager(subnetID)
   598  	require.ErrorIs(err, database.ErrNotFound)
   599  	require.Equal(ids.Empty, chainID)
   600  	require.Nil(addr)
   601  
   602  	d, err := NewDiffOn(state)
   603  	require.NoError(err)
   604  
   605  	chainID, addr, err = d.GetSubnetManager(subnetID)
   606  	require.ErrorIs(err, database.ErrNotFound)
   607  	require.Equal(ids.Empty, chainID)
   608  	require.Nil(addr)
   609  
   610  	// Setting a subnet manager should be reflected on diff not state
   611  	d.SetSubnetManager(subnetID, newManager.ChainID, newManager.Addr)
   612  	chainID, addr, err = d.GetSubnetManager(subnetID)
   613  	require.NoError(err)
   614  	require.Equal(newManager.ChainID, chainID)
   615  	require.Equal(newManager.Addr, addr)
   616  
   617  	chainID, addr, err = state.GetSubnetManager(subnetID)
   618  	require.ErrorIs(err, database.ErrNotFound)
   619  	require.Equal(ids.Empty, chainID)
   620  	require.Nil(addr)
   621  
   622  	// State should reflect new subnet manager after diff is applied
   623  	require.NoError(d.Apply(state))
   624  
   625  	chainID, addr, err = state.GetSubnetManager(subnetID)
   626  	require.NoError(err)
   627  	require.Equal(newManager.ChainID, chainID)
   628  	require.Equal(newManager.Addr, addr)
   629  }
   630  
   631  func TestDiffStacking(t *testing.T) {
   632  	require := require.New(t)
   633  	ctrl := gomock.NewController(t)
   634  
   635  	state := newTestState(t, memdb.New())
   636  
   637  	var (
   638  		owner1 = fxmock.NewOwner(ctrl)
   639  		owner2 = fxmock.NewOwner(ctrl)
   640  		owner3 = fxmock.NewOwner(ctrl)
   641  
   642  		createSubnetTx = &txs.Tx{
   643  			Unsigned: &txs.CreateSubnetTx{
   644  				BaseTx: txs.BaseTx{},
   645  				Owner:  owner1,
   646  			},
   647  		}
   648  
   649  		subnetID = createSubnetTx.ID()
   650  	)
   651  
   652  	// Create subnet on base state
   653  	owner, err := state.GetSubnetOwner(subnetID)
   654  	require.ErrorIs(err, database.ErrNotFound)
   655  	require.Nil(owner)
   656  
   657  	state.AddSubnet(subnetID)
   658  	state.SetSubnetOwner(subnetID, owner1)
   659  
   660  	owner, err = state.GetSubnetOwner(subnetID)
   661  	require.NoError(err)
   662  	require.Equal(owner1, owner)
   663  
   664  	// Create first diff and verify that subnet owner returns correctly
   665  	statesDiff, err := NewDiffOn(state)
   666  	require.NoError(err)
   667  
   668  	owner, err = statesDiff.GetSubnetOwner(subnetID)
   669  	require.NoError(err)
   670  	require.Equal(owner1, owner)
   671  
   672  	// Transferring subnet ownership on first diff should be reflected on first diff not state
   673  	statesDiff.SetSubnetOwner(subnetID, owner2)
   674  	owner, err = statesDiff.GetSubnetOwner(subnetID)
   675  	require.NoError(err)
   676  	require.Equal(owner2, owner)
   677  
   678  	owner, err = state.GetSubnetOwner(subnetID)
   679  	require.NoError(err)
   680  	require.Equal(owner1, owner)
   681  
   682  	// Create a second diff on first diff and verify that subnet owner returns correctly
   683  	stackedDiff, err := NewDiffOn(statesDiff)
   684  	require.NoError(err)
   685  	owner, err = stackedDiff.GetSubnetOwner(subnetID)
   686  	require.NoError(err)
   687  	require.Equal(owner2, owner)
   688  
   689  	// Transfer ownership on stacked diff and verify it is only reflected on stacked diff
   690  	stackedDiff.SetSubnetOwner(subnetID, owner3)
   691  	owner, err = stackedDiff.GetSubnetOwner(subnetID)
   692  	require.NoError(err)
   693  	require.Equal(owner3, owner)
   694  
   695  	owner, err = statesDiff.GetSubnetOwner(subnetID)
   696  	require.NoError(err)
   697  	require.Equal(owner2, owner)
   698  
   699  	owner, err = state.GetSubnetOwner(subnetID)
   700  	require.NoError(err)
   701  	require.Equal(owner1, owner)
   702  
   703  	// Applying both diffs successively should work as expected.
   704  	require.NoError(stackedDiff.Apply(statesDiff))
   705  
   706  	owner, err = statesDiff.GetSubnetOwner(subnetID)
   707  	require.NoError(err)
   708  	require.Equal(owner3, owner)
   709  
   710  	owner, err = state.GetSubnetOwner(subnetID)
   711  	require.NoError(err)
   712  	require.Equal(owner1, owner)
   713  
   714  	require.NoError(statesDiff.Apply(state))
   715  
   716  	owner, err = state.GetSubnetOwner(subnetID)
   717  	require.NoError(err)
   718  	require.Equal(owner3, owner)
   719  }