package auth import ( "encoding/json" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/tendermint/tendermint/crypto" ) var _ sdk.Tx = (*StdTx)(nil) // StdTx is a standard way to wrap a Msg with Fee and Signatures. // NOTE: the first signature is the fee payer (Signatures must not be nil). type StdTx struct { Msgs []sdk.Msg `json:"msg"` Fee StdFee `json:"fee"` Signatures []StdSignature `json:"signatures"` Memo string `json:"memo"` } func NewStdTx(msgs []sdk.Msg, fee StdFee, sigs []StdSignature, memo string) StdTx { return StdTx{ Msgs: msgs, Fee: fee, Signatures: sigs, Memo: memo, } } //nolint func (tx StdTx) GetMsgs() []sdk.Msg { return tx.Msgs } // GetSigners returns the addresses that must sign the transaction. // Addresses are returned in a determistic order. // They are accumulated from the GetSigners method for each Msg // in the order they appear in tx.GetMsgs(). // Duplicate addresses will be omitted. func (tx StdTx) GetSigners() []sdk.AccAddress { seen := map[string]bool{} var signers []sdk.AccAddress for _, msg := range tx.GetMsgs() { for _, addr := range msg.GetSigners() { if !seen[addr.String()] { signers = append(signers, addr) seen[addr.String()] = true } } } return signers } //nolint func (tx StdTx) GetMemo() string { return tx.Memo } // Signatures returns the signature of signers who signed the Msg. // GetSignatures returns the signature of signers who signed the Msg. // CONTRACT: Length returned is same as length of // pubkeys returned from MsgKeySigners, and the order // matches. // CONTRACT: If the signature is missing (ie the Msg is // invalid), then the corresponding signature is // .Empty(). func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures } //__________________________________________________________ // StdFee includes the amount of coins paid in fees and the maximum // gas to be used by the transaction. The ratio yields an effective "gasprice", // which must be above some miminum to be accepted into the mempool. type StdFee struct { Amount sdk.Coins `json:"amount"` Gas int64 `json:"gas"` } func NewStdFee(gas int64, amount ...sdk.Coin) StdFee { return StdFee{ Amount: amount, Gas: gas, } } // fee bytes for signing later func (fee StdFee) Bytes() []byte { // normalize. XXX // this is a sign of something ugly // (in the lcd_test, client side its null, // server side its []) if len(fee.Amount) == 0 { fee.Amount = sdk.Coins{} } bz, err := msgCdc.MarshalJSON(fee) // TODO if err != nil { panic(err) } return bz } //__________________________________________________________ // StdSignDoc is replay-prevention structure. // It includes the result of msg.GetSignBytes(), // as well as the ChainID (prevent cross chain replay) // and the Sequence numbers for each signature (prevent // inchain replay and enforce tx ordering per account). type StdSignDoc struct { AccountNumber int64 `json:"account_number"` ChainID string `json:"chain_id"` Fee json.RawMessage `json:"fee"` Memo string `json:"memo"` Msgs []json.RawMessage `json:"msgs"` Sequence int64 `json:"sequence"` } // StdSignBytes returns the bytes to sign for a transaction. func StdSignBytes(chainID string, accnum int64, sequence int64, fee StdFee, msgs []sdk.Msg, memo string) []byte { var msgsBytes []json.RawMessage for _, msg := range msgs { msgsBytes = append(msgsBytes, json.RawMessage(msg.GetSignBytes())) } bz, err := msgCdc.MarshalJSON(StdSignDoc{ AccountNumber: accnum, ChainID: chainID, Fee: json.RawMessage(fee.Bytes()), Memo: memo, Msgs: msgsBytes, Sequence: sequence, }) if err != nil { panic(err) } return sdk.MustSortJSON(bz) } // Standard Signature type StdSignature struct { crypto.PubKey `json:"pub_key"` // optional Signature []byte `json:"signature"` AccountNumber int64 `json:"account_number"` Sequence int64 `json:"sequence"` } // logic for standard transaction decoding func DefaultTxDecoder(cdc *codec.Codec) sdk.TxDecoder { return func(txBytes []byte) (sdk.Tx, sdk.Error) { var tx = StdTx{} if len(txBytes) == 0 { return nil, sdk.ErrTxDecode("txBytes are empty") } // StdTx.Msg is an interface. The concrete types // are registered by MakeTxCodec err := cdc.UnmarshalBinary(txBytes, &tx) if err != nil { return nil, sdk.ErrTxDecode("").TraceSDK(err.Error()) } return tx, nil } }