Skip to content

Commit

Permalink
Add SoV deactivation owner support to the P-chain wallet (#3541)
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenButtolph authored and tsachiherman committed Jan 29, 2025
1 parent e8dca01 commit f4b4142
Show file tree
Hide file tree
Showing 14 changed files with 148 additions and 54 deletions.
1 change: 1 addition & 0 deletions vms/platformvm/block/builder/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ func newWallet(t testing.TB, e *environment, c walletConfig) wallet.Wallet {
e.state,
secp256k1fx.NewKeychain(c.keys...),
c.subnetIDs,
nil, // validationIDs
[]ids.ID{e.ctx.CChainID, e.ctx.XChainID},
)
}
Expand Down
1 change: 1 addition & 0 deletions vms/platformvm/block/executor/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ func newWallet(t testing.TB, e *environment, c walletConfig) wallet.Wallet {
e.state,
secp256k1fx.NewKeychain(c.keys...),
c.subnetIDs,
nil, // validationIDs
[]ids.ID{e.ctx.CChainID, e.ctx.XChainID},
)
}
Expand Down
3 changes: 3 additions & 0 deletions vms/platformvm/block/executor/verifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ func TestVerifierVisitAtomicBlock(t *testing.T) {
verifier.state,
secp256k1fx.NewKeychain(genesis.EWOQKey),
nil, // subnetIDs
nil, // validationIDs
nil, // chainIDs
)
exportedOutput = &avax.TransferableOutput{
Expand Down Expand Up @@ -346,6 +347,7 @@ func TestVerifierVisitStandardBlock(t *testing.T) {
verifier.state,
secp256k1fx.NewKeychain(genesis.EWOQKey),
nil, // subnetIDs
nil, // validationIDs
[]ids.ID{ctx.XChainID}, // Read the UTXO to import
)
initialTimestamp = verifier.state.GetTimestamp()
Expand Down Expand Up @@ -1098,6 +1100,7 @@ func TestBlockExecutionWithComplexity(t *testing.T) {
verifier.state,
secp256k1fx.NewKeychain(genesis.EWOQKey),
nil, // subnetIDs
nil, // validationIDs
nil, // chainIDs
)

Expand Down
20 changes: 19 additions & 1 deletion vms/platformvm/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ func GetSubnetOwners(
ctx context.Context,
subnetIDs ...ids.ID,
) (map[ids.ID]fx.Owner, error) {
subnetOwners := map[ids.ID]fx.Owner{}
subnetOwners := make(map[ids.ID]fx.Owner, len(subnetIDs))
for _, subnetID := range subnetIDs {
subnetInfo, err := c.GetSubnet(ctx, subnetID)
if err != nil {
Expand All @@ -660,3 +660,21 @@ func GetSubnetOwners(
}
return subnetOwners, nil
}

// GetDeactivationOwners returns a map of validation ID to subnet-only
// validation deactivation owner
func GetDeactivationOwners(
c Client,
ctx context.Context,
validationIDs ...ids.ID,
) (map[ids.ID]fx.Owner, error) {
deactivationOwners := make(map[ids.ID]fx.Owner, len(validationIDs))
for _, validationID := range validationIDs {
sov, _, err := c.GetSubnetOnlyValidator(ctx, validationID)
if err != nil {
return nil, err
}
deactivationOwners[validationID] = sov.DeactivationOwner
}
return deactivationOwners, nil
}
1 change: 1 addition & 0 deletions vms/platformvm/txs/executor/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ func newWallet(t testing.TB, e *environment, c walletConfig) wallet.Wallet {
e.state,
secp256k1fx.NewKeychain(c.keys...),
c.subnetIDs,
nil, // validationIDs
c.chainIDs,
)
}
Expand Down
17 changes: 11 additions & 6 deletions vms/platformvm/txs/executor/standard_tx_executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2383,6 +2383,7 @@ func TestStandardExecutorConvertSubnetTx(t *testing.T) {
baseState,
secp256k1fx.NewKeychain(genesistest.DefaultFundedKeys...),
nil, // subnetIDs
nil, // validationIDs
nil, // chainIDs
)
flowChecker = utxo.NewVerifier(
Expand Down Expand Up @@ -2562,6 +2563,7 @@ func TestStandardExecutorConvertSubnetTx(t *testing.T) {
baseState,
secp256k1fx.NewKeychain(genesistest.DefaultFundedKeys...),
[]ids.ID{subnetID},
nil, // validationIDs
nil, // chainIDs
)
chainID = ids.GenerateTestID()
Expand Down Expand Up @@ -2707,6 +2709,7 @@ func TestStandardExecutorRegisterSubnetValidatorTx(t *testing.T) {
baseState,
secp256k1fx.NewKeychain(genesistest.DefaultFundedKeys...),
nil, // subnetIDs
nil, // validationIDs
nil, // chainIDs
)
flowChecker = utxo.NewVerifier(
Expand Down Expand Up @@ -3122,23 +3125,23 @@ func TestStandardExecutorRegisterSubnetValidatorTx(t *testing.T) {
baseState,
secp256k1fx.NewKeychain(genesistest.DefaultFundedKeys...),
nil, // subnetIDs
nil, // validationIDs
nil, // chainIDs
)

message := test.message
if message == nil {
message = warpMessage.Bytes()
}
registerSubnetValidatorTx, err := wallet.IssueRegisterSubnetValidatorTx(
test.balance,
pop.ProofOfPossession,
message,
warpMessage.Bytes(),
test.builderOptions...,
)
require.NoError(err)

unsignedTx := registerSubnetValidatorTx.Unsigned.(*txs.RegisterSubnetValidatorTx)
if test.message != nil {
unsignedTx.Message = test.message
}
if test.updateTx != nil {
unsignedTx := registerSubnetValidatorTx.Unsigned.(*txs.RegisterSubnetValidatorTx)
test.updateTx(unsignedTx)
}

Expand Down Expand Up @@ -3239,6 +3242,7 @@ func TestStandardExecutorSetSubnetValidatorWeightTx(t *testing.T) {
baseState,
secp256k1fx.NewKeychain(genesistest.DefaultFundedKeys...),
nil, // subnetIDs
nil, // validationIDs
nil, // chainIDs
)
flowChecker = utxo.NewVerifier(
Expand Down Expand Up @@ -3634,6 +3638,7 @@ func TestStandardExecutorSetSubnetValidatorWeightTx(t *testing.T) {
baseState,
secp256k1fx.NewKeychain(genesistest.DefaultFundedKeys...),
nil, // subnetIDs
nil, // validationIDs
nil, // chainIDs
)

Expand Down
16 changes: 15 additions & 1 deletion vms/platformvm/txs/txstest/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/ava-labs/avalanchego/vms/platformvm/fx"
"github.com/ava-labs/avalanchego/vms/platformvm/state"
"github.com/ava-labs/avalanchego/vms/platformvm/txs"
"github.com/ava-labs/avalanchego/vms/platformvm/warp/message"
"github.com/ava-labs/avalanchego/vms/secp256k1fx"
"github.com/ava-labs/avalanchego/wallet/chain/p/builder"
"github.com/ava-labs/avalanchego/wallet/chain/p/signer"
Expand All @@ -32,6 +33,7 @@ func NewWallet(
state state.State,
kc *secp256k1fx.Keychain,
subnetIDs []ids.ID,
validationIDs []ids.ID,
chainIDs []ids.ID,
) wallet.Wallet {
var (
Expand Down Expand Up @@ -74,12 +76,24 @@ func NewWallet(
}
}

owners := make(map[ids.ID]fx.Owner, len(subnetIDs))
owners := make(map[ids.ID]fx.Owner, len(subnetIDs)+len(validationIDs))
for _, subnetID := range subnetIDs {
owner, err := state.GetSubnetOwner(subnetID)
require.NoError(err)
owners[subnetID] = owner
}
for _, validationID := range validationIDs {
sov, err := state.GetSubnetOnlyValidator(validationID)
require.NoError(err)

var owner message.PChainOwner
_, err = txs.Codec.Unmarshal(sov.DeactivationOwner, &owner)
require.NoError(err)
owners[validationID] = &secp256k1fx.OutputOwners{
Threshold: owner.Threshold,
Addrs: owner.Addresses,
}
}

builderContext := newContext(ctx, config, state)
backend := wallet.NewBackend(
Expand Down
1 change: 1 addition & 0 deletions vms/platformvm/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ func newWallet(t testing.TB, vm *VM, c walletConfig) wallet.Wallet {
vm.state,
secp256k1fx.NewKeychain(c.keys...),
c.subnetIDs,
nil, // validationIDs
[]ids.ID{vm.ctx.CChainID, vm.ctx.XChainID},
)
}
Expand Down
22 changes: 11 additions & 11 deletions wallet/chain/p/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ type Builder interface {

type Backend interface {
UTXOs(ctx context.Context, sourceChainID ids.ID) ([]*avax.UTXO, error)
GetSubnetOwner(ctx context.Context, subnetID ids.ID) (fx.Owner, error)
GetOwner(ctx context.Context, ownerID ids.ID) (fx.Owner, error)
}

type builder struct {
Expand Down Expand Up @@ -458,7 +458,7 @@ func (b *builder) NewAddSubnetValidatorTx(
toStake := map[ids.ID]uint64{}

ops := common.NewOptions(options)
subnetAuth, err := b.authorizeSubnet(vdr.Subnet, ops)
subnetAuth, err := b.authorize(vdr.Subnet, ops)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -516,7 +516,7 @@ func (b *builder) NewRemoveSubnetValidatorTx(
toStake := map[ids.ID]uint64{}

ops := common.NewOptions(options)
subnetAuth, err := b.authorizeSubnet(subnetID, ops)
subnetAuth, err := b.authorize(subnetID, ops)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -619,7 +619,7 @@ func (b *builder) NewCreateChainTx(
toStake := map[ids.ID]uint64{}

ops := common.NewOptions(options)
subnetAuth, err := b.authorizeSubnet(subnetID, ops)
subnetAuth, err := b.authorize(subnetID, ops)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -750,7 +750,7 @@ func (b *builder) NewTransferSubnetOwnershipTx(
toStake := map[ids.ID]uint64{}

ops := common.NewOptions(options)
subnetAuth, err := b.authorizeSubnet(subnetID, ops)
subnetAuth, err := b.authorize(subnetID, ops)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -827,7 +827,7 @@ func (b *builder) NewConvertSubnetTx(
toStake = map[ids.ID]uint64{}
ops = common.NewOptions(options)
)
subnetAuth, err := b.authorizeSubnet(subnetID, ops)
subnetAuth, err := b.authorize(subnetID, ops)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1215,7 +1215,7 @@ func (b *builder) NewTransformSubnetTx(
toStake := map[ids.ID]uint64{}

ops := common.NewOptions(options)
subnetAuth, err := b.authorizeSubnet(subnetID, ops)
subnetAuth, err := b.authorize(subnetID, ops)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1754,12 +1754,12 @@ func (b *builder) spend(
return s.inputs, s.changeOutputs, s.stakeOutputs, nil
}

func (b *builder) authorizeSubnet(subnetID ids.ID, options *common.Options) (*secp256k1fx.Input, error) {
ownerIntf, err := b.backend.GetSubnetOwner(options.Context(), subnetID)
func (b *builder) authorize(ownerID ids.ID, options *common.Options) (*secp256k1fx.Input, error) {
ownerIntf, err := b.backend.GetOwner(options.Context(), ownerID)
if err != nil {
return nil, fmt.Errorf(
"failed to fetch subnet owner for %q: %w",
subnetID,
"failed to fetch owner for %q: %w",
ownerID,
err,
)
}
Expand Down
2 changes: 1 addition & 1 deletion wallet/chain/p/signer/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type Signer interface {

type Backend interface {
GetUTXO(ctx stdcontext.Context, chainID, utxoID ids.ID) (*avax.UTXO, error)
GetSubnetOwner(ctx stdcontext.Context, subnetID ids.ID) (fx.Owner, error)
GetOwner(ctx stdcontext.Context, ownerID ids.ID) (fx.Owner, error)
}

type txSigner struct {
Expand Down
30 changes: 15 additions & 15 deletions wallet/chain/p/signer/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ var (
ErrUnknownInputType = errors.New("unknown input type")
ErrUnknownOutputType = errors.New("unknown output type")
ErrInvalidUTXOSigIndex = errors.New("invalid UTXO signature index")
ErrUnknownSubnetAuthType = errors.New("unknown subnet auth type")
ErrUnknownAuthType = errors.New("unknown auth type")
ErrUnknownOwnerType = errors.New("unknown owner type")
ErrUnknownCredentialType = errors.New("unknown credential type")

Expand Down Expand Up @@ -64,7 +64,7 @@ func (s *visitor) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error {
if err != nil {
return err
}
subnetAuthSigners, err := s.getSubnetSigners(tx.SubnetValidator.Subnet, tx.SubnetAuth)
subnetAuthSigners, err := s.getAuthSigners(tx.SubnetValidator.Subnet, tx.SubnetAuth)
if err != nil {
return err
}
Expand All @@ -85,7 +85,7 @@ func (s *visitor) CreateChainTx(tx *txs.CreateChainTx) error {
if err != nil {
return err
}
subnetAuthSigners, err := s.getSubnetSigners(tx.SubnetID, tx.SubnetAuth)
subnetAuthSigners, err := s.getAuthSigners(tx.SubnetID, tx.SubnetAuth)
if err != nil {
return err
}
Expand Down Expand Up @@ -127,7 +127,7 @@ func (s *visitor) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) error
if err != nil {
return err
}
subnetAuthSigners, err := s.getSubnetSigners(tx.Subnet, tx.SubnetAuth)
subnetAuthSigners, err := s.getAuthSigners(tx.Subnet, tx.SubnetAuth)
if err != nil {
return err
}
Expand All @@ -140,7 +140,7 @@ func (s *visitor) TransformSubnetTx(tx *txs.TransformSubnetTx) error {
if err != nil {
return err
}
subnetAuthSigners, err := s.getSubnetSigners(tx.Subnet, tx.SubnetAuth)
subnetAuthSigners, err := s.getAuthSigners(tx.Subnet, tx.SubnetAuth)
if err != nil {
return err
}
Expand Down Expand Up @@ -169,7 +169,7 @@ func (s *visitor) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipTx) e
if err != nil {
return err
}
subnetAuthSigners, err := s.getSubnetSigners(tx.Subnet, tx.SubnetAuth)
subnetAuthSigners, err := s.getAuthSigners(tx.Subnet, tx.SubnetAuth)
if err != nil {
return err
}
Expand All @@ -190,7 +190,7 @@ func (s *visitor) ConvertSubnetTx(tx *txs.ConvertSubnetTx) error {
if err != nil {
return err
}
subnetAuthSigners, err := s.getSubnetSigners(tx.Subnet, tx.SubnetAuth)
subnetAuthSigners, err := s.getAuthSigners(tx.Subnet, tx.SubnetAuth)
if err != nil {
return err
}
Expand Down Expand Up @@ -269,17 +269,17 @@ func (s *visitor) getSigners(sourceChainID ids.ID, ins []*avax.TransferableInput
return txSigners, nil
}

func (s *visitor) getSubnetSigners(subnetID ids.ID, subnetAuth verify.Verifiable) ([]keychain.Signer, error) {
subnetInput, ok := subnetAuth.(*secp256k1fx.Input)
func (s *visitor) getAuthSigners(ownerID ids.ID, auth verify.Verifiable) ([]keychain.Signer, error) {
input, ok := auth.(*secp256k1fx.Input)
if !ok {
return nil, ErrUnknownSubnetAuthType
return nil, ErrUnknownAuthType
}

ownerIntf, err := s.backend.GetSubnetOwner(s.ctx, subnetID)
ownerIntf, err := s.backend.GetOwner(s.ctx, ownerID)
if err != nil {
return nil, fmt.Errorf(
"failed to fetch subnet owner for %q: %w",
subnetID,
"failed to fetch owner for %q: %w",
ownerID,
err,
)
}
Expand All @@ -288,8 +288,8 @@ func (s *visitor) getSubnetSigners(subnetID ids.ID, subnetAuth verify.Verifiable
return nil, ErrUnknownOwnerType
}

authSigners := make([]keychain.Signer, len(subnetInput.SigIndices))
for sigIndex, addrIndex := range subnetInput.SigIndices {
authSigners := make([]keychain.Signer, len(input.SigIndices))
for sigIndex, addrIndex := range input.SigIndices {
if addrIndex >= uint32(len(owner.Addrs)) {
return nil, ErrInvalidUTXOSigIndex
}
Expand Down
Loading

0 comments on commit f4b4142

Please sign in to comment.