cosmos-sdk/client/v2/offchain/verify.go
github-actions[bot] 06f5339d78
chore: fix spelling errors (#23270)
Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
Co-authored-by: Alex | Interchain Labs <alex@skip.money>
2025-01-09 20:52:55 +00:00

133 lines
3.2 KiB
Go

package offchain
import (
"bytes"
"context"
"errors"
"fmt"
"google.golang.org/protobuf/types/known/anypb"
clientcontext "cosmossdk.io/client/v2/context"
clitx "cosmossdk.io/client/v2/tx"
"cosmossdk.io/core/address"
txsigning "cosmossdk.io/x/tx/signing"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
)
// Verify verifies a digest after unmarshalling it.
func Verify(ctx clientcontext.Context, digest []byte, fileFormat string) error {
txConfig, err := clitx.NewTxConfig(clitx.ConfigOptions{
AddressCodec: ctx.AddressCodec,
Cdc: ctx.Cdc,
ValidatorAddressCodec: ctx.ValidatorAddressCodec,
EnabledSignModes: enabledSignModes,
})
if err != nil {
return err
}
dTx, err := unmarshal(fileFormat, digest, txConfig)
if err != nil {
return err
}
return verify(ctx.AddressCodec, txConfig, dTx)
}
// verify verifies given Tx.
func verify(addressCodec address.Codec, txConfig clitx.TxConfig, dTx clitx.Tx) error {
signModeHandler := txConfig.SignModeHandler()
signers, err := dTx.GetSigners()
if err != nil {
return err
}
sigs, err := dTx.GetSignatures()
if err != nil {
return err
}
if len(sigs) != len(signers) {
return errors.New("mismatch between the number of signatures and signers")
}
for i, sig := range sigs {
pubKey := sig.PubKey
if !bytes.Equal(pubKey.Address(), signers[i]) {
return errors.New("signature does not match its respective signer")
}
addr, err := addressCodec.BytesToString(pubKey.Address())
if err != nil {
return err
}
anyPk, err := codectypes.NewAnyWithValue(pubKey)
if err != nil {
return err
}
txSignerData := txsigning.SignerData{
ChainID: ExpectedChainID,
AccountNumber: ExpectedAccountNumber,
Sequence: ExpectedSequence,
Address: addr,
PubKey: &anypb.Any{
TypeUrl: anyPk.TypeUrl,
Value: anyPk.Value,
},
}
txData, err := dTx.GetSigningTxData()
if err != nil {
return err
}
err = verifySignature(context.Background(), pubKey, txSignerData, sig.Data, signModeHandler, txData)
if err != nil {
return err
}
}
return nil
}
// unmarshal unmarshals a digest to a Tx using protobuf protojson.
func unmarshal(format string, bz []byte, config clitx.TxConfig) (clitx.Tx, error) {
switch format {
case "json":
return config.TxJSONDecoder()(bz)
case "text":
return config.TxTextDecoder()(bz)
default:
return nil, fmt.Errorf("unsupported format: %s", format)
}
}
// verifySignature verifies a transaction signature contained in SignatureData abstracting over different signing modes.
func verifySignature(
ctx context.Context,
pubKey cryptotypes.PubKey,
signerData txsigning.SignerData,
signatureData clitx.SignatureData,
handler *txsigning.HandlerMap,
txData txsigning.TxData,
) error {
switch data := signatureData.(type) {
case *clitx.SingleSignatureData:
signBytes, err := handler.GetSignBytes(ctx, data.SignMode, signerData, txData)
if err != nil {
return err
}
if !pubKey.VerifySignature(signBytes, data.Signature) {
return errors.New("unable to verify single signer signature")
}
return nil
default:
return fmt.Errorf("unexpected SignatureData %T", signatureData)
}
}