From 702639ae1ccb19ad3dbefd88e50dadfb2a2f36cf Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sat, 19 Oct 2024 13:38:28 -0400 Subject: [PATCH 01/14] ACP-77: Add ConversionID to state --- vms/platformvm/client.go | 4 +- vms/platformvm/config/execution_config.go | 4 +- .../config/execution_config_test.go | 2 +- vms/platformvm/service.go | 6 +- vms/platformvm/state/diff.go | 43 +++++----- vms/platformvm/state/diff_test.go | 68 ++++++++++----- vms/platformvm/state/mock_chain.go | 31 +++---- vms/platformvm/state/mock_diff.go | 31 +++---- vms/platformvm/state/mock_state.go | 45 +++++----- vms/platformvm/state/state.go | 86 ++++++++++--------- vms/platformvm/state/state_test.go | 60 +++++++------ .../txs/executor/create_chain_test.go | 7 +- .../txs/executor/staker_tx_verification.go | 2 +- .../txs/executor/standard_tx_executor.go | 3 +- .../txs/executor/standard_tx_executor_test.go | 21 +++-- .../txs/executor/subnet_tx_verification.go | 2 +- 16 files changed, 235 insertions(+), 180 deletions(-) diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index 54554f37d92b..522d359055d8 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -235,7 +235,8 @@ type GetSubnetClientResponse struct { Locktime uint64 // subnet transformation tx ID for a permissionless subnet SubnetTransformationTxID ids.ID - // subnet manager information for a permissionless L1 + // subnet conversion information for a permissionless L1 + ConversionID ids.ID ManagerChainID ids.ID ManagerAddress []byte } @@ -259,6 +260,7 @@ func (c *client) GetSubnet(ctx context.Context, subnetID ids.ID, options ...rpc. Threshold: uint32(res.Threshold), Locktime: uint64(res.Locktime), SubnetTransformationTxID: res.SubnetTransformationTxID, + ConversionID: res.ConversionID, ManagerChainID: res.ManagerChainID, ManagerAddress: res.ManagerAddress, }, nil diff --git a/vms/platformvm/config/execution_config.go b/vms/platformvm/config/execution_config.go index fafdaf9b99d2..e5bef1637d05 100644 --- a/vms/platformvm/config/execution_config.go +++ b/vms/platformvm/config/execution_config.go @@ -21,7 +21,7 @@ var DefaultExecutionConfig = ExecutionConfig{ ChainDBCacheSize: 2048, BlockIDCacheSize: 8192, FxOwnerCacheSize: 4 * units.MiB, - SubnetManagerCacheSize: 4 * units.MiB, + SubnetConversionCacheSize: 4 * units.MiB, ChecksumsEnabled: false, MempoolPruneFrequency: 30 * time.Minute, } @@ -37,7 +37,7 @@ type ExecutionConfig struct { ChainDBCacheSize int `json:"chain-db-cache-size"` BlockIDCacheSize int `json:"block-id-cache-size"` FxOwnerCacheSize int `json:"fx-owner-cache-size"` - SubnetManagerCacheSize int `json:"subnet-manager-cache-size"` + SubnetConversionCacheSize int `json:"subnet-conversion-cache-size"` ChecksumsEnabled bool `json:"checksums-enabled"` MempoolPruneFrequency time.Duration `json:"mempool-prune-frequency"` } diff --git a/vms/platformvm/config/execution_config_test.go b/vms/platformvm/config/execution_config_test.go index 5929a75f9063..c938c177add3 100644 --- a/vms/platformvm/config/execution_config_test.go +++ b/vms/platformvm/config/execution_config_test.go @@ -89,7 +89,7 @@ func TestExecutionConfigUnmarshal(t *testing.T) { ChainDBCacheSize: 7, BlockIDCacheSize: 8, FxOwnerCacheSize: 9, - SubnetManagerCacheSize: 10, + SubnetConversionCacheSize: 10, ChecksumsEnabled: true, MempoolPruneFrequency: time.Minute, } diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 91b7810d30df..b7111318c02a 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -439,7 +439,8 @@ type GetSubnetResponse struct { Locktime avajson.Uint64 `json:"locktime"` // subnet transformation tx ID for an elastic subnet SubnetTransformationTxID ids.ID `json:"subnetTransformationTxID"` - // subnet manager information for a permissionless L1 + // subnet conversion information for a permissionless L1 + ConversionID ids.ID `json:"conversionID"` ManagerChainID ids.ID `json:"managerChainID"` ManagerAddress types.JSONByteSlice `json:"managerAddress"` } @@ -490,9 +491,10 @@ func (s *Service) GetSubnet(_ *http.Request, args *GetSubnetArgs, response *GetS return err } - switch chainID, addr, err := s.vm.state.GetSubnetManager(args.SubnetID); err { + switch conversionID, chainID, addr, err := s.vm.state.GetSubnetConversion(args.SubnetID); err { case nil: response.IsPermissioned = false + response.ConversionID = conversionID response.ManagerChainID = chainID response.ManagerAddress = addr case database.ErrNotFound: diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index 24bdabfa96da..579b10bb28db 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -52,8 +52,8 @@ type diff struct { addedSubnetIDs []ids.ID // Subnet ID --> Owner of the subnet subnetOwners map[ids.ID]fx.Owner - // Subnet ID --> Manager of the subnet - subnetManagers map[ids.ID]chainIDAndAddr + // Subnet ID --> Conversion of the subnet + subnetConversions map[ids.ID]subnetConversion // Subnet ID --> Tx that transforms the subnet transformedSubnets map[ids.ID]*txs.Tx @@ -76,14 +76,14 @@ func NewDiff( return nil, fmt.Errorf("%w: %s", ErrMissingParentState, parentID) } return &diff{ - parentID: parentID, - stateVersions: stateVersions, - timestamp: parentState.GetTimestamp(), - feeState: parentState.GetFeeState(), - accruedFees: parentState.GetAccruedFees(), - expiryDiff: newExpiryDiff(), - subnetOwners: make(map[ids.ID]fx.Owner), - subnetManagers: make(map[ids.ID]chainIDAndAddr), + parentID: parentID, + stateVersions: stateVersions, + timestamp: parentState.GetTimestamp(), + feeState: parentState.GetFeeState(), + accruedFees: parentState.GetAccruedFees(), + expiryDiff: newExpiryDiff(), + subnetOwners: make(map[ids.ID]fx.Owner), + subnetConversions: make(map[ids.ID]subnetConversion), }, nil } @@ -357,23 +357,24 @@ func (d *diff) SetSubnetOwner(subnetID ids.ID, owner fx.Owner) { d.subnetOwners[subnetID] = owner } -func (d *diff) GetSubnetManager(subnetID ids.ID) (ids.ID, []byte, error) { - if manager, exists := d.subnetManagers[subnetID]; exists { - return manager.ChainID, manager.Addr, nil +func (d *diff) GetSubnetConversion(subnetID ids.ID) (ids.ID, ids.ID, []byte, error) { + if c, ok := d.subnetConversions[subnetID]; ok { + return c.ConversionID, c.ChainID, c.Addr, nil } // If the subnet manager was not assigned in this diff, ask the parent state. parentState, ok := d.stateVersions.GetState(d.parentID) if !ok { - return ids.Empty, nil, ErrMissingParentState + return ids.Empty, ids.Empty, nil, ErrMissingParentState } - return parentState.GetSubnetManager(subnetID) + return parentState.GetSubnetConversion(subnetID) } -func (d *diff) SetSubnetManager(subnetID ids.ID, chainID ids.ID, addr []byte) { - d.subnetManagers[subnetID] = chainIDAndAddr{ - ChainID: chainID, - Addr: addr, +func (d *diff) SetSubnetConversion(subnetID ids.ID, conversionID ids.ID, chainID ids.ID, addr []byte) { + d.subnetConversions[subnetID] = subnetConversion{ + ConversionID: conversionID, + ChainID: chainID, + Addr: addr, } } @@ -576,8 +577,8 @@ func (d *diff) Apply(baseState Chain) error { for subnetID, owner := range d.subnetOwners { baseState.SetSubnetOwner(subnetID, owner) } - for subnetID, manager := range d.subnetManagers { - baseState.SetSubnetManager(subnetID, manager.ChainID, manager.Addr) + for subnetID, c := range d.subnetConversions { + baseState.SetSubnetConversion(subnetID, c.ConversionID, c.ChainID, c.Addr) } return nil } diff --git a/vms/platformvm/state/diff_test.go b/vms/platformvm/state/diff_test.go index 3b091cd67a69..408ac9fe1cbf 100644 --- a/vms/platformvm/state/diff_test.go +++ b/vms/platformvm/state/diff_test.go @@ -774,44 +774,68 @@ func TestDiffSubnetOwner(t *testing.T) { func TestDiffSubnetManager(t *testing.T) { var ( - require = require.New(t) - state = newTestState(t, memdb.New()) - newManager = chainIDAndAddr{ids.GenerateTestID(), []byte{1, 2, 3, 4}} - subnetID = ids.GenerateTestID() + require = require.New(t) + state = newTestState(t, memdb.New()) + expectedConversion = subnetConversion{ + ConversionID: ids.GenerateTestID(), + ChainID: ids.GenerateTestID(), + Addr: []byte{1, 2, 3, 4}, + } + subnetID = ids.GenerateTestID() ) - chainID, addr, err := state.GetSubnetManager(subnetID) + conversionID, chainID, addr, err := state.GetSubnetConversion(subnetID) require.ErrorIs(err, database.ErrNotFound) - require.Equal(ids.Empty, chainID) - require.Nil(addr) + require.Zero(subnetConversion{ + ConversionID: conversionID, + ChainID: chainID, + Addr: addr, + }) d, err := NewDiffOn(state) require.NoError(err) - chainID, addr, err = d.GetSubnetManager(subnetID) + conversionID, chainID, addr, err = d.GetSubnetConversion(subnetID) require.ErrorIs(err, database.ErrNotFound) - require.Equal(ids.Empty, chainID) - require.Nil(addr) + require.Zero(subnetConversion{ + ConversionID: conversionID, + ChainID: chainID, + Addr: addr, + }) - // Setting a subnet manager should be reflected on diff not state - d.SetSubnetManager(subnetID, newManager.ChainID, newManager.Addr) - chainID, addr, err = d.GetSubnetManager(subnetID) + // Setting a subnet conversion should be reflected on diff not state + d.SetSubnetConversion(subnetID, expectedConversion.ConversionID, expectedConversion.ChainID, expectedConversion.Addr) + conversionID, chainID, addr, err = d.GetSubnetConversion(subnetID) require.NoError(err) - require.Equal(newManager.ChainID, chainID) - require.Equal(newManager.Addr, addr) + require.Equal( + expectedConversion, + subnetConversion{ + ConversionID: conversionID, + ChainID: chainID, + Addr: addr, + }, + ) - chainID, addr, err = state.GetSubnetManager(subnetID) + conversionID, chainID, addr, err = state.GetSubnetConversion(subnetID) require.ErrorIs(err, database.ErrNotFound) - require.Equal(ids.Empty, chainID) - require.Nil(addr) + require.Zero(subnetConversion{ + ConversionID: conversionID, + ChainID: chainID, + Addr: addr, + }) // State should reflect new subnet manager after diff is applied require.NoError(d.Apply(state)) - - chainID, addr, err = state.GetSubnetManager(subnetID) + conversionID, chainID, addr, err = state.GetSubnetConversion(subnetID) require.NoError(err) - require.Equal(newManager.ChainID, chainID) - require.Equal(newManager.Addr, addr) + require.Equal( + expectedConversion, + subnetConversion{ + ConversionID: conversionID, + ChainID: chainID, + Addr: addr, + }, + ) } func TestDiffStacking(t *testing.T) { diff --git a/vms/platformvm/state/mock_chain.go b/vms/platformvm/state/mock_chain.go index 3b380a87a8b8..f4f8dc661b90 100644 --- a/vms/platformvm/state/mock_chain.go +++ b/vms/platformvm/state/mock_chain.go @@ -353,20 +353,21 @@ func (mr *MockChainMockRecorder) GetPendingValidator(subnetID, nodeID any) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPendingValidator", reflect.TypeOf((*MockChain)(nil).GetPendingValidator), subnetID, nodeID) } -// GetSubnetManager mocks base method. -func (m *MockChain) GetSubnetManager(subnetID ids.ID) (ids.ID, []byte, error) { +// GetSubnetConversion mocks base method. +func (m *MockChain) GetSubnetConversion(subnetID ids.ID) (ids.ID, ids.ID, []byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSubnetManager", subnetID) + ret := m.ctrl.Call(m, "GetSubnetConversion", subnetID) ret0, _ := ret[0].(ids.ID) - ret1, _ := ret[1].([]byte) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 + ret1, _ := ret[1].(ids.ID) + ret2, _ := ret[2].([]byte) + ret3, _ := ret[3].(error) + return ret0, ret1, ret2, ret3 } -// GetSubnetManager indicates an expected call of GetSubnetManager. -func (mr *MockChainMockRecorder) GetSubnetManager(subnetID any) *gomock.Call { +// GetSubnetConversion indicates an expected call of GetSubnetConversion. +func (mr *MockChainMockRecorder) GetSubnetConversion(subnetID any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnetManager", reflect.TypeOf((*MockChain)(nil).GetSubnetManager), subnetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnetConversion", reflect.TypeOf((*MockChain)(nil).GetSubnetConversion), subnetID) } // GetSubnetOwner mocks base method. @@ -573,16 +574,16 @@ func (mr *MockChainMockRecorder) SetFeeState(f any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeState", reflect.TypeOf((*MockChain)(nil).SetFeeState), f) } -// SetSubnetManager mocks base method. -func (m *MockChain) SetSubnetManager(subnetID, chainID ids.ID, addr []byte) { +// SetSubnetConversion mocks base method. +func (m *MockChain) SetSubnetConversion(subnetID, conversionID, chainID ids.ID, addr []byte) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSubnetManager", subnetID, chainID, addr) + m.ctrl.Call(m, "SetSubnetConversion", subnetID, conversionID, chainID, addr) } -// SetSubnetManager indicates an expected call of SetSubnetManager. -func (mr *MockChainMockRecorder) SetSubnetManager(subnetID, chainID, addr any) *gomock.Call { +// SetSubnetConversion indicates an expected call of SetSubnetConversion. +func (mr *MockChainMockRecorder) SetSubnetConversion(subnetID, conversionID, chainID, addr any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSubnetManager", reflect.TypeOf((*MockChain)(nil).SetSubnetManager), subnetID, chainID, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSubnetConversion", reflect.TypeOf((*MockChain)(nil).SetSubnetConversion), subnetID, conversionID, chainID, addr) } // SetSubnetOwner mocks base method. diff --git a/vms/platformvm/state/mock_diff.go b/vms/platformvm/state/mock_diff.go index 77edfde92aaf..bbeed71080b1 100644 --- a/vms/platformvm/state/mock_diff.go +++ b/vms/platformvm/state/mock_diff.go @@ -367,20 +367,21 @@ func (mr *MockDiffMockRecorder) GetPendingValidator(subnetID, nodeID any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPendingValidator", reflect.TypeOf((*MockDiff)(nil).GetPendingValidator), subnetID, nodeID) } -// GetSubnetManager mocks base method. -func (m *MockDiff) GetSubnetManager(subnetID ids.ID) (ids.ID, []byte, error) { +// GetSubnetConversion mocks base method. +func (m *MockDiff) GetSubnetConversion(subnetID ids.ID) (ids.ID, ids.ID, []byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSubnetManager", subnetID) + ret := m.ctrl.Call(m, "GetSubnetConversion", subnetID) ret0, _ := ret[0].(ids.ID) - ret1, _ := ret[1].([]byte) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 + ret1, _ := ret[1].(ids.ID) + ret2, _ := ret[2].([]byte) + ret3, _ := ret[3].(error) + return ret0, ret1, ret2, ret3 } -// GetSubnetManager indicates an expected call of GetSubnetManager. -func (mr *MockDiffMockRecorder) GetSubnetManager(subnetID any) *gomock.Call { +// GetSubnetConversion indicates an expected call of GetSubnetConversion. +func (mr *MockDiffMockRecorder) GetSubnetConversion(subnetID any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnetManager", reflect.TypeOf((*MockDiff)(nil).GetSubnetManager), subnetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnetConversion", reflect.TypeOf((*MockDiff)(nil).GetSubnetConversion), subnetID) } // GetSubnetOwner mocks base method. @@ -587,16 +588,16 @@ func (mr *MockDiffMockRecorder) SetFeeState(f any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeState", reflect.TypeOf((*MockDiff)(nil).SetFeeState), f) } -// SetSubnetManager mocks base method. -func (m *MockDiff) SetSubnetManager(subnetID, chainID ids.ID, addr []byte) { +// SetSubnetConversion mocks base method. +func (m *MockDiff) SetSubnetConversion(subnetID, conversionID, chainID ids.ID, addr []byte) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSubnetManager", subnetID, chainID, addr) + m.ctrl.Call(m, "SetSubnetConversion", subnetID, conversionID, chainID, addr) } -// SetSubnetManager indicates an expected call of SetSubnetManager. -func (mr *MockDiffMockRecorder) SetSubnetManager(subnetID, chainID, addr any) *gomock.Call { +// SetSubnetConversion indicates an expected call of SetSubnetConversion. +func (mr *MockDiffMockRecorder) SetSubnetConversion(subnetID, conversionID, chainID, addr any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSubnetManager", reflect.TypeOf((*MockDiff)(nil).SetSubnetManager), subnetID, chainID, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSubnetConversion", reflect.TypeOf((*MockDiff)(nil).SetSubnetConversion), subnetID, conversionID, chainID, addr) } // SetSubnetOwner mocks base method. diff --git a/vms/platformvm/state/mock_state.go b/vms/platformvm/state/mock_state.go index f602345688b1..ed44205d9b49 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -557,6 +557,23 @@ func (mr *MockStateMockRecorder) GetStatelessBlock(blockID any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStatelessBlock", reflect.TypeOf((*MockState)(nil).GetStatelessBlock), blockID) } +// GetSubnetConversion mocks base method. +func (m *MockState) GetSubnetConversion(subnetID ids.ID) (ids.ID, ids.ID, []byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSubnetConversion", subnetID) + ret0, _ := ret[0].(ids.ID) + ret1, _ := ret[1].(ids.ID) + ret2, _ := ret[2].([]byte) + ret3, _ := ret[3].(error) + return ret0, ret1, ret2, ret3 +} + +// GetSubnetConversion indicates an expected call of GetSubnetConversion. +func (mr *MockStateMockRecorder) GetSubnetConversion(subnetID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnetConversion", reflect.TypeOf((*MockState)(nil).GetSubnetConversion), subnetID) +} + // GetSubnetIDs mocks base method. func (m *MockState) GetSubnetIDs() ([]ids.ID, error) { m.ctrl.T.Helper() @@ -572,22 +589,6 @@ func (mr *MockStateMockRecorder) GetSubnetIDs() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnetIDs", reflect.TypeOf((*MockState)(nil).GetSubnetIDs)) } -// GetSubnetManager mocks base method. -func (m *MockState) GetSubnetManager(subnetID ids.ID) (ids.ID, []byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSubnetManager", subnetID) - ret0, _ := ret[0].(ids.ID) - ret1, _ := ret[1].([]byte) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// GetSubnetManager indicates an expected call of GetSubnetManager. -func (mr *MockStateMockRecorder) GetSubnetManager(subnetID any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnetManager", reflect.TypeOf((*MockState)(nil).GetSubnetManager), subnetID) -} - // GetSubnetOwner mocks base method. func (m *MockState) GetSubnetOwner(subnetID ids.ID) (fx.Owner, error) { m.ctrl.T.Helper() @@ -846,16 +847,16 @@ func (mr *MockStateMockRecorder) SetLastAccepted(blkID any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastAccepted", reflect.TypeOf((*MockState)(nil).SetLastAccepted), blkID) } -// SetSubnetManager mocks base method. -func (m *MockState) SetSubnetManager(subnetID, chainID ids.ID, addr []byte) { +// SetSubnetConversion mocks base method. +func (m *MockState) SetSubnetConversion(subnetID, conversionID, chainID ids.ID, addr []byte) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSubnetManager", subnetID, chainID, addr) + m.ctrl.Call(m, "SetSubnetConversion", subnetID, conversionID, chainID, addr) } -// SetSubnetManager indicates an expected call of SetSubnetManager. -func (mr *MockStateMockRecorder) SetSubnetManager(subnetID, chainID, addr any) *gomock.Call { +// SetSubnetConversion indicates an expected call of SetSubnetConversion. +func (mr *MockStateMockRecorder) SetSubnetConversion(subnetID, conversionID, chainID, addr any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSubnetManager", reflect.TypeOf((*MockState)(nil).SetSubnetManager), subnetID, chainID, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSubnetConversion", reflect.TypeOf((*MockState)(nil).SetSubnetConversion), subnetID, conversionID, chainID, addr) } // SetSubnetOwner mocks base method. diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index f351bf5940b2..c839d4b7034b 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -78,7 +78,7 @@ var ( UTXOPrefix = []byte("utxo") SubnetPrefix = []byte("subnet") SubnetOwnerPrefix = []byte("subnetOwner") - SubnetManagerPrefix = []byte("subnetManager") + SubnetConversionPrefix = []byte("subnetConversion") TransformedSubnetPrefix = []byte("transformedSubnet") SupplyPrefix = []byte("supply") ChainPrefix = []byte("chain") @@ -123,8 +123,8 @@ type Chain interface { GetSubnetOwner(subnetID ids.ID) (fx.Owner, error) SetSubnetOwner(subnetID ids.ID, owner fx.Owner) - GetSubnetManager(subnetID ids.ID) (ids.ID, []byte, error) - SetSubnetManager(subnetID ids.ID, chainID ids.ID, addr []byte) + GetSubnetConversion(subnetID ids.ID) (conversionID ids.ID, chainID ids.ID, addr []byte, err error) + SetSubnetConversion(subnetID ids.ID, conversionID ids.ID, chainID ids.ID, addr []byte) GetSubnetTransformation(subnetID ids.ID) (*txs.Tx, error) AddSubnetTransformation(transformSubnetTx *txs.Tx) @@ -275,7 +275,9 @@ type stateBlk struct { * | '-. list * | '-- txID -> nil * |-. subnetOwners - * | '-. subnetID -> owner + * | '-- subnetID -> owner + * |-. subnetConversions + * | '-- subnetID -> conversionID + chainID + addr * |-. chains * | '-. subnetID * | '-. list @@ -364,9 +366,9 @@ type state struct { subnetOwnerCache cache.Cacher[ids.ID, fxOwnerAndSize] // cache of subnetID -> owner; if the entry is nil, it is not in the database subnetOwnerDB database.Database - subnetManagers map[ids.ID]chainIDAndAddr // map of subnetID -> manager of the subnet - subnetManagerCache cache.Cacher[ids.ID, chainIDAndAddr] // cache of subnetID -> manager - subnetManagerDB database.Database + subnetConversions map[ids.ID]subnetConversion // map of subnetID -> conversion of the subnet + subnetConversionCache cache.Cacher[ids.ID, subnetConversion] // cache of subnetID -> conversion + subnetConversionDB database.Database transformedSubnets map[ids.ID]*txs.Tx // map of subnetID -> transformSubnetTx transformedSubnetCache cache.Cacher[ids.ID, *txs.Tx] // cache of subnetID -> transformSubnetTx; if the entry is nil, it is not in the database @@ -439,9 +441,10 @@ type fxOwnerAndSize struct { size int } -type chainIDAndAddr struct { - ChainID ids.ID `serialize:"true"` - Addr []byte `serialize:"true"` +type subnetConversion struct { + ConversionID ids.ID `serialize:"true"` + ChainID ids.ID `serialize:"true"` + Addr []byte `serialize:"true"` } func txSize(_ ids.ID, tx *txs.Tx) int { @@ -552,12 +555,12 @@ func New( return nil, err } - subnetManagerDB := prefixdb.New(SubnetManagerPrefix, baseDB) - subnetManagerCache, err := metercacher.New[ids.ID, chainIDAndAddr]( + subnetConversionDB := prefixdb.New(SubnetConversionPrefix, baseDB) + subnetConversionCache, err := metercacher.New[ids.ID, subnetConversion]( "subnet_manager_cache", metricsReg, - cache.NewSizedLRU[ids.ID, chainIDAndAddr](execCfg.SubnetManagerCacheSize, func(_ ids.ID, f chainIDAndAddr) int { - return 2*ids.IDLen + len(f.Addr) + cache.NewSizedLRU[ids.ID, subnetConversion](execCfg.SubnetConversionCacheSize, func(_ ids.ID, c subnetConversion) int { + return 3*ids.IDLen + len(c.Addr) }), ) if err != nil { @@ -666,9 +669,9 @@ func New( subnetOwnerDB: subnetOwnerDB, subnetOwnerCache: subnetOwnerCache, - subnetManagers: make(map[ids.ID]chainIDAndAddr), - subnetManagerDB: subnetManagerDB, - subnetManagerCache: subnetManagerCache, + subnetConversions: make(map[ids.ID]subnetConversion), + subnetConversionDB: subnetConversionDB, + subnetConversionCache: subnetConversionCache, transformedSubnets: make(map[ids.ID]*txs.Tx), transformedSubnetCache: transformedSubnetCache, @@ -856,32 +859,33 @@ func (s *state) SetSubnetOwner(subnetID ids.ID, owner fx.Owner) { s.subnetOwners[subnetID] = owner } -func (s *state) GetSubnetManager(subnetID ids.ID) (ids.ID, []byte, error) { - if chainIDAndAddr, exists := s.subnetManagers[subnetID]; exists { - return chainIDAndAddr.ChainID, chainIDAndAddr.Addr, nil +func (s *state) GetSubnetConversion(subnetID ids.ID) (ids.ID, ids.ID, []byte, error) { + if c, ok := s.subnetConversions[subnetID]; ok { + return c.ConversionID, c.ChainID, c.Addr, nil } - if chainIDAndAddr, cached := s.subnetManagerCache.Get(subnetID); cached { - return chainIDAndAddr.ChainID, chainIDAndAddr.Addr, nil + if c, ok := s.subnetConversionCache.Get(subnetID); ok { + return c.ConversionID, c.ChainID, c.Addr, nil } - chainIDAndAddrBytes, err := s.subnetManagerDB.Get(subnetID[:]) + bytes, err := s.subnetConversionDB.Get(subnetID[:]) if err != nil { - return ids.Empty, nil, err + return ids.Empty, ids.Empty, nil, err } - var manager chainIDAndAddr - if _, err := block.GenesisCodec.Unmarshal(chainIDAndAddrBytes, &manager); err != nil { - return ids.Empty, nil, err + var c subnetConversion + if _, err := block.GenesisCodec.Unmarshal(bytes, &c); err != nil { + return ids.Empty, ids.Empty, nil, err } - s.subnetManagerCache.Put(subnetID, manager) - return manager.ChainID, manager.Addr, nil + s.subnetConversionCache.Put(subnetID, c) + return c.ConversionID, c.ChainID, c.Addr, nil } -func (s *state) SetSubnetManager(subnetID ids.ID, chainID ids.ID, addr []byte) { - s.subnetManagers[subnetID] = chainIDAndAddr{ - ChainID: chainID, - Addr: addr, +func (s *state) SetSubnetConversion(subnetID ids.ID, conversionID ids.ID, chainID ids.ID, addr []byte) { + s.subnetConversions[subnetID] = subnetConversion{ + ConversionID: conversionID, + ChainID: chainID, + Addr: addr, } } @@ -1765,7 +1769,7 @@ func (s *state) write(updateValidators bool, height uint64) error { s.writeUTXOs(), s.writeSubnets(), s.writeSubnetOwners(), - s.writeSubnetManagers(), + s.writeSubnetConversions(), s.writeTransformedSubnets(), s.writeSubnetSupplies(), s.writeChains(), @@ -2364,20 +2368,20 @@ func (s *state) writeSubnetOwners() error { return nil } -func (s *state) writeSubnetManagers() error { - for subnetID, manager := range s.subnetManagers { +func (s *state) writeSubnetConversions() error { + for subnetID, c := range s.subnetConversions { subnetID := subnetID - manager := manager - delete(s.subnetManagers, subnetID) + c := c + delete(s.subnetConversions, subnetID) - managerBytes, err := block.GenesisCodec.Marshal(block.CodecVersion, &manager) + bytes, err := block.GenesisCodec.Marshal(block.CodecVersion, &c) if err != nil { return fmt.Errorf("failed to marshal subnet manager: %w", err) } - s.subnetManagerCache.Put(subnetID, manager) + s.subnetConversionCache.Put(subnetID, c) - if err := s.subnetManagerDB.Put(subnetID[:], managerBytes); err != nil { + if err := s.subnetConversionDB.Put(subnetID[:], bytes); err != nil { return fmt.Errorf("failed to write subnet manager: %w", err) } } diff --git a/vms/platformvm/state/state_test.go b/vms/platformvm/state/state_test.go index 0f23a3ebc833..ea13a2dd30ac 100644 --- a/vms/platformvm/state/state_test.go +++ b/vms/platformvm/state/state_test.go @@ -1323,52 +1323,58 @@ func TestStateSubnetOwner(t *testing.T) { require.Equal(owner2, owner) } -func TestStateSubnetManager(t *testing.T) { +func TestStateSubnetConversion(t *testing.T) { tests := []struct { name string - setup func(t *testing.T, s State, subnetID ids.ID, chainID ids.ID, addr []byte) + setup func(s *state, subnetID ids.ID, c subnetConversion) }{ { name: "in-memory", - setup: func(_ *testing.T, s State, subnetID ids.ID, chainID ids.ID, addr []byte) { - s.SetSubnetManager(subnetID, chainID, addr) + setup: func(s *state, subnetID ids.ID, c subnetConversion) { + s.SetSubnetConversion(subnetID, c.ConversionID, c.ChainID, c.Addr) }, }, { name: "cache", - setup: func(t *testing.T, s State, subnetID ids.ID, chainID ids.ID, addr []byte) { - subnetManagerCache := s.(*state).subnetManagerCache - - require.Zero(t, subnetManagerCache.Len()) - subnetManagerCache.Put(subnetID, chainIDAndAddr{ - ChainID: chainID, - Addr: addr, - }) - require.Equal(t, 1, subnetManagerCache.Len()) + setup: func(s *state, subnetID ids.ID, c subnetConversion) { + s.subnetConversionCache.Flush() + s.subnetConversionCache.Put(subnetID, c) }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - require := require.New(t) - - initializedState := newTestState(t, memdb.New()) + var ( + require = require.New(t) + initializedState = newTestState(t, memdb.New()) + subnetID = ids.GenerateTestID() + expectedConversion = subnetConversion{ + ConversionID: ids.GenerateTestID(), + ChainID: ids.GenerateTestID(), + Addr: []byte{'a', 'd', 'd', 'r'}, + } + ) - subnetID := ids.GenerateTestID() - chainID, addr, err := initializedState.GetSubnetManager(subnetID) + conversionID, chainID, addr, err := initializedState.GetSubnetConversion(subnetID) require.ErrorIs(err, database.ErrNotFound) - require.Equal(ids.Empty, chainID) - require.Nil(addr) - - expectedChainID := ids.GenerateTestID() - expectedAddr := []byte{'a', 'd', 'd', 'r'} + require.Zero(subnetConversion{ + ConversionID: conversionID, + ChainID: chainID, + Addr: addr, + }) - test.setup(t, initializedState, subnetID, expectedChainID, expectedAddr) + test.setup(initializedState, subnetID, expectedConversion) - chainID, addr, err = initializedState.GetSubnetManager(subnetID) + conversionID, chainID, addr, err = initializedState.GetSubnetConversion(subnetID) require.NoError(err) - require.Equal(expectedChainID, chainID) - require.Equal(expectedAddr, addr) + require.Equal( + expectedConversion, + subnetConversion{ + ConversionID: conversionID, + ChainID: chainID, + Addr: addr, + }, + ) }) } } diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 61fead2677a7..cf3e0e8d2cf2 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -286,7 +286,12 @@ func TestEtnaCreateChainTxInvalidWithManagedSubnet(t *testing.T) { builderDiff, err := state.NewDiffOn(stateDiff) require.NoError(err) - stateDiff.SetSubnetManager(subnetID, ids.GenerateTestID(), []byte{'a', 'd', 'd', 'r', 'e', 's', 's'}) + stateDiff.SetSubnetConversion( + subnetID, + ids.GenerateTestID(), + ids.GenerateTestID(), + []byte{'a', 'd', 'd', 'r', 'e', 's', 's'}, + ) feeCalculator := state.PickFeeCalculator(env.config, builderDiff) executor := StandardTxExecutor{ diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index d458c01ab259..69b8cd567586 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -308,7 +308,7 @@ func verifyRemoveSubnetValidatorTx( } if backend.Config.UpgradeConfig.IsEtnaActivated(currentTimestamp) { - _, _, err := chainState.GetSubnetManager(tx.Subnet) + _, _, _, err := chainState.GetSubnetConversion(tx.Subnet) if err == nil { return nil, false, fmt.Errorf("%w: %q", ErrRemoveValidatorManagedSubnet, tx.Subnet) } diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index d0a37f5ba82c..14069b1e4e43 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -542,7 +542,8 @@ func (e *StandardTxExecutor) ConvertSubnetTx(tx *txs.ConvertSubnetTx) error { // Produce the UTXOS avax.Produce(e.State, txID, tx.Outs) // Set the new Subnet manager in the database - e.State.SetSubnetManager(tx.Subnet, tx.ChainID, tx.Address) + // TODO: Populate the conversionID + e.State.SetSubnetConversion(tx.Subnet, ids.Empty, tx.ChainID, tx.Address) return nil } diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index e11ad73ac5d9..837af0ba73a5 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -913,7 +913,12 @@ func TestEtnaStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - onAcceptState.SetSubnetManager(subnetID, ids.GenerateTestID(), []byte{'a', 'd', 'd', 'r', 'e', 's', 's'}) + onAcceptState.SetSubnetConversion( + subnetID, + ids.GenerateTestID(), + ids.GenerateTestID(), + []byte{'a', 'd', 'd', 'r', 'e', 's', 's'}, + ) executor := StandardTxExecutor{ Backend: &env.backend, @@ -1994,7 +1999,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { name: "attempted to remove subnet validator after subnet manager is set", newExecutor: func(ctrl *gomock.Controller) (*txs.RemoveSubnetValidatorTx, *StandardTxExecutor) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) - env.state.EXPECT().GetSubnetManager(env.unsignedTx.Subnet).Return(ids.GenerateTestID(), []byte{'a', 'd', 'd', 'r', 'e', 's', 's'}, nil).AnyTimes() + env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return(ids.GenerateTestID(), ids.GenerateTestID(), []byte{'a', 'd', 'd', 'r', 'e', 's', 's'}, nil).AnyTimes() env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() cfg := &config.Config{ @@ -2245,7 +2250,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { subnetOwner := fxmock.NewOwner(ctrl) env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil) - env.state.EXPECT().GetSubnetManager(env.unsignedTx.Subnet).Return(ids.Empty, nil, database.ErrNotFound).Times(1) + env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return(ids.Empty, ids.Empty, nil, database.ErrNotFound).Times(1) env.state.EXPECT().GetSubnetTransformation(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound).Times(1) env.fx.EXPECT().VerifyPermission(gomock.Any(), env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(nil) env.flowChecker.EXPECT().VerifySpend( @@ -2284,7 +2289,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { subnetOwner := fxmock.NewOwner(ctrl) env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil).Times(1) - env.state.EXPECT().GetSubnetManager(env.unsignedTx.Subnet).Return(ids.GenerateTestID(), make([]byte, 20), nil) + env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return(ids.GenerateTestID(), ids.GenerateTestID(), make([]byte, 20), nil) env.state.EXPECT().GetSubnetTransformation(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound).Times(1) env.fx.EXPECT().VerifyPermission(env.unsignedTx, env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(nil).Times(1) @@ -2319,7 +2324,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { subnetOwner := fxmock.NewOwner(ctrl) env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil).Times(1) - env.state.EXPECT().GetSubnetManager(env.unsignedTx.Subnet).Return(ids.Empty, nil, database.ErrNotFound).Times(1) + env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return(ids.Empty, ids.Empty, nil, database.ErrNotFound).Times(1) env.state.EXPECT().GetSubnetTransformation(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound).Times(1) env.fx.EXPECT().VerifyPermission(env.unsignedTx, env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(nil).Times(1) env.flowChecker.EXPECT().VerifySpend( @@ -2478,7 +2483,7 @@ func TestStandardExecutorConvertSubnetTx(t *testing.T) { { name: "invalid if subnet is converted", updateExecutor: func(e *StandardTxExecutor) { - e.State.SetSubnetManager(subnetID, ids.GenerateTestID(), nil) + e.State.SetSubnetConversion(subnetID, ids.GenerateTestID(), ids.GenerateTestID(), nil) }, expectedErr: errIsImmutable, }, @@ -2566,8 +2571,10 @@ func TestStandardExecutorConvertSubnetTx(t *testing.T) { require.Equal(expectedUTXO, utxo) } - stateChainID, stateAddress, err := diff.GetSubnetManager(subnetID) + stateConversionID, stateChainID, stateAddress, err := diff.GetSubnetConversion(subnetID) require.NoError(err) + // TODO: Update this test when we populate the correct conversionID + require.Zero(stateConversionID) require.Equal(chainID, stateChainID) require.Equal(address, stateAddress) }) diff --git a/vms/platformvm/txs/executor/subnet_tx_verification.go b/vms/platformvm/txs/executor/subnet_tx_verification.go index 6e5ecb9a34f5..7466fd78227e 100644 --- a/vms/platformvm/txs/executor/subnet_tx_verification.go +++ b/vms/platformvm/txs/executor/subnet_tx_verification.go @@ -43,7 +43,7 @@ func verifyPoASubnetAuthorization( return nil, err } - _, _, err = chainState.GetSubnetManager(subnetID) + _, _, _, err = chainState.GetSubnetConversion(subnetID) if err == nil { return nil, fmt.Errorf("%q %w", subnetID, errIsImmutable) } From 4b562f05e10ecd9c881f01db8799bb82ec92e1c0 Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sat, 19 Oct 2024 13:45:02 -0400 Subject: [PATCH 02/14] nit --- vms/platformvm/state/diff_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vms/platformvm/state/diff_test.go b/vms/platformvm/state/diff_test.go index 408ac9fe1cbf..3bb156c5096b 100644 --- a/vms/platformvm/state/diff_test.go +++ b/vms/platformvm/state/diff_test.go @@ -772,7 +772,7 @@ func TestDiffSubnetOwner(t *testing.T) { require.Equal(owner2, owner) } -func TestDiffSubnetManager(t *testing.T) { +func TestDiffSubnetConversion(t *testing.T) { var ( require = require.New(t) state = newTestState(t, memdb.New()) From 7f3dd5e39afe01672de659518671e36f1c2039bf Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sat, 19 Oct 2024 13:49:13 -0400 Subject: [PATCH 03/14] nit --- vms/platformvm/state/diff.go | 2 +- vms/platformvm/state/diff_test.go | 2 +- vms/platformvm/state/state.go | 4 ++-- vms/platformvm/txs/executor/standard_tx_executor.go | 2 +- vms/platformvm/txs/executor/standard_tx_executor_test.go | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index 579b10bb28db..e2cfd648296d 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -362,7 +362,7 @@ func (d *diff) GetSubnetConversion(subnetID ids.ID) (ids.ID, ids.ID, []byte, err return c.ConversionID, c.ChainID, c.Addr, nil } - // If the subnet manager was not assigned in this diff, ask the parent state. + // If the subnet conversion was not assigned in this diff, ask the parent state. parentState, ok := d.stateVersions.GetState(d.parentID) if !ok { return ids.Empty, ids.Empty, nil, ErrMissingParentState diff --git a/vms/platformvm/state/diff_test.go b/vms/platformvm/state/diff_test.go index 3bb156c5096b..c62333a383a9 100644 --- a/vms/platformvm/state/diff_test.go +++ b/vms/platformvm/state/diff_test.go @@ -824,7 +824,7 @@ func TestDiffSubnetConversion(t *testing.T) { Addr: addr, }) - // State should reflect new subnet manager after diff is applied + // State should reflect new subnet conversion after diff is applied require.NoError(d.Apply(state)) conversionID, chainID, addr, err = state.GetSubnetConversion(subnetID) require.NoError(err) diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index c839d4b7034b..d626639bf0f7 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -2376,13 +2376,13 @@ func (s *state) writeSubnetConversions() error { bytes, err := block.GenesisCodec.Marshal(block.CodecVersion, &c) if err != nil { - return fmt.Errorf("failed to marshal subnet manager: %w", err) + return fmt.Errorf("failed to marshal subnet conversion: %w", err) } s.subnetConversionCache.Put(subnetID, c) if err := s.subnetConversionDB.Put(subnetID[:], bytes); err != nil { - return fmt.Errorf("failed to write subnet manager: %w", err) + return fmt.Errorf("failed to write subnet conversion: %w", err) } } return nil diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index 14069b1e4e43..9cc9eddf723b 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -541,7 +541,7 @@ func (e *StandardTxExecutor) ConvertSubnetTx(tx *txs.ConvertSubnetTx) error { avax.Consume(e.State, tx.Ins) // Produce the UTXOS avax.Produce(e.State, txID, tx.Outs) - // Set the new Subnet manager in the database + // Track the subnet conversion in the database // TODO: Populate the conversionID e.State.SetSubnetConversion(tx.Subnet, ids.Empty, tx.ChainID, tx.Address) return nil diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 837af0ba73a5..64686a1c744e 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -1996,7 +1996,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { expectedErr: ErrFlowCheckFailed, }, { - name: "attempted to remove subnet validator after subnet manager is set", + name: "attempted to remove subnet validator after subnet conversion has occurred", newExecutor: func(ctrl *gomock.Controller) (*txs.RemoveSubnetValidatorTx, *StandardTxExecutor) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return(ids.GenerateTestID(), ids.GenerateTestID(), []byte{'a', 'd', 'd', 'r', 'e', 's', 's'}, nil).AnyTimes() @@ -2281,7 +2281,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { err: ErrFlowCheckFailed, }, { - name: "invalid if subnet manager is set", + name: "invalid after subnet conversion", newExecutor: func(ctrl *gomock.Controller) (*txs.TransformSubnetTx, *StandardTxExecutor) { env := newValidTransformSubnetTxVerifyEnv(t, ctrl) From f40c1b3ff8bc3877ec4e5edde410ec62b6fc27b0 Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sat, 19 Oct 2024 14:15:41 -0400 Subject: [PATCH 04/14] nit --- vms/platformvm/state/diff_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vms/platformvm/state/diff_test.go b/vms/platformvm/state/diff_test.go index c62333a383a9..7441786ac1bf 100644 --- a/vms/platformvm/state/diff_test.go +++ b/vms/platformvm/state/diff_test.go @@ -776,12 +776,12 @@ func TestDiffSubnetConversion(t *testing.T) { var ( require = require.New(t) state = newTestState(t, memdb.New()) + subnetID = ids.GenerateTestID() expectedConversion = subnetConversion{ ConversionID: ids.GenerateTestID(), ChainID: ids.GenerateTestID(), Addr: []byte{1, 2, 3, 4}, } - subnetID = ids.GenerateTestID() ) conversionID, chainID, addr, err := state.GetSubnetConversion(subnetID) From 51f009b9e972be459794aadba2fd67a0ad3417f8 Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sat, 19 Oct 2024 14:23:53 -0400 Subject: [PATCH 05/14] nit --- vms/platformvm/state/state.go | 2 +- vms/platformvm/state/state_test.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index d626639bf0f7..04ed6b619b4d 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -557,7 +557,7 @@ func New( subnetConversionDB := prefixdb.New(SubnetConversionPrefix, baseDB) subnetConversionCache, err := metercacher.New[ids.ID, subnetConversion]( - "subnet_manager_cache", + "subnet_conversion_cache", metricsReg, cache.NewSizedLRU[ids.ID, subnetConversion](execCfg.SubnetConversionCacheSize, func(_ ids.ID, c subnetConversion) int { return 3*ids.IDLen + len(c.Addr) diff --git a/vms/platformvm/state/state_test.go b/vms/platformvm/state/state_test.go index ea13a2dd30ac..f2e0483a25c6 100644 --- a/vms/platformvm/state/state_test.go +++ b/vms/platformvm/state/state_test.go @@ -1346,7 +1346,7 @@ func TestStateSubnetConversion(t *testing.T) { t.Run(test.name, func(t *testing.T) { var ( require = require.New(t) - initializedState = newTestState(t, memdb.New()) + state = newTestState(t, memdb.New()) subnetID = ids.GenerateTestID() expectedConversion = subnetConversion{ ConversionID: ids.GenerateTestID(), @@ -1355,7 +1355,7 @@ func TestStateSubnetConversion(t *testing.T) { } ) - conversionID, chainID, addr, err := initializedState.GetSubnetConversion(subnetID) + conversionID, chainID, addr, err := state.GetSubnetConversion(subnetID) require.ErrorIs(err, database.ErrNotFound) require.Zero(subnetConversion{ ConversionID: conversionID, @@ -1363,9 +1363,9 @@ func TestStateSubnetConversion(t *testing.T) { Addr: addr, }) - test.setup(initializedState, subnetID, expectedConversion) + test.setup(state, subnetID, expectedConversion) - conversionID, chainID, addr, err = initializedState.GetSubnetConversion(subnetID) + conversionID, chainID, addr, err = state.GetSubnetConversion(subnetID) require.NoError(err) require.Equal( expectedConversion, From 05a7b136901e4dfed52d1eed9e6cf53be00ad391 Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sat, 19 Oct 2024 14:26:51 -0400 Subject: [PATCH 06/14] nit --- vms/platformvm/service.go | 1 + 1 file changed, 1 insertion(+) diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index b7111318c02a..7c3bbc4596be 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -498,6 +498,7 @@ func (s *Service) GetSubnet(_ *http.Request, args *GetSubnetArgs, response *GetS response.ManagerChainID = chainID response.ManagerAddress = addr case database.ErrNotFound: + response.ConversionID = ids.Empty response.ManagerChainID = ids.Empty response.ManagerAddress = []byte(nil) default: From a1db89e32a8265019b13bc5207e6d9b1a859b4f7 Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sat, 19 Oct 2024 14:31:26 -0400 Subject: [PATCH 07/14] nit --- vms/platformvm/state/state.go | 1 + 1 file changed, 1 insertion(+) diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 04ed6b619b4d..0c92fde71ec5 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -1795,6 +1795,7 @@ func (s *state) Close() error { s.rewardUTXODB.Close(), s.utxoDB.Close(), s.subnetBaseDB.Close(), + s.subnetConversionDB.Close(), s.transformedSubnetDB.Close(), s.supplyDB.Close(), s.chainDB.Close(), From 575b36ac37b279b5cdef3fdf0d31e4f8c3cc23fb Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sat, 19 Oct 2024 16:19:38 -0400 Subject: [PATCH 08/14] remove unneeded assignment --- vms/platformvm/state/state.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 0c92fde71ec5..a059323f6874 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -2371,8 +2371,6 @@ func (s *state) writeSubnetOwners() error { func (s *state) writeSubnetConversions() error { for subnetID, c := range s.subnetConversions { - subnetID := subnetID - c := c delete(s.subnetConversions, subnetID) bytes, err := block.GenesisCodec.Marshal(block.CodecVersion, &c) From d2d0f69976f54fd3827c840260fb3d9ec667345d Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sat, 19 Oct 2024 16:26:46 -0400 Subject: [PATCH 09/14] update comment --- vms/platformvm/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index 522d359055d8..505c545bdded 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -235,7 +235,7 @@ type GetSubnetClientResponse struct { Locktime uint64 // subnet transformation tx ID for a permissionless subnet SubnetTransformationTxID ids.ID - // subnet conversion information for a permissionless L1 + // subnet conversion information for an L1 ConversionID ids.ID ManagerChainID ids.ID ManagerAddress []byte From b6b6515ffa8458fc5df186f990bbeca3a64b5caa Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sat, 19 Oct 2024 16:51:41 -0400 Subject: [PATCH 10/14] update comment --- vms/platformvm/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 7c3bbc4596be..72be28e40f4d 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -439,7 +439,7 @@ type GetSubnetResponse struct { Locktime avajson.Uint64 `json:"locktime"` // subnet transformation tx ID for an elastic subnet SubnetTransformationTxID ids.ID `json:"subnetTransformationTxID"` - // subnet conversion information for a permissionless L1 + // subnet conversion information for an L1 ConversionID ids.ID `json:"conversionID"` ManagerChainID ids.ID `json:"managerChainID"` ManagerAddress types.JSONByteSlice `json:"managerAddress"` From 6ffcd1b30910226ef2dc8bf9c133598eb4bc49d6 Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sat, 19 Oct 2024 17:27:33 -0400 Subject: [PATCH 11/14] update doc --- vms/platformvm/service.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/vms/platformvm/service.md b/vms/platformvm/service.md index f4cd28cd35f1..81c929b0ecda 100644 --- a/vms/platformvm/service.md +++ b/vms/platformvm/service.md @@ -1204,7 +1204,7 @@ Testnet: U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK ### `platform.getSubnet` -Get owners and elastic info about the Subnet. +Get owners and elastic info about the Subnet or L1. **Signature:** @@ -1217,7 +1217,10 @@ platform.getSubnet({ controlKeys: []string, threshold: string, locktime: string, - subnetTransformationTxID: string + subnetTransformationTxID: string, + conversionID: string, + managerChainID: string, + managerAddress: string } ``` @@ -1226,8 +1229,10 @@ platform.getSubnet({ a permissioned subnet. If the Subnet is a PoS Subnet, then `threshold` will be `0` and `controlKeys` will be empty. - changes can not be made into the subnet until `locktime` is in the past. -- `subnetTransformationTxID` is the ID of the transaction that changed the subnet into a elastic one, - for when this change was performed. +- `subnetTransformationTxID` is the ID of the transaction that changed the subnet into an elastic one, if it exists. +- `conversionID` is the ID of the conversion from a permissioned Subnet into an L1, if it exists. +- `managerChainID` is the ChainID that has the ability to modify this L1s validator set, if it exists. +- `managerAddress` is the address that has the ability to modify this L1s validator set, if it exists. **Example Call:** @@ -1250,7 +1255,10 @@ curl -X POST --data '{ "controlKeys": ["P-fuji1ztvstx6naeg6aarfd047fzppdt8v4gsah88e0c","P-fuji193kvt4grqewv6ce2x59wnhydr88xwdgfcedyr3"], "threshold": "1", "locktime": "0", - "subnetTransformationTxID": "11111111111111111111111111111111LpoYY" + "subnetTransformationTxID": "11111111111111111111111111111111LpoYY", + "conversionID": "11111111111111111111111111111111LpoYY", + "managerChainID": "11111111111111111111111111111111LpoYY", + "managerAddress": null }, "id": 1 } From ad001806ca9f191294126842e766b8043450b5bb Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sun, 20 Oct 2024 13:15:23 -0400 Subject: [PATCH 12/14] Address comments --- vms/platformvm/service.go | 8 +-- vms/platformvm/service.md | 2 +- vms/platformvm/state/diff.go | 20 +++----- vms/platformvm/state/diff_test.go | 50 +++++-------------- vms/platformvm/state/mock_chain.go | 18 +++---- vms/platformvm/state/mock_diff.go | 18 +++---- vms/platformvm/state/mock_state.go | 18 +++---- vms/platformvm/state/state.go | 38 +++++++------- vms/platformvm/state/state_test.go | 30 ++++------- .../txs/executor/staker_tx_verification.go | 2 +- .../txs/executor/standard_tx_executor.go | 11 +++- .../txs/executor/subnet_tx_verification.go | 2 +- 12 files changed, 86 insertions(+), 131 deletions(-) diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 72be28e40f4d..22153a97ece6 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -491,12 +491,12 @@ func (s *Service) GetSubnet(_ *http.Request, args *GetSubnetArgs, response *GetS return err } - switch conversionID, chainID, addr, err := s.vm.state.GetSubnetConversion(args.SubnetID); err { + switch c, err := s.vm.state.GetSubnetConversion(args.SubnetID); err { case nil: response.IsPermissioned = false - response.ConversionID = conversionID - response.ManagerChainID = chainID - response.ManagerAddress = addr + response.ConversionID = c.ConversionID + response.ManagerChainID = c.ChainID + response.ManagerAddress = c.Addr case database.ErrNotFound: response.ConversionID = ids.Empty response.ManagerChainID = ids.Empty diff --git a/vms/platformvm/service.md b/vms/platformvm/service.md index 81c929b0ecda..dbb12907694b 100644 --- a/vms/platformvm/service.md +++ b/vms/platformvm/service.md @@ -1204,7 +1204,7 @@ Testnet: U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK ### `platform.getSubnet` -Get owners and elastic info about the Subnet or L1. +Get owners and info about the Subnet or L1. **Signature:** diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index e2cfd648296d..9fe6a62363c0 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -53,7 +53,7 @@ type diff struct { // Subnet ID --> Owner of the subnet subnetOwners map[ids.ID]fx.Owner // Subnet ID --> Conversion of the subnet - subnetConversions map[ids.ID]subnetConversion + subnetConversions map[ids.ID]SubnetConversion // Subnet ID --> Tx that transforms the subnet transformedSubnets map[ids.ID]*txs.Tx @@ -83,7 +83,7 @@ func NewDiff( accruedFees: parentState.GetAccruedFees(), expiryDiff: newExpiryDiff(), subnetOwners: make(map[ids.ID]fx.Owner), - subnetConversions: make(map[ids.ID]subnetConversion), + subnetConversions: make(map[ids.ID]SubnetConversion), }, nil } @@ -357,25 +357,21 @@ func (d *diff) SetSubnetOwner(subnetID ids.ID, owner fx.Owner) { d.subnetOwners[subnetID] = owner } -func (d *diff) GetSubnetConversion(subnetID ids.ID) (ids.ID, ids.ID, []byte, error) { +func (d *diff) GetSubnetConversion(subnetID ids.ID) (SubnetConversion, error) { if c, ok := d.subnetConversions[subnetID]; ok { - return c.ConversionID, c.ChainID, c.Addr, nil + return c, nil } // If the subnet conversion was not assigned in this diff, ask the parent state. parentState, ok := d.stateVersions.GetState(d.parentID) if !ok { - return ids.Empty, ids.Empty, nil, ErrMissingParentState + return SubnetConversion{}, ErrMissingParentState } return parentState.GetSubnetConversion(subnetID) } -func (d *diff) SetSubnetConversion(subnetID ids.ID, conversionID ids.ID, chainID ids.ID, addr []byte) { - d.subnetConversions[subnetID] = subnetConversion{ - ConversionID: conversionID, - ChainID: chainID, - Addr: addr, - } +func (d *diff) SetSubnetConversion(subnetID ids.ID, c SubnetConversion) { + d.subnetConversions[subnetID] = c } func (d *diff) GetSubnetTransformation(subnetID ids.ID) (*txs.Tx, error) { @@ -578,7 +574,7 @@ func (d *diff) Apply(baseState Chain) error { baseState.SetSubnetOwner(subnetID, owner) } for subnetID, c := range d.subnetConversions { - baseState.SetSubnetConversion(subnetID, c.ConversionID, c.ChainID, c.Addr) + baseState.SetSubnetConversion(subnetID, c) } return nil } diff --git a/vms/platformvm/state/diff_test.go b/vms/platformvm/state/diff_test.go index 7441786ac1bf..013a918b60fa 100644 --- a/vms/platformvm/state/diff_test.go +++ b/vms/platformvm/state/diff_test.go @@ -777,65 +777,39 @@ func TestDiffSubnetConversion(t *testing.T) { require = require.New(t) state = newTestState(t, memdb.New()) subnetID = ids.GenerateTestID() - expectedConversion = subnetConversion{ + expectedConversion = SubnetConversion{ ConversionID: ids.GenerateTestID(), ChainID: ids.GenerateTestID(), Addr: []byte{1, 2, 3, 4}, } ) - conversionID, chainID, addr, err := state.GetSubnetConversion(subnetID) + actualConversion, err := state.GetSubnetConversion(subnetID) require.ErrorIs(err, database.ErrNotFound) - require.Zero(subnetConversion{ - ConversionID: conversionID, - ChainID: chainID, - Addr: addr, - }) + require.Zero(actualConversion) d, err := NewDiffOn(state) require.NoError(err) - conversionID, chainID, addr, err = d.GetSubnetConversion(subnetID) + actualConversion, err = d.GetSubnetConversion(subnetID) require.ErrorIs(err, database.ErrNotFound) - require.Zero(subnetConversion{ - ConversionID: conversionID, - ChainID: chainID, - Addr: addr, - }) + require.Zero(actualConversion) // Setting a subnet conversion should be reflected on diff not state - d.SetSubnetConversion(subnetID, expectedConversion.ConversionID, expectedConversion.ChainID, expectedConversion.Addr) - conversionID, chainID, addr, err = d.GetSubnetConversion(subnetID) + d.SetSubnetConversion(subnetID, expectedConversion) + actualConversion, err = d.GetSubnetConversion(subnetID) require.NoError(err) - require.Equal( - expectedConversion, - subnetConversion{ - ConversionID: conversionID, - ChainID: chainID, - Addr: addr, - }, - ) + require.Equal(expectedConversion, actualConversion) - conversionID, chainID, addr, err = state.GetSubnetConversion(subnetID) + actualConversion, err = state.GetSubnetConversion(subnetID) require.ErrorIs(err, database.ErrNotFound) - require.Zero(subnetConversion{ - ConversionID: conversionID, - ChainID: chainID, - Addr: addr, - }) + require.Zero(actualConversion) // State should reflect new subnet conversion after diff is applied require.NoError(d.Apply(state)) - conversionID, chainID, addr, err = state.GetSubnetConversion(subnetID) + actualConversion, err = state.GetSubnetConversion(subnetID) require.NoError(err) - require.Equal( - expectedConversion, - subnetConversion{ - ConversionID: conversionID, - ChainID: chainID, - Addr: addr, - }, - ) + require.Equal(expectedConversion, actualConversion) } func TestDiffStacking(t *testing.T) { diff --git a/vms/platformvm/state/mock_chain.go b/vms/platformvm/state/mock_chain.go index f4f8dc661b90..27daeae3a101 100644 --- a/vms/platformvm/state/mock_chain.go +++ b/vms/platformvm/state/mock_chain.go @@ -354,14 +354,12 @@ func (mr *MockChainMockRecorder) GetPendingValidator(subnetID, nodeID any) *gomo } // GetSubnetConversion mocks base method. -func (m *MockChain) GetSubnetConversion(subnetID ids.ID) (ids.ID, ids.ID, []byte, error) { +func (m *MockChain) GetSubnetConversion(subnetID ids.ID) (SubnetConversion, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSubnetConversion", subnetID) - ret0, _ := ret[0].(ids.ID) - ret1, _ := ret[1].(ids.ID) - ret2, _ := ret[2].([]byte) - ret3, _ := ret[3].(error) - return ret0, ret1, ret2, ret3 + ret0, _ := ret[0].(SubnetConversion) + ret1, _ := ret[1].(error) + return ret0, ret1 } // GetSubnetConversion indicates an expected call of GetSubnetConversion. @@ -575,15 +573,15 @@ func (mr *MockChainMockRecorder) SetFeeState(f any) *gomock.Call { } // SetSubnetConversion mocks base method. -func (m *MockChain) SetSubnetConversion(subnetID, conversionID, chainID ids.ID, addr []byte) { +func (m *MockChain) SetSubnetConversion(subnetID ids.ID, c SubnetConversion) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSubnetConversion", subnetID, conversionID, chainID, addr) + m.ctrl.Call(m, "SetSubnetConversion", subnetID, c) } // SetSubnetConversion indicates an expected call of SetSubnetConversion. -func (mr *MockChainMockRecorder) SetSubnetConversion(subnetID, conversionID, chainID, addr any) *gomock.Call { +func (mr *MockChainMockRecorder) SetSubnetConversion(subnetID, c any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSubnetConversion", reflect.TypeOf((*MockChain)(nil).SetSubnetConversion), subnetID, conversionID, chainID, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSubnetConversion", reflect.TypeOf((*MockChain)(nil).SetSubnetConversion), subnetID, c) } // SetSubnetOwner mocks base method. diff --git a/vms/platformvm/state/mock_diff.go b/vms/platformvm/state/mock_diff.go index bbeed71080b1..8732fc49b406 100644 --- a/vms/platformvm/state/mock_diff.go +++ b/vms/platformvm/state/mock_diff.go @@ -368,14 +368,12 @@ func (mr *MockDiffMockRecorder) GetPendingValidator(subnetID, nodeID any) *gomoc } // GetSubnetConversion mocks base method. -func (m *MockDiff) GetSubnetConversion(subnetID ids.ID) (ids.ID, ids.ID, []byte, error) { +func (m *MockDiff) GetSubnetConversion(subnetID ids.ID) (SubnetConversion, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSubnetConversion", subnetID) - ret0, _ := ret[0].(ids.ID) - ret1, _ := ret[1].(ids.ID) - ret2, _ := ret[2].([]byte) - ret3, _ := ret[3].(error) - return ret0, ret1, ret2, ret3 + ret0, _ := ret[0].(SubnetConversion) + ret1, _ := ret[1].(error) + return ret0, ret1 } // GetSubnetConversion indicates an expected call of GetSubnetConversion. @@ -589,15 +587,15 @@ func (mr *MockDiffMockRecorder) SetFeeState(f any) *gomock.Call { } // SetSubnetConversion mocks base method. -func (m *MockDiff) SetSubnetConversion(subnetID, conversionID, chainID ids.ID, addr []byte) { +func (m *MockDiff) SetSubnetConversion(subnetID ids.ID, c SubnetConversion) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSubnetConversion", subnetID, conversionID, chainID, addr) + m.ctrl.Call(m, "SetSubnetConversion", subnetID, c) } // SetSubnetConversion indicates an expected call of SetSubnetConversion. -func (mr *MockDiffMockRecorder) SetSubnetConversion(subnetID, conversionID, chainID, addr any) *gomock.Call { +func (mr *MockDiffMockRecorder) SetSubnetConversion(subnetID, c any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSubnetConversion", reflect.TypeOf((*MockDiff)(nil).SetSubnetConversion), subnetID, conversionID, chainID, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSubnetConversion", reflect.TypeOf((*MockDiff)(nil).SetSubnetConversion), subnetID, c) } // SetSubnetOwner mocks base method. diff --git a/vms/platformvm/state/mock_state.go b/vms/platformvm/state/mock_state.go index ed44205d9b49..a17593982572 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -558,14 +558,12 @@ func (mr *MockStateMockRecorder) GetStatelessBlock(blockID any) *gomock.Call { } // GetSubnetConversion mocks base method. -func (m *MockState) GetSubnetConversion(subnetID ids.ID) (ids.ID, ids.ID, []byte, error) { +func (m *MockState) GetSubnetConversion(subnetID ids.ID) (SubnetConversion, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSubnetConversion", subnetID) - ret0, _ := ret[0].(ids.ID) - ret1, _ := ret[1].(ids.ID) - ret2, _ := ret[2].([]byte) - ret3, _ := ret[3].(error) - return ret0, ret1, ret2, ret3 + ret0, _ := ret[0].(SubnetConversion) + ret1, _ := ret[1].(error) + return ret0, ret1 } // GetSubnetConversion indicates an expected call of GetSubnetConversion. @@ -848,15 +846,15 @@ func (mr *MockStateMockRecorder) SetLastAccepted(blkID any) *gomock.Call { } // SetSubnetConversion mocks base method. -func (m *MockState) SetSubnetConversion(subnetID, conversionID, chainID ids.ID, addr []byte) { +func (m *MockState) SetSubnetConversion(subnetID ids.ID, c SubnetConversion) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSubnetConversion", subnetID, conversionID, chainID, addr) + m.ctrl.Call(m, "SetSubnetConversion", subnetID, c) } // SetSubnetConversion indicates an expected call of SetSubnetConversion. -func (mr *MockStateMockRecorder) SetSubnetConversion(subnetID, conversionID, chainID, addr any) *gomock.Call { +func (mr *MockStateMockRecorder) SetSubnetConversion(subnetID, c any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSubnetConversion", reflect.TypeOf((*MockState)(nil).SetSubnetConversion), subnetID, conversionID, chainID, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSubnetConversion", reflect.TypeOf((*MockState)(nil).SetSubnetConversion), subnetID, c) } // SetSubnetOwner mocks base method. diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index a059323f6874..58c2056570bd 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -123,8 +123,8 @@ type Chain interface { GetSubnetOwner(subnetID ids.ID) (fx.Owner, error) SetSubnetOwner(subnetID ids.ID, owner fx.Owner) - GetSubnetConversion(subnetID ids.ID) (conversionID ids.ID, chainID ids.ID, addr []byte, err error) - SetSubnetConversion(subnetID ids.ID, conversionID ids.ID, chainID ids.ID, addr []byte) + GetSubnetConversion(subnetID ids.ID) (SubnetConversion, error) + SetSubnetConversion(subnetID ids.ID, c SubnetConversion) GetSubnetTransformation(subnetID ids.ID) (*txs.Tx, error) AddSubnetTransformation(transformSubnetTx *txs.Tx) @@ -366,8 +366,8 @@ type state struct { subnetOwnerCache cache.Cacher[ids.ID, fxOwnerAndSize] // cache of subnetID -> owner; if the entry is nil, it is not in the database subnetOwnerDB database.Database - subnetConversions map[ids.ID]subnetConversion // map of subnetID -> conversion of the subnet - subnetConversionCache cache.Cacher[ids.ID, subnetConversion] // cache of subnetID -> conversion + subnetConversions map[ids.ID]SubnetConversion // map of subnetID -> conversion of the subnet + subnetConversionCache cache.Cacher[ids.ID, SubnetConversion] // cache of subnetID -> conversion subnetConversionDB database.Database transformedSubnets map[ids.ID]*txs.Tx // map of subnetID -> transformSubnetTx @@ -441,7 +441,7 @@ type fxOwnerAndSize struct { size int } -type subnetConversion struct { +type SubnetConversion struct { ConversionID ids.ID `serialize:"true"` ChainID ids.ID `serialize:"true"` Addr []byte `serialize:"true"` @@ -556,10 +556,10 @@ func New( } subnetConversionDB := prefixdb.New(SubnetConversionPrefix, baseDB) - subnetConversionCache, err := metercacher.New[ids.ID, subnetConversion]( + subnetConversionCache, err := metercacher.New[ids.ID, SubnetConversion]( "subnet_conversion_cache", metricsReg, - cache.NewSizedLRU[ids.ID, subnetConversion](execCfg.SubnetConversionCacheSize, func(_ ids.ID, c subnetConversion) int { + cache.NewSizedLRU[ids.ID, SubnetConversion](execCfg.SubnetConversionCacheSize, func(_ ids.ID, c SubnetConversion) int { return 3*ids.IDLen + len(c.Addr) }), ) @@ -669,7 +669,7 @@ func New( subnetOwnerDB: subnetOwnerDB, subnetOwnerCache: subnetOwnerCache, - subnetConversions: make(map[ids.ID]subnetConversion), + subnetConversions: make(map[ids.ID]SubnetConversion), subnetConversionDB: subnetConversionDB, subnetConversionCache: subnetConversionCache, @@ -859,34 +859,30 @@ func (s *state) SetSubnetOwner(subnetID ids.ID, owner fx.Owner) { s.subnetOwners[subnetID] = owner } -func (s *state) GetSubnetConversion(subnetID ids.ID) (ids.ID, ids.ID, []byte, error) { +func (s *state) GetSubnetConversion(subnetID ids.ID) (SubnetConversion, error) { if c, ok := s.subnetConversions[subnetID]; ok { - return c.ConversionID, c.ChainID, c.Addr, nil + return c, nil } if c, ok := s.subnetConversionCache.Get(subnetID); ok { - return c.ConversionID, c.ChainID, c.Addr, nil + return c, nil } bytes, err := s.subnetConversionDB.Get(subnetID[:]) if err != nil { - return ids.Empty, ids.Empty, nil, err + return SubnetConversion{}, err } - var c subnetConversion + var c SubnetConversion if _, err := block.GenesisCodec.Unmarshal(bytes, &c); err != nil { - return ids.Empty, ids.Empty, nil, err + return SubnetConversion{}, err } s.subnetConversionCache.Put(subnetID, c) - return c.ConversionID, c.ChainID, c.Addr, nil + return c, nil } -func (s *state) SetSubnetConversion(subnetID ids.ID, conversionID ids.ID, chainID ids.ID, addr []byte) { - s.subnetConversions[subnetID] = subnetConversion{ - ConversionID: conversionID, - ChainID: chainID, - Addr: addr, - } +func (s *state) SetSubnetConversion(subnetID ids.ID, c SubnetConversion) { + s.subnetConversions[subnetID] = c } func (s *state) GetSubnetTransformation(subnetID ids.ID) (*txs.Tx, error) { diff --git a/vms/platformvm/state/state_test.go b/vms/platformvm/state/state_test.go index f2e0483a25c6..d29129500435 100644 --- a/vms/platformvm/state/state_test.go +++ b/vms/platformvm/state/state_test.go @@ -1326,18 +1326,17 @@ func TestStateSubnetOwner(t *testing.T) { func TestStateSubnetConversion(t *testing.T) { tests := []struct { name string - setup func(s *state, subnetID ids.ID, c subnetConversion) + setup func(s *state, subnetID ids.ID, c SubnetConversion) }{ { name: "in-memory", - setup: func(s *state, subnetID ids.ID, c subnetConversion) { - s.SetSubnetConversion(subnetID, c.ConversionID, c.ChainID, c.Addr) + setup: func(s *state, subnetID ids.ID, c SubnetConversion) { + s.SetSubnetConversion(subnetID, c) }, }, { name: "cache", - setup: func(s *state, subnetID ids.ID, c subnetConversion) { - s.subnetConversionCache.Flush() + setup: func(s *state, subnetID ids.ID, c SubnetConversion) { s.subnetConversionCache.Put(subnetID, c) }, }, @@ -1348,33 +1347,22 @@ func TestStateSubnetConversion(t *testing.T) { require = require.New(t) state = newTestState(t, memdb.New()) subnetID = ids.GenerateTestID() - expectedConversion = subnetConversion{ + expectedConversion = SubnetConversion{ ConversionID: ids.GenerateTestID(), ChainID: ids.GenerateTestID(), Addr: []byte{'a', 'd', 'd', 'r'}, } ) - conversionID, chainID, addr, err := state.GetSubnetConversion(subnetID) + actualConversion, err := state.GetSubnetConversion(subnetID) require.ErrorIs(err, database.ErrNotFound) - require.Zero(subnetConversion{ - ConversionID: conversionID, - ChainID: chainID, - Addr: addr, - }) + require.Zero(actualConversion) test.setup(state, subnetID, expectedConversion) - conversionID, chainID, addr, err = state.GetSubnetConversion(subnetID) + actualConversion, err = state.GetSubnetConversion(subnetID) require.NoError(err) - require.Equal( - expectedConversion, - subnetConversion{ - ConversionID: conversionID, - ChainID: chainID, - Addr: addr, - }, - ) + require.Equal(expectedConversion, actualConversion) }) } } diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index 69b8cd567586..72ef8561ad43 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -308,7 +308,7 @@ func verifyRemoveSubnetValidatorTx( } if backend.Config.UpgradeConfig.IsEtnaActivated(currentTimestamp) { - _, _, _, err := chainState.GetSubnetConversion(tx.Subnet) + _, err := chainState.GetSubnetConversion(tx.Subnet) if err == nil { return nil, false, fmt.Errorf("%w: %q", ErrRemoveValidatorManagedSubnet, tx.Subnet) } diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index 9cc9eddf723b..1c08880a94e0 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -542,8 +542,15 @@ func (e *StandardTxExecutor) ConvertSubnetTx(tx *txs.ConvertSubnetTx) error { // Produce the UTXOS avax.Produce(e.State, txID, tx.Outs) // Track the subnet conversion in the database - // TODO: Populate the conversionID - e.State.SetSubnetConversion(tx.Subnet, ids.Empty, tx.ChainID, tx.Address) + e.State.SetSubnetConversion( + tx.Subnet, + state.SubnetConversion{ + // TODO: Populate the conversionID + ConversionID: ids.Empty, + ChainID: tx.ChainID, + Addr: tx.Address, + }, + ) return nil } diff --git a/vms/platformvm/txs/executor/subnet_tx_verification.go b/vms/platformvm/txs/executor/subnet_tx_verification.go index 7466fd78227e..59acbe650491 100644 --- a/vms/platformvm/txs/executor/subnet_tx_verification.go +++ b/vms/platformvm/txs/executor/subnet_tx_verification.go @@ -43,7 +43,7 @@ func verifyPoASubnetAuthorization( return nil, err } - _, _, _, err = chainState.GetSubnetConversion(subnetID) + _, err = chainState.GetSubnetConversion(subnetID) if err == nil { return nil, fmt.Errorf("%q %w", subnetID, errIsImmutable) } From f1b07d294a98b6035cdd5e8804ec602826fb857b Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sun, 20 Oct 2024 13:30:34 -0400 Subject: [PATCH 13/14] nit --- .../txs/executor/create_chain_test.go | 8 ++-- .../txs/executor/standard_tx_executor_test.go | 41 ++++++++++++++----- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index cf3e0e8d2cf2..7f9919e4a8f5 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -288,9 +288,11 @@ func TestEtnaCreateChainTxInvalidWithManagedSubnet(t *testing.T) { stateDiff.SetSubnetConversion( subnetID, - ids.GenerateTestID(), - ids.GenerateTestID(), - []byte{'a', 'd', 'd', 'r', 'e', 's', 's'}, + state.SubnetConversion{ + ConversionID: ids.GenerateTestID(), + ChainID: ids.GenerateTestID(), + Addr: []byte("address"), + }, ) feeCalculator := state.PickFeeCalculator(env.config, builderDiff) diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 64686a1c744e..e3f6a67b21b3 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -915,9 +915,11 @@ func TestEtnaStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState.SetSubnetConversion( subnetID, - ids.GenerateTestID(), - ids.GenerateTestID(), - []byte{'a', 'd', 'd', 'r', 'e', 's', 's'}, + state.SubnetConversion{ + ConversionID: ids.GenerateTestID(), + ChainID: ids.GenerateTestID(), + Addr: []byte("address"), + }, ) executor := StandardTxExecutor{ @@ -1999,7 +2001,14 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { name: "attempted to remove subnet validator after subnet conversion has occurred", newExecutor: func(ctrl *gomock.Controller) (*txs.RemoveSubnetValidatorTx, *StandardTxExecutor) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) - env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return(ids.GenerateTestID(), ids.GenerateTestID(), []byte{'a', 'd', 'd', 'r', 'e', 's', 's'}, nil).AnyTimes() + env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return( + state.SubnetConversion{ + ConversionID: ids.GenerateTestID(), + ChainID: ids.GenerateTestID(), + Addr: []byte("address"), + }, + nil, + ).AnyTimes() env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() cfg := &config.Config{ @@ -2483,7 +2492,14 @@ func TestStandardExecutorConvertSubnetTx(t *testing.T) { { name: "invalid if subnet is converted", updateExecutor: func(e *StandardTxExecutor) { - e.State.SetSubnetConversion(subnetID, ids.GenerateTestID(), ids.GenerateTestID(), nil) + e.State.SetSubnetConversion( + subnetID, + state.SubnetConversion{ + ConversionID: ids.GenerateTestID(), + ChainID: ids.GenerateTestID(), + Addr: utils.RandomBytes(32), + }, + ) }, expectedErr: errIsImmutable, }, @@ -2571,12 +2587,17 @@ func TestStandardExecutorConvertSubnetTx(t *testing.T) { require.Equal(expectedUTXO, utxo) } - stateConversionID, stateChainID, stateAddress, err := diff.GetSubnetConversion(subnetID) + stateConversion, err := diff.GetSubnetConversion(subnetID) require.NoError(err) - // TODO: Update this test when we populate the correct conversionID - require.Zero(stateConversionID) - require.Equal(chainID, stateChainID) - require.Equal(address, stateAddress) + require.Equal( + state.SubnetConversion{ + // TODO: Specify the correct conversionID + ConversionID: ids.Empty, + ChainID: chainID, + Addr: address, + }, + stateConversion, + ) }) } } From 7fb99c068b63d5937d098e088033cb009e394c1d Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Sun, 20 Oct 2024 15:21:42 -0400 Subject: [PATCH 14/14] fix unit tests --- .../txs/executor/standard_tx_executor_test.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index e3f6a67b21b3..0301748101bc 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -2259,7 +2259,10 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { subnetOwner := fxmock.NewOwner(ctrl) env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil) - env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return(ids.Empty, ids.Empty, nil, database.ErrNotFound).Times(1) + env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return( + state.SubnetConversion{}, + database.ErrNotFound, + ).Times(1) env.state.EXPECT().GetSubnetTransformation(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound).Times(1) env.fx.EXPECT().VerifyPermission(gomock.Any(), env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(nil) env.flowChecker.EXPECT().VerifySpend( @@ -2298,7 +2301,14 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { subnetOwner := fxmock.NewOwner(ctrl) env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil).Times(1) - env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return(ids.GenerateTestID(), ids.GenerateTestID(), make([]byte, 20), nil) + env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return( + state.SubnetConversion{ + ConversionID: ids.GenerateTestID(), + ChainID: ids.GenerateTestID(), + Addr: make([]byte, 20), + }, + nil, + ) env.state.EXPECT().GetSubnetTransformation(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound).Times(1) env.fx.EXPECT().VerifyPermission(env.unsignedTx, env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(nil).Times(1) @@ -2333,7 +2343,10 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { subnetOwner := fxmock.NewOwner(ctrl) env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil).Times(1) - env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return(ids.Empty, ids.Empty, nil, database.ErrNotFound).Times(1) + env.state.EXPECT().GetSubnetConversion(env.unsignedTx.Subnet).Return( + state.SubnetConversion{}, + database.ErrNotFound, + ).Times(1) env.state.EXPECT().GetSubnetTransformation(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound).Times(1) env.fx.EXPECT().VerifyPermission(env.unsignedTx, env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(nil).Times(1) env.flowChecker.EXPECT().VerifySpend(