From 9b851419158596a5c200e47d83108a71bea8bddb Mon Sep 17 00:00:00 2001 From: Dhruba Basu <7675102+dhrubabasu@users.noreply.github.com> Date: Thu, 30 Nov 2023 12:42:36 -0800 Subject: [PATCH] `vms/platformvm`: Move `GetRewardUTXOs`, `GetSubnets`, and `GetChains` to `State` interface (#2402) --- vms/platformvm/state/diff.go | 97 +---------------- vms/platformvm/state/diff_test.go | 164 +++++++++++++++-------------- vms/platformvm/state/mock_state.go | 90 ---------------- vms/platformvm/state/state.go | 7 +- 4 files changed, 88 insertions(+), 270 deletions(-) diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index 1aafcf079969..d509fa69e0dd 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -47,10 +47,8 @@ type diff struct { subnetOwners map[ids.ID]fx.Owner // Subnet ID --> Tx that transforms the subnet transformedSubnets map[ids.ID]*txs.Tx - cachedSubnets []*txs.Tx - addedChains map[ids.ID][]*txs.Tx - cachedChains map[ids.ID][]*txs.Tx + addedChains map[ids.ID][]*txs.Tx addedRewardUTXOs map[ids.ID][]*avax.UTXO @@ -259,41 +257,8 @@ func (d *diff) GetPendingStakerIterator() (StakerIterator, error) { return d.pendingStakerDiffs.GetStakerIterator(parentIterator), nil } -func (d *diff) GetSubnets() ([]*txs.Tx, error) { - if len(d.addedSubnets) == 0 { - parentState, ok := d.stateVersions.GetState(d.parentID) - if !ok { - return nil, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) - } - return parentState.GetSubnets() - } - - if len(d.cachedSubnets) != 0 { - return d.cachedSubnets, nil - } - - parentState, ok := d.stateVersions.GetState(d.parentID) - if !ok { - return nil, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) - } - subnets, err := parentState.GetSubnets() - if err != nil { - return nil, err - } - newSubnets := make([]*txs.Tx, len(subnets)+len(d.addedSubnets)) - copy(newSubnets, subnets) - for i, subnet := range d.addedSubnets { - newSubnets[i+len(subnets)] = subnet - } - d.cachedSubnets = newSubnets - return newSubnets, nil -} - func (d *diff) AddSubnet(createSubnetTx *txs.Tx) { d.addedSubnets = append(d.addedSubnets, createSubnetTx) - if d.cachedSubnets != nil { - d.cachedSubnets = append(d.cachedSubnets, createSubnetTx) - } } func (d *diff) GetSubnetOwner(subnetID ids.ID) (fx.Owner, error) { @@ -339,48 +304,6 @@ func (d *diff) AddSubnetTransformation(transformSubnetTxIntf *txs.Tx) { } } -func (d *diff) GetChains(subnetID ids.ID) ([]*txs.Tx, error) { - addedChains := d.addedChains[subnetID] - if len(addedChains) == 0 { - // No chains have been added to this subnet - parentState, ok := d.stateVersions.GetState(d.parentID) - if !ok { - return nil, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) - } - return parentState.GetChains(subnetID) - } - - // There have been chains added to the requested subnet - - if d.cachedChains == nil { - // This is the first time we are going to be caching the subnet chains - d.cachedChains = make(map[ids.ID][]*txs.Tx) - } - - cachedChains, cached := d.cachedChains[subnetID] - if cached { - return cachedChains, nil - } - - // This chain wasn't cached yet - parentState, ok := d.stateVersions.GetState(d.parentID) - if !ok { - return nil, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) - } - chains, err := parentState.GetChains(subnetID) - if err != nil { - return nil, err - } - - newChains := make([]*txs.Tx, len(chains)+len(addedChains)) - copy(newChains, chains) - for i, chain := range addedChains { - newChains[i+len(chains)] = chain - } - d.cachedChains[subnetID] = newChains - return newChains, nil -} - func (d *diff) AddChain(createChainTx *txs.Tx) { tx := createChainTx.Unsigned.(*txs.CreateChainTx) if d.addedChains == nil { @@ -390,12 +313,6 @@ func (d *diff) AddChain(createChainTx *txs.Tx) { } else { d.addedChains[tx.SubnetID] = append(d.addedChains[tx.SubnetID], createChainTx) } - - cachedChains, cached := d.cachedChains[tx.SubnetID] - if !cached { - return - } - d.cachedChains[tx.SubnetID] = append(cachedChains, createChainTx) } func (d *diff) GetTx(txID ids.ID) (*txs.Tx, status.Status, error) { @@ -425,18 +342,6 @@ func (d *diff) AddTx(tx *txs.Tx, status status.Status) { } } -func (d *diff) GetRewardUTXOs(txID ids.ID) ([]*avax.UTXO, error) { - if utxos, exists := d.addedRewardUTXOs[txID]; exists { - return utxos, nil - } - - parentState, ok := d.stateVersions.GetState(d.parentID) - if !ok { - return nil, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) - } - return parentState.GetRewardUTXOs(txID) -} - func (d *diff) AddRewardUTXO(txID ids.ID, utxo *avax.UTXO) { if d.addedRewardUTXOs == nil { d.addedRewardUTXOs = make(map[ids.ID][]*avax.UTXO) diff --git a/vms/platformvm/state/diff_test.go b/vms/platformvm/state/diff_test.go index 9b833f8482a8..50c87b2d3a53 100644 --- a/vms/platformvm/state/diff_test.go +++ b/vms/platformvm/state/diff_test.go @@ -250,15 +250,28 @@ func TestDiffSubnet(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) - state := NewMockState(ctrl) - // Called in NewDiff - state.EXPECT().GetTimestamp().Return(time.Now()).Times(1) + state, _ := newInitializedState(require) + + // Initialize parent with one subnet + parentStateCreateSubnetTx := &txs.Tx{ + Unsigned: &txs.CreateSubnetTx{ + Owner: fx.NewMockOwner(ctrl), + }, + } + state.AddSubnet(parentStateCreateSubnetTx) + + // Verify parent returns one subnet + subnets, err := state.GetSubnets() + require.NoError(err) + require.Equal([]*txs.Tx{ + parentStateCreateSubnetTx, + }, subnets) states := NewMockVersions(ctrl) lastAcceptedID := ids.GenerateTestID() states.EXPECT().GetState(lastAcceptedID).Return(state, true).AnyTimes() - d, err := NewDiff(lastAcceptedID, states) + diff, err := NewDiff(lastAcceptedID, states) require.NoError(err) // Put a subnet @@ -267,60 +280,67 @@ func TestDiffSubnet(t *testing.T) { Owner: fx.NewMockOwner(ctrl), }, } - d.AddSubnet(createSubnetTx) + diff.AddSubnet(createSubnetTx) - // Assert that we get the subnet back - // [state] returns 1 subnet. - parentStateCreateSubnetTx := &txs.Tx{ - Unsigned: &txs.CreateSubnetTx{ - Owner: fx.NewMockOwner(ctrl), - }, - } - state.EXPECT().GetSubnets().Return([]*txs.Tx{parentStateCreateSubnetTx}, nil).Times(1) - gotSubnets, err := d.GetSubnets() + // Apply diff to parent state + require.NoError(diff.Apply(state)) + + // Verify parent now returns two subnets + subnets, err = state.GetSubnets() require.NoError(err) - require.Len(gotSubnets, 2) - require.Equal(gotSubnets[0], parentStateCreateSubnetTx) - require.Equal(gotSubnets[1], createSubnetTx) + require.Equal([]*txs.Tx{ + parentStateCreateSubnetTx, + createSubnetTx, + }, subnets) } func TestDiffChain(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) - state := NewMockState(ctrl) - // Called in NewDiff - state.EXPECT().GetTimestamp().Return(time.Now()).Times(1) + state, _ := newInitializedState(require) + subnetID := ids.GenerateTestID() + + // Initialize parent with one chain + parentStateCreateChainTx := &txs.Tx{ + Unsigned: &txs.CreateChainTx{ + SubnetID: subnetID, + }, + } + state.AddChain(parentStateCreateChainTx) + + // Verify parent returns one chain + chains, err := state.GetChains(subnetID) + require.NoError(err) + require.Equal([]*txs.Tx{ + parentStateCreateChainTx, + }, chains) states := NewMockVersions(ctrl) lastAcceptedID := ids.GenerateTestID() states.EXPECT().GetState(lastAcceptedID).Return(state, true).AnyTimes() - d, err := NewDiff(lastAcceptedID, states) + diff, err := NewDiff(lastAcceptedID, states) require.NoError(err) // Put a chain - subnetID := ids.GenerateTestID() createChainTx := &txs.Tx{ Unsigned: &txs.CreateChainTx{ - SubnetID: subnetID, + SubnetID: subnetID, // note this is the same subnet as [parentStateCreateChainTx] }, } - d.AddChain(createChainTx) + diff.AddChain(createChainTx) - // Assert that we get the chain back - // [state] returns 1 chain. - parentStateCreateChainTx := &txs.Tx{ - Unsigned: &txs.CreateChainTx{ - SubnetID: subnetID, // note this is the same subnet as [createChainTx] - }, - } - state.EXPECT().GetChains(subnetID).Return([]*txs.Tx{parentStateCreateChainTx}, nil).Times(1) - gotChains, err := d.GetChains(subnetID) + // Apply diff to parent state + require.NoError(diff.Apply(state)) + + // Verify parent now returns two chains + chains, err = state.GetChains(subnetID) require.NoError(err) - require.Len(gotChains, 2) - require.Equal(parentStateCreateChainTx, gotChains[0]) - require.Equal(createChainTx, gotChains[1]) + require.Equal([]*txs.Tx{ + parentStateCreateChainTx, + createChainTx, + }, chains) } func TestDiffTx(t *testing.T) { @@ -377,45 +397,46 @@ func TestDiffRewardUTXO(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) - state := NewMockState(ctrl) - // Called in NewDiff - state.EXPECT().GetTimestamp().Return(time.Now()).Times(1) + state, _ := newInitializedState(require) + + txID := ids.GenerateTestID() + + // Initialize parent with one reward UTXO + parentRewardUTXO := &avax.UTXO{ + UTXOID: avax.UTXOID{TxID: txID}, + } + state.AddRewardUTXO(txID, parentRewardUTXO) + + // Verify parent returns the reward UTXO + rewardUTXOs, err := state.GetRewardUTXOs(txID) + require.NoError(err) + require.Equal([]*avax.UTXO{ + parentRewardUTXO, + }, rewardUTXOs) states := NewMockVersions(ctrl) lastAcceptedID := ids.GenerateTestID() states.EXPECT().GetState(lastAcceptedID).Return(state, true).AnyTimes() - d, err := NewDiff(lastAcceptedID, states) + diff, err := NewDiff(lastAcceptedID, states) require.NoError(err) // Put a reward UTXO - txID := ids.GenerateTestID() rewardUTXO := &avax.UTXO{ UTXOID: avax.UTXOID{TxID: txID}, } - d.AddRewardUTXO(txID, rewardUTXO) + diff.AddRewardUTXO(txID, rewardUTXO) - { - // Assert that we get the UTXO back - gotRewardUTXOs, err := d.GetRewardUTXOs(txID) - require.NoError(err) - require.Len(gotRewardUTXOs, 1) - require.Equal(rewardUTXO, gotRewardUTXOs[0]) - } + // Apply diff to parent state + require.NoError(diff.Apply(state)) - { - // Assert that we can get a UTXO from the parent state - // [state] returns 1 UTXO. - txID2 := ids.GenerateTestID() - parentRewardUTXO := &avax.UTXO{ - UTXOID: avax.UTXOID{TxID: txID2}, - } - state.EXPECT().GetRewardUTXOs(txID2).Return([]*avax.UTXO{parentRewardUTXO}, nil).Times(1) - gotParentRewardUTXOs, err := d.GetRewardUTXOs(txID2) - require.NoError(err) - require.Len(gotParentRewardUTXOs, 1) - require.Equal(parentRewardUTXO, gotParentRewardUTXOs[0]) - } + // Verify parent now returns two reward UTXOs + rewardUTXOs, err = state.GetRewardUTXOs(txID) + require.NoError(err) + require.Equal([]*avax.UTXO{ + parentRewardUTXO, + rewardUTXO, + }, rewardUTXOs) } func TestDiffUTXO(t *testing.T) { @@ -496,25 +517,6 @@ func assertChainsEqual(t *testing.T, expected, actual Chain) { require.NoError(err) require.Equal(expectedCurrentSupply, actualCurrentSupply) - - expectedSubnets, expectedErr := expected.GetSubnets() - actualSubnets, actualErr := actual.GetSubnets() - require.Equal(expectedErr, actualErr) - if expectedErr == nil { - require.Equal(expectedSubnets, actualSubnets) - - for _, subnet := range expectedSubnets { - subnetID := subnet.ID() - - expectedChains, expectedErr := expected.GetChains(subnetID) - actualChains, actualErr := actual.GetChains(subnetID) - require.Equal(expectedErr, actualErr) - if expectedErr != nil { - continue - } - require.Equal(expectedChains, actualChains) - } - } } func TestDiffSubnetOwner(t *testing.T) { diff --git a/vms/platformvm/state/mock_state.go b/vms/platformvm/state/mock_state.go index 465b3fda2bac..8a3aac7d81f1 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -180,21 +180,6 @@ func (mr *MockChainMockRecorder) DeleteUTXO(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUTXO", reflect.TypeOf((*MockChain)(nil).DeleteUTXO), arg0) } -// GetChains mocks base method. -func (m *MockChain) GetChains(arg0 ids.ID) ([]*txs.Tx, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetChains", arg0) - ret0, _ := ret[0].([]*txs.Tx) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetChains indicates an expected call of GetChains. -func (mr *MockChainMockRecorder) GetChains(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChains", reflect.TypeOf((*MockChain)(nil).GetChains), arg0) -} - // GetCurrentDelegatorIterator mocks base method. func (m *MockChain) GetCurrentDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -315,21 +300,6 @@ func (mr *MockChainMockRecorder) GetPendingValidator(arg0, arg1 interface{}) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPendingValidator", reflect.TypeOf((*MockChain)(nil).GetPendingValidator), arg0, arg1) } -// GetRewardUTXOs mocks base method. -func (m *MockChain) GetRewardUTXOs(arg0 ids.ID) ([]*avax.UTXO, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRewardUTXOs", arg0) - ret0, _ := ret[0].([]*avax.UTXO) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetRewardUTXOs indicates an expected call of GetRewardUTXOs. -func (mr *MockChainMockRecorder) GetRewardUTXOs(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRewardUTXOs", reflect.TypeOf((*MockChain)(nil).GetRewardUTXOs), arg0) -} - // GetSubnetOwner mocks base method. func (m *MockChain) GetSubnetOwner(arg0 ids.ID) (fx.Owner, error) { m.ctrl.T.Helper() @@ -360,21 +330,6 @@ func (mr *MockChainMockRecorder) GetSubnetTransformation(arg0 interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnetTransformation", reflect.TypeOf((*MockChain)(nil).GetSubnetTransformation), arg0) } -// GetSubnets mocks base method. -func (m *MockChain) GetSubnets() ([]*txs.Tx, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSubnets") - ret0, _ := ret[0].([]*txs.Tx) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetSubnets indicates an expected call of GetSubnets. -func (mr *MockChainMockRecorder) GetSubnets() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnets", reflect.TypeOf((*MockChain)(nil).GetSubnets)) -} - // GetTimestamp mocks base method. func (m *MockChain) GetTimestamp() time.Time { m.ctrl.T.Helper() @@ -687,21 +642,6 @@ func (mr *MockDiffMockRecorder) DeleteUTXO(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUTXO", reflect.TypeOf((*MockDiff)(nil).DeleteUTXO), arg0) } -// GetChains mocks base method. -func (m *MockDiff) GetChains(arg0 ids.ID) ([]*txs.Tx, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetChains", arg0) - ret0, _ := ret[0].([]*txs.Tx) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetChains indicates an expected call of GetChains. -func (mr *MockDiffMockRecorder) GetChains(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChains", reflect.TypeOf((*MockDiff)(nil).GetChains), arg0) -} - // GetCurrentDelegatorIterator mocks base method. func (m *MockDiff) GetCurrentDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -822,21 +762,6 @@ func (mr *MockDiffMockRecorder) GetPendingValidator(arg0, arg1 interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPendingValidator", reflect.TypeOf((*MockDiff)(nil).GetPendingValidator), arg0, arg1) } -// GetRewardUTXOs mocks base method. -func (m *MockDiff) GetRewardUTXOs(arg0 ids.ID) ([]*avax.UTXO, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRewardUTXOs", arg0) - ret0, _ := ret[0].([]*avax.UTXO) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetRewardUTXOs indicates an expected call of GetRewardUTXOs. -func (mr *MockDiffMockRecorder) GetRewardUTXOs(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRewardUTXOs", reflect.TypeOf((*MockDiff)(nil).GetRewardUTXOs), arg0) -} - // GetSubnetOwner mocks base method. func (m *MockDiff) GetSubnetOwner(arg0 ids.ID) (fx.Owner, error) { m.ctrl.T.Helper() @@ -867,21 +792,6 @@ func (mr *MockDiffMockRecorder) GetSubnetTransformation(arg0 interface{}) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnetTransformation", reflect.TypeOf((*MockDiff)(nil).GetSubnetTransformation), arg0) } -// GetSubnets mocks base method. -func (m *MockDiff) GetSubnets() ([]*txs.Tx, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSubnets") - ret0, _ := ret[0].([]*txs.Tx) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetSubnets indicates an expected call of GetSubnets. -func (mr *MockDiffMockRecorder) GetSubnets() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnets", reflect.TypeOf((*MockDiff)(nil).GetSubnets)) -} - // GetTimestamp mocks base method. func (m *MockDiff) GetTimestamp() time.Time { m.ctrl.T.Helper() diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 4b2b59cf2f70..4627fc706626 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -106,10 +106,8 @@ type Chain interface { GetCurrentSupply(subnetID ids.ID) (uint64, error) SetCurrentSupply(subnetID ids.ID, cs uint64) - GetRewardUTXOs(txID ids.ID) ([]*avax.UTXO, error) AddRewardUTXO(txID ids.ID, utxo *avax.UTXO) - GetSubnets() ([]*txs.Tx, error) AddSubnet(createSubnetTx *txs.Tx) GetSubnetOwner(subnetID ids.ID) (fx.Owner, error) @@ -118,7 +116,6 @@ type Chain interface { GetSubnetTransformation(subnetID ids.ID) (*txs.Tx, error) AddSubnetTransformation(transformSubnetTx *txs.Tx) - GetChains(subnetID ids.ID) ([]*txs.Tx, error) AddChain(createChainTx *txs.Tx) GetTx(txID ids.ID) (*txs.Tx, status.Status, error) @@ -140,6 +137,10 @@ type State interface { GetBlockIDAtHeight(height uint64) (ids.ID, error) + GetRewardUTXOs(txID ids.ID) ([]*avax.UTXO, error) + GetSubnets() ([]*txs.Tx, error) + GetChains(subnetID ids.ID) ([]*txs.Tx, error) + // ApplyValidatorWeightDiffs iterates from [startHeight] towards the genesis // block until it has applied all of the diffs up to and including // [endHeight]. Applying the diffs modifies [validators].