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 }