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

Migrate validate-signatures cmd to SignatureV2 #6470

Closed
wants to merge 10 commits into from
3 changes: 3 additions & 0 deletions crypto/types/multisig/pubkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ type PubKey interface {

// GetPubKeys returns the crypto.PubKey's nested within the multi-sig PubKey
GetPubKeys() []crypto.PubKey

// GetThreshold returns the threshold number of signatures that must be obtained to verify a signature.
GetThreshold() uint
}

// GetSignBytesFunc defines a function type which returns sign bytes for a given SignMode or an error.
Expand Down
5 changes: 5 additions & 0 deletions crypto/types/multisig/threshold_pubkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,8 @@ func (pk PubKeyMultisigThreshold) Equals(other crypto.PubKey) bool {
}
return true
}

// GetThreshold implements the PubKey.GetThreshold method
func (pk PubKeyMultisigThreshold) GetThreshold() uint {
return pk.K
}
106 changes: 76 additions & 30 deletions x/auth/client/cli/validate_sigs.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ 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/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)

Expand All @@ -37,11 +40,10 @@ transaction will be not be performed as that will require RPC communication with

func makeValidateSignaturesCmd(clientCtx client.Context) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0])
clientCtx, txBldr, stdTx, err := readTxAndInitContexts(clientCtx, cmd, args[0])
if err != nil {
return err
}
stdTx := tx.(types.StdTx)

if !printAndValidateSigs(cmd, clientCtx, txBldr.ChainID(), stdTx, clientCtx.Offline) {
return fmt.Errorf("signatures validation failed")
Expand All @@ -55,17 +57,23 @@ func makeValidateSignaturesCmd(clientCtx client.Context) func(cmd *cobra.Command
// expected signers. In addition, if offline has not been supplied, the signature is
// verified over the transaction sign bytes. Returns false if the validation fails.
func printAndValidateSigs(
cmd *cobra.Command, clientCtx client.Context, chainID string, stdTx types.StdTx, offline bool,
cmd *cobra.Command, clientCtx client.Context, chainID string, tx sdk.Tx, offline bool,
) bool {
sigTx := tx.(authsigning.SigVerifiableTx)
signModeHandler := clientCtx.TxGenerator.SignModeHandler()

cmd.Println("Signers:")
signers := stdTx.GetSigners()
signers := sigTx.GetSigners()

for i, signer := range signers {
cmd.Printf(" %v: %v\n", i, signer.String())
}

success := true
sigs := stdTx.Signatures
sigs, err := sigTx.GetSignaturesV2()
if err != nil {
panic(err)
}
cmd.Println("")
cmd.Println("Signatures:")

Expand All @@ -75,9 +83,10 @@ func printAndValidateSigs(

for i, sig := range sigs {
var (
pubKey = sig.PubKey
multiSigHeader string
multiSigMsg string
sigAddr = sdk.AccAddress(sig.GetPubKey().Address())
sigAddr = sdk.AccAddress(pubKey.Address())
sigSanity = "OK"
)

Expand All @@ -89,40 +98,63 @@ func printAndValidateSigs(
// Validate the actual signature over the transaction bytes since we can
// reach out to a full node to query accounts.
if !offline && success {
acc, err := types.NewAccountRetriever(authclient.Codec).GetAccount(clientCtx, sigAddr)
accNum, accSeq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, sigAddr)
if err != nil {
cmd.Printf("failed to get account: %s\n", sigAddr)
return false
}

sigBytes := types.StdSignBytes(
chainID, acc.GetAccountNumber(), acc.GetSequence(),
stdTx.Fee, stdTx.GetMsgs(), stdTx.GetMemo(),
)

if ok := sig.GetPubKey().VerifyBytes(sigBytes, sig.Signature); !ok {
sigSanity = "ERROR: signature invalid"
success = false
signingData := authsigning.SignerData{
ChainID: chainID,
AccountNumber: accNum,
AccountSequence: accSeq,
}
}

multiPK, ok := sig.GetPubKey().(multisig.PubKeyMultisigThreshold)
if ok {
var multiSig multisig.AminoMultisignature
clientCtx.Codec.MustUnmarshalBinaryBare(sig.Signature, &multiSig)

var b strings.Builder
b.WriteString("\n MultiSig Signatures:\n")
switch data := sig.Data.(type) {
sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved
case *signing.SingleSignatureData:
sigBytes, err := signModeHandler.GetSignBytes(data.SignMode, signingData, tx)
if err != nil {
sigSanity = "ERROR: can't get sign bytes"
success = false
}

for i := 0; i < multiSig.BitArray.Count(); i++ {
if multiSig.BitArray.GetIndex(i) {
addr := sdk.AccAddress(multiPK.PubKeys[i].Address().Bytes())
b.WriteString(fmt.Sprintf(" %d: %s (weight: %d)\n", i, addr, 1))
if ok := pubKey.VerifyBytes(sigBytes, data.Signature); !ok {
sigSanity = "ERROR: signature invalid"
success = false
}
case *signing.MultiSignatureData:
multiPK, ok := pubKey.(multisig.PubKey)
if ok {
err = multiPK.VerifyMultisignature(func(mode signing.SignMode) ([]byte, error) {
return signModeHandler.GetSignBytes(mode, signingData, tx)
}, data)

if err != nil {
sigSanity = fmt.Sprintf("ERROR: signature invalid: %v", err)
success = false
}

var b strings.Builder
b.WriteString("\n MultiSig Signatures:\n")

pks := multiPK.GetPubKeys()
for i := 0; i < data.BitArray.Count(); i++ {
if data.BitArray.GetIndex(i) {
addr := sdk.AccAddress(pks[i].Address().Bytes())
b.WriteString(fmt.Sprintf(" %d: %s (weight: %d)\n", i, addr, 1))
}
}

multiSigHeader = fmt.Sprintf(" [multisig threshold: %d/%d]", multiPK.GetThreshold(), len(pks))
multiSigMsg = b.String()
} else {
sigSanity = "ERROR: expected multisig pub key"
success = false
}
default:
sigSanity = "ERROR: unexpected ModeInfo"
success = false
}

multiSigHeader = fmt.Sprintf(" [multisig threshold: %d/%d]", multiPK.K, len(multiPK.PubKeys))
multiSigMsg = b.String()
}

cmd.Printf(" %d: %s\t\t\t[%s]%s%s\n", i, sigAddr.String(), sigSanity, multiSigHeader, multiSigMsg)
Expand All @@ -133,6 +165,20 @@ func printAndValidateSigs(
return success
}

func readTxAndInitContexts(clientCtx client.Context, cmd *cobra.Command, filename string) (client.Context, tx.Factory, sdk.Tx, error) {
stdTx, err := authclient.ReadTxFromFile(clientCtx, filename)
if err != nil {
return clientCtx, tx.Factory{}, nil, err
}

inBuf := bufio.NewReader(cmd.InOrStdin())
clientCtx = clientCtx.InitWithInput(inBuf)
txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())

return clientCtx, txFactory, stdTx, nil
}

// deprecated
func readStdTxAndInitContexts(clientCtx client.Context, cmd *cobra.Command, filename string) (
client.Context, types.TxBuilder, sdk.Tx, error,
) {
Expand Down