Skip to content

Commit

Permalink
feat: multisig prepend existing signatures with given signature
Browse files Browse the repository at this point in the history
  • Loading branch information
OxIchigo committed Nov 30, 2023
1 parent 00ee987 commit 3437177
Showing 1 changed file with 94 additions and 1 deletion.
95 changes: 94 additions & 1 deletion x/auth/client/cli/tx_multisign.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/errors"
Expand Down Expand Up @@ -120,6 +122,45 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) (err error) {
txFactory = txFactory.WithAccountNumber(accnum).WithSequence(seq)
}

sigVerifiableTx := parsedTx.(signing.SigVerifiableTx)
oldSigs, _ := sigVerifiableTx.GetSignaturesV2()
txPubKeys, _ := sigVerifiableTx.GetPubKeys()
signModeHandler := txCfg.SignModeHandler()

extractedSignatues := make([]signingtypes.SignatureV2, 0)

for _, sig := range oldSigs {
extractedSigs := extractSignatues(sig, txPubKeys, clientCtx.LegacyAmino, func(pk cryptotypes.PubKey, signatureData signingtypes.SignatureData) error {
signingData := signing.SignerData{
Address: sdk.AccAddress(pk.Address()).String(),
ChainID: txFactory.ChainID(),
AccountNumber: txFactory.AccountNumber(),
Sequence: txFactory.Sequence(),
PubKey: pk,
}

singleSignatureData, ok := signatureData.(*signingtypes.SingleSignatureData)
// TODO - Implemenation required for multisignatureData case
if !ok {
return fmt.Errorf("nested multisignature is not supported yet")
}
msg, _ := signModeHandler.GetSignBytes(singleSignatureData.SignMode, signingData, txBuilder.GetTx())

valid := pk.VerifySignature(msg, singleSignatureData.Signature)
if !valid {
return fmt.Errorf("signature doesn't match with the given public key")
}
return nil
})

// Add All extracted signatures into signature slice
extractedSignatues = append(extractedSignatues, extractedSigs...)
}

for _, sig := range extractedSignatues {
multisig.AddSignatureV2(multisigSig, sig, multisigPub.GetPubKeys())

Check warning

Code scanning / gosec

Errors unhandled. Warning

Errors unhandled.
}

// read each signature and add it to the multisig if valid
for i := 2; i < len(args); i++ {
sigs, err := unmarshalSignatureJSON(clientCtx, args[i])
Expand All @@ -140,7 +181,7 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) (err error) {
PubKey: sig.PubKey,
}

err = signing.VerifySignature(sig.PubKey, signingData, sig.Data, txCfg.SignModeHandler(), txBuilder.GetTx())
err = signing.VerifySignature(sig.PubKey, signingData, sig.Data, signModeHandler, txBuilder.GetTx())
if err != nil {
addr, _ := sdk.AccAddressFromHexUnsafe(sig.PubKey.Address().String())
return fmt.Errorf("couldn't verify signature for address %s", addr)
Expand Down Expand Up @@ -418,3 +459,55 @@ func getMultisigRecord(clientCtx client.Context, name string) (*keyring.Record,

return multisigRecord, nil
}

type SignatureVerifier func(cryptotypes.PubKey, signingtypes.SignatureData) error

func matchPubKeyAndSignature(signatureData signingtypes.SignatureData, keys []cryptotypes.PubKey, verificationHandler SignatureVerifier) cryptotypes.PubKey {
for _, key := range keys {
multiPubkey, ok := key.(*kmultisig.LegacyAminoPubKey)
if ok {
return matchPubKeyAndSignature(signatureData, multiPubkey.GetPubKeys(), verificationHandler)
}
err := verificationHandler(key, signatureData)
if err == nil {
return key
}
}
return nil
}

func extractSignatues(oldSig signingtypes.SignatureV2, pubKeys []cryptotypes.PubKey, cdc *codec.LegacyAmino,
verificationHandler SignatureVerifier) []signingtypes.SignatureV2 {

Check failure on line 480 in x/auth/client/cli/tx_multisign.go

View workflow job for this annotation

GitHub Actions / golangci-lint

File is not `gofumpt`-ed (gofumpt)

extractedSignatues := make([]signingtypes.SignatureV2, 0)

switch data := oldSig.Data.(type) {

case *signingtypes.SingleSignatureData:
return append(extractedSignatues, oldSig)

case *signingtypes.MultiSignatureData:
for _, sig := range data.Signatures {
// TODO - convert this into switch case to handle nested multisig
singleSig, ok := sig.(*signingtypes.SingleSignatureData)
if !ok {
continue
}

pub := matchPubKeyAndSignature(singleSig, pubKeys, verificationHandler)
if pub != nil {
// TODO - find replacement for this deprecated method
stdSig := legacytx.StdSignature{

Check failure on line 500 in x/auth/client/cli/tx_multisign.go

View workflow job for this annotation

GitHub Actions / Analyze

SA1019: legacytx.StdSignature is deprecated: StdSignature represents a sig (staticcheck)

Check failure on line 500 in x/auth/client/cli/tx_multisign.go

View workflow job for this annotation

GitHub Actions / golangci-lint

SA1019: legacytx.StdSignature is deprecated: StdSignature represents a sig (staticcheck)
PubKey: pub,
Signature: singleSig.Signature,
}

sigV2, err := legacytx.StdSignatureToSignatureV2(cdc, stdSig)
if err == nil {
extractedSignatues = append(extractedSignatues, sigV2)
}
}
}
}
return extractedSignatues
}

0 comments on commit 3437177

Please sign in to comment.