mirror of
https://github.com/luxfi/cli.git
synced 2026-10-30 17:01:20 +00:00
108 lines
4.2 KiB
Go
108 lines
4.2 KiB
Go
// Copyright (C) 2022, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
package txutils
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/luxfi/node/v2/v2/utils/crypto/secp256k1"
|
|
"github.com/luxfi/node/v2/v2/vms/components/verify"
|
|
"github.com/luxfi/node/v2/v2/vms/platformvm/txs"
|
|
"github.com/luxfi/node/v2/v2/vms/secp256k1fx"
|
|
)
|
|
|
|
// get all subnet auth addresses that are required to sign a given tx
|
|
// - get subnet control keys as string slice using P-Chain API (GetOwners)
|
|
// - get subnet auth indices from the tx, field tx.UnsignedTx.SubnetAuth
|
|
// - creates the string slice of required subnet auth addresses by applying
|
|
// the indices to the control keys slice
|
|
//
|
|
// expect tx.Unsigned type to be in:
|
|
// - txs.CreateChainTx
|
|
// - txs.AddSubnetValidatorTx
|
|
// - txs.RemoveSubnetValidatorTx
|
|
//
|
|
// controlKeys must be in the same order as in the subnet creation tx (as obtained by GetOwners)
|
|
func GetAuthSigners(tx *txs.Tx, controlKeys []string) ([]string, error) {
|
|
unsignedTx := tx.Unsigned
|
|
var subnetAuth verify.Verifiable
|
|
switch unsignedTx := unsignedTx.(type) {
|
|
case *txs.RemoveSubnetValidatorTx:
|
|
subnetAuth = unsignedTx.SubnetAuth
|
|
case *txs.AddSubnetValidatorTx:
|
|
subnetAuth = unsignedTx.SubnetAuth
|
|
case *txs.CreateChainTx:
|
|
subnetAuth = unsignedTx.SubnetAuth
|
|
case *txs.TransformSubnetTx:
|
|
subnetAuth = unsignedTx.SubnetAuth
|
|
default:
|
|
return nil, fmt.Errorf("unexpected unsigned tx type %T", unsignedTx)
|
|
}
|
|
subnetInput, ok := subnetAuth.(*secp256k1fx.Input)
|
|
if !ok {
|
|
return nil, fmt.Errorf("expected subnetAuth of type *secp256k1fx.Input, got %T", subnetAuth)
|
|
}
|
|
authSigners := []string{}
|
|
for _, sigIndex := range subnetInput.SigIndices {
|
|
if sigIndex >= uint32(len(controlKeys)) {
|
|
return nil, fmt.Errorf("signer index %d exceeds number of control keys", sigIndex)
|
|
}
|
|
authSigners = append(authSigners, controlKeys[sigIndex])
|
|
}
|
|
return authSigners, nil
|
|
}
|
|
|
|
// get subnet auth addresses that did not yet signed a given tx
|
|
// - get the string slice of auth signers for the tx (GetAuthSigners)
|
|
// - verifies that all creds in tx.Creds, except the last one, are fully signed
|
|
// (a cred is fully signed if all the signatures in cred.Sigs are non-empty)
|
|
// - computes remaining signers by iterating the last cred in tx.Creds, associated to subnet auth signing
|
|
// - for each sig in cred.Sig: if sig is empty, then add the associated auth signer address (obtained from
|
|
// authSigners by using the index) to the remaining signers list
|
|
//
|
|
// if the tx is fully signed, returns empty slice
|
|
// expect tx.Unsigned type to be in [txs.AddSubnetValidatorTx, txs.CreateChainTx]
|
|
//
|
|
// controlKeys must be in the same order as in the subnet creation tx (as obtained by GetOwners)
|
|
func GetRemainingSigners(tx *txs.Tx, controlKeys []string) ([]string, []string, error) {
|
|
authSigners, err := GetAuthSigners(tx, controlKeys)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
emptySig := [secp256k1.SignatureLen]byte{}
|
|
// we should have at least 1 cred for output owners and 1 cred for subnet auth
|
|
if len(tx.Creds) < 2 {
|
|
return nil, nil, fmt.Errorf("expected tx.Creds of len 2, got %d", len(tx.Creds))
|
|
}
|
|
// signatures for output owners should be filled (all creds except last one)
|
|
for credIndex := range tx.Creds[:len(tx.Creds)-1] {
|
|
cred, ok := tx.Creds[credIndex].(*secp256k1fx.Credential)
|
|
if !ok {
|
|
return nil, nil, fmt.Errorf("expected cred to be of type *secp256k1fx.Credential, got %T", tx.Creds[credIndex])
|
|
}
|
|
for i, sig := range cred.Sigs {
|
|
if sig == emptySig {
|
|
return nil, nil, fmt.Errorf("expected funding sig %d of cred %d to be filled", i, credIndex)
|
|
}
|
|
}
|
|
}
|
|
// signatures for subnet auth (last cred)
|
|
cred, ok := tx.Creds[len(tx.Creds)-1].(*secp256k1fx.Credential)
|
|
if !ok {
|
|
return nil, nil, fmt.Errorf("expected cred to be of type *secp256k1fx.Credential, got %T", tx.Creds[1])
|
|
}
|
|
if len(cred.Sigs) != len(authSigners) {
|
|
return nil, nil, fmt.Errorf("expected number of cred's signatures %d to equal number of auth signers %d",
|
|
len(cred.Sigs),
|
|
len(authSigners),
|
|
)
|
|
}
|
|
remainingSigners := []string{}
|
|
for i, sig := range cred.Sigs {
|
|
if sig == emptySig {
|
|
remainingSigners = append(remainingSigners, authSigners[i])
|
|
}
|
|
}
|
|
return authSigners, remainingSigners, nil
|
|
}
|