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