cosmos-sdk/x/auth/client/txbuilder/txbuilder.go

204 lines
5.7 KiB
Go
Raw Normal View History

2018-08-06 11:11:30 -07:00
package context
import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/pkg/errors"
"github.com/spf13/viper"
)
2018-09-07 06:36:21 -07:00
// TxBuilder implements a transaction context created in SDK modules.
type TxBuilder struct {
TxEncoder sdk.TxEncoder
AccountNumber uint64
Sequence uint64
Gas uint64
GasAdjustment float64
SimulateGas bool
2018-08-06 11:11:30 -07:00
ChainID string
Memo string
Fee string
}
2018-09-07 06:36:21 -07:00
// NewTxBuilderFromCLI returns a new initialized TxBuilder with parameters from
2018-08-06 11:11:30 -07:00
// the command line using Viper.
2018-09-07 06:36:21 -07:00
func NewTxBuilderFromCLI() TxBuilder {
2018-08-06 11:11:30 -07:00
// if chain ID is not specified manually, read default chain ID
chainID := viper.GetString(client.FlagChainID)
2018-09-07 06:36:21 -07:00
return TxBuilder{
2018-08-06 11:11:30 -07:00
ChainID: chainID,
AccountNumber: uint64(viper.GetInt64(client.FlagAccountNumber)),
Gas: client.GasFlagVar.Gas,
GasAdjustment: viper.GetFloat64(client.FlagGasAdjustment),
Sequence: uint64(viper.GetInt64(client.FlagSequence)),
SimulateGas: client.GasFlagVar.Simulate,
2018-08-06 11:11:30 -07:00
Fee: viper.GetString(client.FlagFee),
Memo: viper.GetString(client.FlagMemo),
}
}
// WithCodec returns a copy of the context with an updated codec.
func (bldr TxBuilder) WithTxEncoder(txEncoder sdk.TxEncoder) TxBuilder {
bldr.TxEncoder = txEncoder
2018-09-07 10:34:44 -07:00
return bldr
2018-08-06 11:11:30 -07:00
}
// WithChainID returns a copy of the context with an updated chainID.
2018-09-07 10:34:44 -07:00
func (bldr TxBuilder) WithChainID(chainID string) TxBuilder {
bldr.ChainID = chainID
return bldr
2018-08-06 11:11:30 -07:00
}
// WithGas returns a copy of the context with an updated gas.
func (bldr TxBuilder) WithGas(gas uint64) TxBuilder {
2018-09-07 10:34:44 -07:00
bldr.Gas = gas
return bldr
2018-08-06 11:11:30 -07:00
}
// WithFee returns a copy of the context with an updated fee.
2018-09-07 10:34:44 -07:00
func (bldr TxBuilder) WithFee(fee string) TxBuilder {
bldr.Fee = fee
return bldr
2018-08-06 11:11:30 -07:00
}
// WithSequence returns a copy of the context with an updated sequence number.
func (bldr TxBuilder) WithSequence(sequence uint64) TxBuilder {
2018-09-07 10:34:44 -07:00
bldr.Sequence = sequence
return bldr
2018-08-06 11:11:30 -07:00
}
// WithMemo returns a copy of the context with an updated memo.
2018-09-07 10:34:44 -07:00
func (bldr TxBuilder) WithMemo(memo string) TxBuilder {
bldr.Memo = memo
return bldr
2018-08-06 11:11:30 -07:00
}
// WithAccountNumber returns a copy of the context with an account number.
func (bldr TxBuilder) WithAccountNumber(accnum uint64) TxBuilder {
2018-09-07 10:34:44 -07:00
bldr.AccountNumber = accnum
return bldr
2018-08-06 11:11:30 -07:00
}
2018-09-07 06:36:21 -07:00
// Build builds a single message to be signed from a TxBuilder given a set of
2018-08-06 11:11:30 -07:00
// messages. It returns an error if a fee is supplied but cannot be parsed.
func (bldr TxBuilder) Build(msgs []sdk.Msg) (StdSignMsg, error) {
2018-09-07 10:34:44 -07:00
chainID := bldr.ChainID
2018-08-06 11:11:30 -07:00
if chainID == "" {
return StdSignMsg{}, errors.Errorf("chain ID required but not specified")
2018-08-06 11:11:30 -07:00
}
fee := sdk.Coin{}
2018-09-07 10:34:44 -07:00
if bldr.Fee != "" {
parsedFee, err := sdk.ParseCoin(bldr.Fee)
2018-08-06 11:11:30 -07:00
if err != nil {
return StdSignMsg{}, err
2018-08-06 11:11:30 -07:00
}
fee = parsedFee
}
return StdSignMsg{
2018-09-07 10:34:44 -07:00
ChainID: bldr.ChainID,
AccountNumber: bldr.AccountNumber,
Sequence: bldr.Sequence,
Memo: bldr.Memo,
2018-08-06 11:11:30 -07:00
Msgs: msgs,
2018-09-07 10:34:44 -07:00
Fee: auth.NewStdFee(bldr.Gas, fee),
2018-08-06 11:11:30 -07:00
}, nil
}
// Sign signs a transaction given a name, passphrase, and a single message to
// signed. An error is returned if signing fails.
func (bldr TxBuilder) Sign(name, passphrase string, msg StdSignMsg) ([]byte, error) {
sig, err := MakeSignature(name, passphrase, msg)
2018-08-06 11:11:30 -07:00
if err != nil {
return nil, err
}
return bldr.TxEncoder(auth.NewStdTx(msg.Msgs, msg.Fee, []auth.StdSignature{sig}, msg.Memo))
2018-08-06 11:11:30 -07:00
}
// BuildAndSign builds a single message to be signed, and signs a transaction
// with the built message given a name, passphrase, and a set of
// messages.
2018-09-07 10:34:44 -07:00
func (bldr TxBuilder) BuildAndSign(name, passphrase string, msgs []sdk.Msg) ([]byte, error) {
msg, err := bldr.Build(msgs)
2018-08-06 11:11:30 -07:00
if err != nil {
return nil, err
}
2018-09-07 10:34:44 -07:00
return bldr.Sign(name, passphrase, msg)
2018-08-06 11:11:30 -07:00
}
2018-09-07 06:36:21 -07:00
// BuildWithPubKey builds a single message to be signed from a TxBuilder given a set of
// messages and attach the public key associated to the given name.
// It returns an error if a fee is supplied but cannot be parsed or the key cannot be
// retrieved.
2018-09-07 10:34:44 -07:00
func (bldr TxBuilder) BuildWithPubKey(name string, msgs []sdk.Msg) ([]byte, error) {
msg, err := bldr.Build(msgs)
if err != nil {
return nil, err
}
keybase, err := keys.GetKeyBase()
if err != nil {
return nil, err
}
info, err := keybase.Get(name)
if err != nil {
return nil, err
}
sigs := []auth.StdSignature{{
PubKey: info.GetPubKey(),
}}
return bldr.TxEncoder(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo))
}
// SignStdTx appends a signature to a StdTx and returns a copy of a it. If append
// is false, it replaces the signatures already attached with the new signature.
func (bldr TxBuilder) SignStdTx(name, passphrase string, stdTx auth.StdTx, appendSig bool) (signedStdTx auth.StdTx, err error) {
stdSignature, err := MakeSignature(name, passphrase, StdSignMsg{
ChainID: bldr.ChainID,
AccountNumber: bldr.AccountNumber,
Sequence: bldr.Sequence,
Fee: stdTx.Fee,
Msgs: stdTx.GetMsgs(),
Memo: stdTx.GetMemo(),
})
if err != nil {
return
}
sigs := stdTx.GetSignatures()
if len(sigs) == 0 || !appendSig {
sigs = []auth.StdSignature{stdSignature}
} else {
sigs = append(sigs, stdSignature)
}
signedStdTx = auth.NewStdTx(stdTx.GetMsgs(), stdTx.Fee, sigs, stdTx.GetMemo())
return
}
// MakeSignature builds a StdSignature given key name, passphrase, and a StdSignMsg.
func MakeSignature(name, passphrase string, msg StdSignMsg) (sig auth.StdSignature, err error) {
keybase, err := keys.GetKeyBase()
if err != nil {
return
}
sigBytes, pubkey, err := keybase.Sign(name, passphrase, msg.Bytes())
if err != nil {
return
}
return auth.StdSignature{
PubKey: pubkey,
Signature: sigBytes,
}, nil
}