2020-07-06 10:03:45 -07:00
|
|
|
package tx
|
|
|
|
|
|
|
|
import (
|
2020-07-25 01:10:04 -07:00
|
|
|
"github.com/gogo/protobuf/proto"
|
|
|
|
|
2020-07-06 10:03:45 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
2020-11-09 08:01:43 -08:00
|
|
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
2020-07-06 10:03:45 -07:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2020-07-29 08:52:22 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/types/tx"
|
|
|
|
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
2020-08-18 06:44:56 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/auth/ante"
|
2020-07-29 08:52:22 -07:00
|
|
|
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
2020-07-06 10:03:45 -07:00
|
|
|
)
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
// wrapper is a wrapper around the tx.Tx proto.Message which retain the raw
|
|
|
|
// body and auth_info bytes.
|
|
|
|
type wrapper struct {
|
2020-07-06 10:03:45 -07:00
|
|
|
tx *tx.Tx
|
|
|
|
|
|
|
|
// bodyBz represents the protobuf encoding of TxBody. This should be encoding
|
|
|
|
// from the client using TxRaw if the tx was decoded from the wire
|
|
|
|
bodyBz []byte
|
|
|
|
|
|
|
|
// authInfoBz represents the protobuf encoding of TxBody. This should be encoding
|
|
|
|
// from the client using TxRaw if the tx was decoded from the wire
|
|
|
|
authInfoBz []byte
|
|
|
|
|
2020-08-03 12:47:25 -07:00
|
|
|
txBodyHasUnknownNonCriticals bool
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
2020-08-24 07:41:08 -07:00
|
|
|
_ authsigning.Tx = &wrapper{}
|
|
|
|
_ client.TxBuilder = &wrapper{}
|
|
|
|
_ ante.HasExtensionOptionsTx = &wrapper{}
|
|
|
|
_ ExtensionOptionsTxBuilder = &wrapper{}
|
2020-09-10 11:26:47 -07:00
|
|
|
_ codectypes.IntoAny = &wrapper{}
|
2020-07-06 10:03:45 -07:00
|
|
|
)
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
// ExtensionOptionsTxBuilder defines a TxBuilder that can also set extensions.
|
2020-08-18 06:44:56 -07:00
|
|
|
type ExtensionOptionsTxBuilder interface {
|
|
|
|
client.TxBuilder
|
|
|
|
|
|
|
|
SetExtensionOptions(...*codectypes.Any)
|
|
|
|
SetNonCriticalExtensionOptions(...*codectypes.Any)
|
|
|
|
}
|
|
|
|
|
2020-09-21 09:48:28 -07:00
|
|
|
func newBuilder() *wrapper {
|
2020-08-24 07:41:08 -07:00
|
|
|
return &wrapper{
|
2020-07-06 10:03:45 -07:00
|
|
|
tx: &tx.Tx{
|
|
|
|
Body: &tx.TxBody{},
|
|
|
|
AuthInfo: &tx.AuthInfo{
|
|
|
|
Fee: &tx.Fee{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) GetMsgs() []sdk.Msg {
|
2020-09-10 11:26:47 -07:00
|
|
|
return w.tx.GetMsgs()
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) ValidateBasic() error {
|
2020-09-10 11:26:47 -07:00
|
|
|
return w.tx.ValidateBasic()
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) getBodyBytes() []byte {
|
|
|
|
if len(w.bodyBz) == 0 {
|
2020-07-06 10:03:45 -07:00
|
|
|
// if bodyBz is empty, then marshal the body. bodyBz will generally
|
|
|
|
// be set to nil whenever SetBody is called so the result of calling
|
|
|
|
// this method should always return the correct bytes. Note that after
|
|
|
|
// decoding bodyBz is derived from TxRaw so that it matches what was
|
|
|
|
// transmitted over the wire
|
2020-07-25 01:10:04 -07:00
|
|
|
var err error
|
2020-08-24 07:41:08 -07:00
|
|
|
w.bodyBz, err = proto.Marshal(w.tx.Body)
|
2020-07-25 01:10:04 -07:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
2020-08-24 07:41:08 -07:00
|
|
|
return w.bodyBz
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) getAuthInfoBytes() []byte {
|
|
|
|
if len(w.authInfoBz) == 0 {
|
2020-07-06 10:03:45 -07:00
|
|
|
// if authInfoBz is empty, then marshal the body. authInfoBz will generally
|
|
|
|
// be set to nil whenever SetAuthInfo is called so the result of calling
|
|
|
|
// this method should always return the correct bytes. Note that after
|
|
|
|
// decoding authInfoBz is derived from TxRaw so that it matches what was
|
|
|
|
// transmitted over the wire
|
2020-07-25 01:10:04 -07:00
|
|
|
var err error
|
2020-08-24 07:41:08 -07:00
|
|
|
w.authInfoBz, err = proto.Marshal(w.tx.AuthInfo)
|
2020-07-25 01:10:04 -07:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
2020-08-24 07:41:08 -07:00
|
|
|
return w.authInfoBz
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) GetSigners() []sdk.AccAddress {
|
2020-09-10 11:26:47 -07:00
|
|
|
return w.tx.GetSigners()
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-11-09 08:01:43 -08:00
|
|
|
func (w *wrapper) GetPubKeys() []cryptotypes.PubKey {
|
2020-09-21 09:48:28 -07:00
|
|
|
signerInfos := w.tx.AuthInfo.SignerInfos
|
2020-11-09 08:01:43 -08:00
|
|
|
pks := make([]cryptotypes.PubKey, len(signerInfos))
|
2020-07-06 10:03:45 -07:00
|
|
|
|
2020-09-21 09:48:28 -07:00
|
|
|
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
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-11-09 08:01:43 -08:00
|
|
|
pk, ok := si.PublicKey.GetCachedValue().(cryptotypes.PubKey)
|
2020-09-21 09:48:28 -07:00
|
|
|
if ok {
|
|
|
|
pks[i] = pk
|
|
|
|
}
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-09-21 09:48:28 -07:00
|
|
|
return pks
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) GetGas() uint64 {
|
|
|
|
return w.tx.AuthInfo.Fee.GasLimit
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) GetFee() sdk.Coins {
|
|
|
|
return w.tx.AuthInfo.Fee.Amount
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) FeePayer() sdk.AccAddress {
|
2020-09-30 02:03:44 -07:00
|
|
|
feePayer := w.tx.AuthInfo.Fee.Payer
|
|
|
|
if feePayer != "" {
|
|
|
|
payerAddr, err := sdk.AccAddressFromBech32(feePayer)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return payerAddr
|
|
|
|
}
|
|
|
|
// use first signer as default if no payer specified
|
2020-08-24 07:41:08 -07:00
|
|
|
return w.GetSigners()[0]
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-10-05 14:56:09 -07:00
|
|
|
func (w *wrapper) FeeGranter() sdk.AccAddress {
|
|
|
|
feePayer := w.tx.AuthInfo.Fee.Granter
|
|
|
|
if feePayer != "" {
|
|
|
|
granterAddr, err := sdk.AccAddressFromBech32(feePayer)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return granterAddr
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) GetMemo() string {
|
|
|
|
return w.tx.Body.Memo
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) GetSignatures() [][]byte {
|
|
|
|
return w.tx.Signatures
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-07 16:32:22 -07:00
|
|
|
// GetTimeoutHeight returns the transaction's timeout height (if set).
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) GetTimeoutHeight() uint64 {
|
|
|
|
return w.tx.Body.TimeoutHeight
|
2020-08-07 16:32:22 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) GetSignaturesV2() ([]signing.SignatureV2, error) {
|
|
|
|
signerInfos := w.tx.AuthInfo.SignerInfos
|
|
|
|
sigs := w.tx.Signatures
|
|
|
|
pubKeys := w.GetPubKeys()
|
2020-07-06 10:03:45 -07:00
|
|
|
n := len(signerInfos)
|
|
|
|
res := make([]signing.SignatureV2, n)
|
|
|
|
|
|
|
|
for i, si := range signerInfos {
|
2020-09-02 13:41:13 -07:00
|
|
|
// handle nil signatures (in case of simulation)
|
|
|
|
if si.ModeInfo == nil {
|
|
|
|
res[i] = signing.SignatureV2{
|
|
|
|
PubKey: pubKeys[i],
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
var err error
|
|
|
|
sigData, err := ModeInfoAndSigToSignatureData(si.ModeInfo, sigs[i])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
res[i] = signing.SignatureV2{
|
|
|
|
PubKey: pubKeys[i],
|
|
|
|
Data: sigData,
|
|
|
|
Sequence: si.GetSequence(),
|
|
|
|
}
|
|
|
|
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res, nil
|
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) SetMsgs(msgs ...sdk.Msg) error {
|
2020-07-06 10:03:45 -07:00
|
|
|
anys := make([]*codectypes.Any, len(msgs))
|
|
|
|
|
|
|
|
for i, msg := range msgs {
|
|
|
|
var err error
|
2020-10-15 06:07:59 -07:00
|
|
|
switch msg := msg.(type) {
|
|
|
|
case sdk.ServiceMsg:
|
|
|
|
{
|
|
|
|
bz, err := proto.Marshal(msg.Request)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
anys[i] = &codectypes.Any{
|
|
|
|
TypeUrl: msg.MethodName,
|
|
|
|
Value: bz,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
anys[i], err = codectypes.NewAnyWithValue(msg)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
2020-10-15 06:07:59 -07:00
|
|
|
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
w.tx.Body.Messages = anys
|
2020-07-06 10:03:45 -07:00
|
|
|
|
|
|
|
// set bodyBz to nil because the cached bodyBz no longer matches tx.Body
|
2020-08-24 07:41:08 -07:00
|
|
|
w.bodyBz = nil
|
2020-07-06 10:03:45 -07:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-07 16:32:22 -07:00
|
|
|
// SetTimeoutHeight sets the transaction's height timeout.
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) SetTimeoutHeight(height uint64) {
|
|
|
|
w.tx.Body.TimeoutHeight = height
|
2020-08-07 16:32:22 -07:00
|
|
|
|
|
|
|
// set bodyBz to nil because the cached bodyBz no longer matches tx.Body
|
2020-08-24 07:41:08 -07:00
|
|
|
w.bodyBz = nil
|
2020-08-07 16:32:22 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) SetMemo(memo string) {
|
|
|
|
w.tx.Body.Memo = memo
|
2020-07-06 10:03:45 -07:00
|
|
|
|
|
|
|
// set bodyBz to nil because the cached bodyBz no longer matches tx.Body
|
2020-08-24 07:41:08 -07:00
|
|
|
w.bodyBz = nil
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) SetGasLimit(limit uint64) {
|
|
|
|
if w.tx.AuthInfo.Fee == nil {
|
|
|
|
w.tx.AuthInfo.Fee = &tx.Fee{}
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
w.tx.AuthInfo.Fee.GasLimit = limit
|
2020-07-06 10:03:45 -07:00
|
|
|
|
|
|
|
// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
|
2020-08-24 07:41:08 -07:00
|
|
|
w.authInfoBz = nil
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) SetFeeAmount(coins sdk.Coins) {
|
|
|
|
if w.tx.AuthInfo.Fee == nil {
|
|
|
|
w.tx.AuthInfo.Fee = &tx.Fee{}
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
w.tx.AuthInfo.Fee.Amount = coins
|
2020-07-06 10:03:45 -07:00
|
|
|
|
|
|
|
// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
|
2020-08-24 07:41:08 -07:00
|
|
|
w.authInfoBz = nil
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-09-30 02:03:44 -07:00
|
|
|
func (w *wrapper) SetFeePayer(feePayer sdk.AccAddress) {
|
|
|
|
if w.tx.AuthInfo.Fee == nil {
|
|
|
|
w.tx.AuthInfo.Fee = &tx.Fee{}
|
|
|
|
}
|
|
|
|
|
|
|
|
w.tx.AuthInfo.Fee.Payer = feePayer.String()
|
|
|
|
|
|
|
|
// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
|
|
|
|
w.authInfoBz = nil
|
|
|
|
}
|
|
|
|
|
2020-10-05 14:56:09 -07:00
|
|
|
func (w *wrapper) SetFeeGranter(feeGranter sdk.AccAddress) {
|
|
|
|
if w.tx.AuthInfo.Fee == nil {
|
|
|
|
w.tx.AuthInfo.Fee = &tx.Fee{}
|
|
|
|
}
|
|
|
|
|
|
|
|
w.tx.AuthInfo.Fee.Granter = feeGranter.String()
|
|
|
|
|
|
|
|
// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
|
|
|
|
w.authInfoBz = nil
|
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) SetSignatures(signatures ...signing.SignatureV2) error {
|
2020-07-06 10:03:45 -07:00
|
|
|
n := len(signatures)
|
|
|
|
signerInfos := make([]*tx.SignerInfo, n)
|
|
|
|
rawSigs := make([][]byte, n)
|
|
|
|
|
|
|
|
for i, sig := range signatures {
|
|
|
|
var modeInfo *tx.ModeInfo
|
|
|
|
modeInfo, rawSigs[i] = SignatureDataToModeInfoAndSig(sig.Data)
|
2020-09-21 09:48:28 -07:00
|
|
|
any, err := PubKeyToAny(sig.PubKey)
|
2020-07-06 10:03:45 -07:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
signerInfos[i] = &tx.SignerInfo{
|
2020-09-21 09:48:28 -07:00
|
|
|
PublicKey: any,
|
2020-07-06 10:03:45 -07:00
|
|
|
ModeInfo: modeInfo,
|
2020-08-21 07:20:47 -07:00
|
|
|
Sequence: sig.Sequence,
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
w.setSignerInfos(signerInfos)
|
|
|
|
w.setSignatures(rawSigs)
|
2020-07-06 10:03:45 -07:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) setSignerInfos(infos []*tx.SignerInfo) {
|
|
|
|
w.tx.AuthInfo.SignerInfos = infos
|
2020-07-06 10:03:45 -07:00
|
|
|
// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
|
2020-08-24 07:41:08 -07:00
|
|
|
w.authInfoBz = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *wrapper) setSignatures(sigs [][]byte) {
|
|
|
|
w.tx.Signatures = sigs
|
|
|
|
}
|
2020-07-29 08:52:22 -07:00
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) GetTx() authsigning.Tx {
|
|
|
|
return w
|
2020-07-29 08:52:22 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
// GetProtoTx returns the tx as a proto.Message.
|
2020-09-10 11:26:47 -07:00
|
|
|
func (w *wrapper) AsAny() *codectypes.Any {
|
|
|
|
// We're sure here that w.tx is a proto.Message, so this will call
|
|
|
|
// codectypes.NewAnyWithValue under the hood.
|
|
|
|
return codectypes.UnsafePackAny(w.tx)
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
// WrapTx creates a TxBuilder wrapper around a tx.Tx proto message.
|
2020-09-21 09:48:28 -07:00
|
|
|
func WrapTx(protoTx *tx.Tx) client.TxBuilder {
|
2020-08-24 07:41:08 -07:00
|
|
|
return &wrapper{
|
2020-09-21 09:48:28 -07:00
|
|
|
tx: protoTx,
|
2020-08-24 07:41:08 -07:00
|
|
|
}
|
2020-07-06 10:03:45 -07:00
|
|
|
}
|
2020-08-18 06:44:56 -07:00
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) GetExtensionOptions() []*codectypes.Any {
|
|
|
|
return w.tx.Body.ExtensionOptions
|
2020-08-18 06:44:56 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) GetNonCriticalExtensionOptions() []*codectypes.Any {
|
|
|
|
return w.tx.Body.NonCriticalExtensionOptions
|
2020-08-18 06:44:56 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) SetExtensionOptions(extOpts ...*codectypes.Any) {
|
|
|
|
w.tx.Body.ExtensionOptions = extOpts
|
|
|
|
w.bodyBz = nil
|
2020-08-18 06:44:56 -07:00
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
func (w *wrapper) SetNonCriticalExtensionOptions(extOpts ...*codectypes.Any) {
|
|
|
|
w.tx.Body.NonCriticalExtensionOptions = extOpts
|
|
|
|
w.bodyBz = nil
|
2020-08-18 06:44:56 -07:00
|
|
|
}
|
2020-09-21 09:48:28 -07:00
|
|
|
|
2020-11-09 08:01:43 -08:00
|
|
|
// PubKeyToAny converts a cryptotypes.PubKey to a proto Any.
|
|
|
|
func PubKeyToAny(key cryptotypes.PubKey) (*codectypes.Any, error) {
|
|
|
|
return codectypes.NewAnyWithValue(key)
|
2020-09-21 09:48:28 -07:00
|
|
|
}
|