Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ACP-77: Add ConversionID to state #3481

Merged
merged 14 commits into from
Oct 20, 2024
4 changes: 3 additions & 1 deletion vms/platformvm/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 an L1
ConversionID ids.ID
ManagerChainID ids.ID
ManagerAddress []byte
}
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions vms/platformvm/config/execution_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand All @@ -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"`
}
Expand Down
2 changes: 1 addition & 1 deletion vms/platformvm/config/execution_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestExecutionConfigUnmarshal(t *testing.T) {
ChainDBCacheSize: 7,
BlockIDCacheSize: 8,
FxOwnerCacheSize: 9,
SubnetManagerCacheSize: 10,
SubnetConversionCacheSize: 10,
ChecksumsEnabled: true,
MempoolPruneFrequency: time.Minute,
}
Expand Down
7 changes: 5 additions & 2 deletions vms/platformvm/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 an L1
ConversionID ids.ID `json:"conversionID"`
ManagerChainID ids.ID `json:"managerChainID"`
ManagerAddress types.JSONByteSlice `json:"managerAddress"`
}
Expand Down Expand Up @@ -490,12 +491,14 @@ 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:
response.ConversionID = ids.Empty
response.ManagerChainID = ids.Empty
response.ManagerAddress = []byte(nil)
default:
Expand Down
18 changes: 13 additions & 5 deletions vms/platformvm/service.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
StephenButtolph marked this conversation as resolved.
Show resolved Hide resolved

**Signature:**

Expand All @@ -1217,7 +1217,10 @@ platform.getSubnet({
controlKeys: []string,
threshold: string,
locktime: string,
subnetTransformationTxID: string
subnetTransformationTxID: string,
conversionID: string,
managerChainID: string,
managerAddress: string
}
```

Expand All @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `subnetTransformationTxID` is the ID of the transaction that changed the subnet into an elastic one, if it exists.
- `subnetTransformationTxID` is the ID of the transaction that changed the subnet into an L1, if it exists.

Copy link
Contributor

@meaghanfitzgerald meaghanfitzgerald Oct 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

realized this is probably only referencing the tx hash of TransformSubnetTx can this field not be removed from the response since it has been deprecated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it makes sense to remove this as part of this PR.

- `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:**

Expand All @@ -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
}
Expand Down
45 changes: 23 additions & 22 deletions vms/platformvm/state/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
}

Expand Down Expand Up @@ -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) {
StephenButtolph marked this conversation as resolved.
Show resolved Hide resolved
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.
// 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, 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,
}
}

Expand Down Expand Up @@ -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
}
72 changes: 48 additions & 24 deletions vms/platformvm/state/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -772,46 +772,70 @@ 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())
newManager = chainIDAndAddr{ids.GenerateTestID(), []byte{1, 2, 3, 4}}
subnetID = ids.GenerateTestID()
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},
}
)

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{
marun marked this conversation as resolved.
Show resolved Hide resolved
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
// State should reflect new subnet conversion 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) {
Expand Down
31 changes: 16 additions & 15 deletions vms/platformvm/state/mock_chain.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 16 additions & 15 deletions vms/platformvm/state/mock_diff.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading