cosmos-sdk/client/v2/tx/wrapper.go
Julián Toledano ed46a4c93a
refactor(client/v2): offchain uses client/v2/factory (#22344)
Co-authored-by: Julien Robert <julien@rbrt.fr>
2024-11-05 15:49:09 +00:00

127 lines
3.1 KiB
Go

package tx
import (
"fmt"
"reflect"
"strings"
"github.com/cosmos/gogoproto/proto"
"google.golang.org/protobuf/types/known/anypb"
"cosmossdk.io/core/transaction"
"cosmossdk.io/x/tx/decode"
"cosmossdk.io/x/tx/signing"
"github.com/cosmos/cosmos-sdk/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
)
var (
_ transaction.Tx = wrappedTx{}
_ Tx = wrappedTx{}
)
// wrappedTx wraps a transaction and provides a codec for binary encoding/decoding.
type wrappedTx struct {
*decode.DecodedTx
cdc codec.BinaryCodec
}
func newWrapperTx(cdc codec.BinaryCodec, decodedTx *decode.DecodedTx) *wrappedTx {
return &wrappedTx{
DecodedTx: decodedTx,
cdc: cdc,
}
}
// GetSigners fetches the addresses of the signers of the transaction.
func (w wrappedTx) GetSigners() ([][]byte, error) {
return w.Signers, nil
}
// GetPubKeys retrieves the public keys of the signers from the transaction's SignerInfos.
func (w wrappedTx) GetPubKeys() ([]cryptotypes.PubKey, error) {
signerInfos := w.Tx.AuthInfo.SignerInfos
pks := make([]cryptotypes.PubKey, len(signerInfos))
for i, si := range signerInfos {
// NOTE: it is okay to leave this nil if there is no PubKey in the SignerInfo.
// PubKey's can be left unset in SignerInfo.
if si.PublicKey == nil {
continue
}
maybePk, err := w.decodeAny(si.PublicKey)
if err != nil {
return nil, err
}
pk, ok := maybePk.(cryptotypes.PubKey)
if !ok {
return nil, fmt.Errorf("invalid public key type: %T", maybePk)
}
pks[i] = pk
}
return pks, nil
}
// GetSignatures fetches the signatures attached to the transaction.
func (w wrappedTx) GetSignatures() ([]Signature, error) {
signerInfos := w.Tx.AuthInfo.SignerInfos
sigs := w.Tx.Signatures
pubKeys, err := w.GetPubKeys()
if err != nil {
return nil, err
}
signatures := make([]Signature, len(sigs))
for i, si := range signerInfos {
if si.ModeInfo == nil || si.ModeInfo.Sum == nil {
signatures[i] = Signature{
PubKey: pubKeys[i],
}
} else {
sigData, err := modeInfoAndSigToSignatureData(si.ModeInfo, sigs[i])
if err != nil {
return nil, err
}
signatures[i] = Signature{
PubKey: pubKeys[i],
Data: sigData,
Sequence: si.GetSequence(),
}
}
}
return signatures, nil
}
func (w wrappedTx) GetSigningTxData() (signing.TxData, error) {
return signing.TxData{
Body: w.Tx.Body,
AuthInfo: w.Tx.AuthInfo,
BodyBytes: w.TxRaw.BodyBytes,
AuthInfoBytes: w.TxRaw.AuthInfoBytes,
BodyHasUnknownNonCriticals: w.TxBodyHasUnknownNonCriticals,
}, nil
}
// decodeAny decodes a protobuf Any message into a concrete proto.Message.
func (w wrappedTx) decodeAny(anyPb *anypb.Any) (proto.Message, error) {
name := anyPb.GetTypeUrl()
if i := strings.LastIndexByte(name, '/'); i >= 0 {
name = name[i+len("/"):]
}
typ := proto.MessageType(name)
if typ == nil {
return nil, fmt.Errorf("unknown type: %s", name)
}
v1 := reflect.New(typ.Elem()).Interface().(proto.Message)
err := w.cdc.Unmarshal(anyPb.GetValue(), v1)
if err != nil {
return nil, err
}
return v1, nil
}