diff --git a/CHANGELOG.md b/CHANGELOG.md index 167aa339ef..21fdc8bcf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -102,6 +102,8 @@ ALL legacy code should use `*codec.Codec` instead of `*amino.Codec` directly * (x/gov) [\#6147](https://github.com/cosmos/cosmos-sdk/pull/6147) The `Content` field on `Proposal` and `MsgSubmitProposal` is now `Any` in concordance with [ADR 019](docs/architecture/adr-019-protobuf-state-encoding.md) and `GetContent` should now be used to retrieve the actual proposal `Content`. Also the `NewMsgSubmitProposal` constructor now may return an `error` +* (modules) [\#5989](https://github.com/cosmos/cosmos-sdk/pull/5989) `AppModuleBasic.GetTxCmd` now takes a single `CLIContext` parameter. +* (x/auth) [\#5989](https://github.com/cosmos/cosmos-sdk/pull/5989) All `AccountRetriever` methods now take `NodeQuerier` as a parameter instead of as a struct member. ### Features diff --git a/Makefile b/Makefile index e060ea27c6..b7064e8d22 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ build-sim: go.sum build-sim mocks: $(MOCKS_DIR) - mockgen -source=x/auth/types/account_retriever.go -package mocks -destination tests/mocks/account_retriever.go + mockgen -source=client/context/account_retriever.go -package mocks -destination tests/mocks/account_retriever.go mockgen -package mocks -destination tests/mocks/tendermint_tm_db_DB.go github.com/tendermint/tm-db DB mockgen -source=types/module/module.go -package mocks -destination tests/mocks/types_module_module.go mockgen -source=types/invariant.go -package mocks -destination tests/mocks/types_invariant.go diff --git a/client/context/account_retriever.go b/client/context/account_retriever.go new file mode 100644 index 0000000000..595eadde91 --- /dev/null +++ b/client/context/account_retriever.go @@ -0,0 +1,21 @@ +package context + +import "github.com/cosmos/cosmos-sdk/types" + +// AccountRetriever defines the interfaces required by transactions to +// ensure an account exists and to be able to query for account fields necessary +// for signing. +type AccountRetriever interface { + EnsureExists(nodeQuerier NodeQuerier, addr types.AccAddress) error + GetAccountNumberSequence(nodeQuerier NodeQuerier, addr types.AccAddress) (accNum uint64, accSeq uint64, err error) +} + +// NodeQuerier is an interface that is satisfied by types that provide the QueryWithData method +type NodeQuerier interface { + // QueryWithData performs a query to a Tendermint node with the provided path + // and a data payload. It returns the result and height of the query upon success + // or an error if the query fails. + QueryWithData(path string, data []byte) ([]byte, int64, error) +} + +var _ NodeQuerier = CLIContext{} diff --git a/client/context/context.go b/client/context/context.go index 1e8b91deff..6ea912c843 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -1,17 +1,19 @@ package context import ( + "bufio" "fmt" "io" "os" "github.com/pkg/errors" "github.com/spf13/viper" + yaml "gopkg.in/yaml.v2" + "github.com/tendermint/tendermint/libs/cli" tmlite "github.com/tendermint/tendermint/lite" rpcclient "github.com/tendermint/tendermint/rpc/client" rpchttp "github.com/tendermint/tendermint/rpc/client/http" - yaml "gopkg.in/yaml.v2" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" @@ -22,28 +24,30 @@ import ( // CLIContext implements a typical CLI context created in SDK modules for // transaction handling and queries. type CLIContext struct { - FromAddress sdk.AccAddress - Client rpcclient.Client - ChainID string - Marshaler codec.Marshaler - Input io.Reader - Keyring keyring.Keyring - Output io.Writer - OutputFormat string - Height int64 - HomeDir string - NodeURI string - From string - BroadcastMode string - Verifier tmlite.Verifier - FromName string - TrustNode bool - UseLedger bool - Simulate bool - GenerateOnly bool - Offline bool - Indent bool - SkipConfirm bool + FromAddress sdk.AccAddress + Client rpcclient.Client + ChainID string + JSONMarshaler codec.JSONMarshaler + Input io.Reader + Keyring keyring.Keyring + Output io.Writer + OutputFormat string + Height int64 + HomeDir string + NodeURI string + From string + BroadcastMode string + Verifier tmlite.Verifier + FromName string + TrustNode bool + UseLedger bool + Simulate bool + GenerateOnly bool + Offline bool + Indent bool + SkipConfirm bool + TxGenerator TxGenerator + AccountRetriever AccountRetriever // TODO: Deprecated (remove). Codec *codec.Codec @@ -56,75 +60,8 @@ type CLIContext struct { // a CLIContext in tests or any non CLI-based environment, the verifier will not be created // and will be set as nil because FlagTrustNode must be set. func NewCLIContextWithInputAndFrom(input io.Reader, from string) CLIContext { - var nodeURI string - var rpc rpcclient.Client - - homedir := viper.GetString(flags.FlagHome) - genOnly := viper.GetBool(flags.FlagGenerateOnly) - backend := viper.GetString(flags.FlagKeyringBackend) - if len(backend) == 0 { - backend = keyring.BackendMemory - } - - keyring, err := newKeyringFromFlags(backend, homedir, input, genOnly) - if err != nil { - panic(fmt.Errorf("couldn't acquire keyring: %v", err)) - } - - fromAddress, fromName, err := GetFromFields(keyring, from, genOnly) - if err != nil { - fmt.Printf("failed to get from fields: %v\n", err) - os.Exit(1) - } - - offline := viper.GetBool(flags.FlagOffline) - if !offline { - nodeURI = viper.GetString(flags.FlagNode) - if nodeURI != "" { - rpc, err = rpchttp.New(nodeURI, "/websocket") - if err != nil { - fmt.Printf("failted to get client: %v\n", err) - os.Exit(1) - } - } - } - - trustNode := viper.GetBool(flags.FlagTrustNode) - ctx := CLIContext{ - Client: rpc, - ChainID: viper.GetString(flags.FlagChainID), - Input: input, - Output: os.Stdout, - NodeURI: nodeURI, - From: viper.GetString(flags.FlagFrom), - Keyring: keyring, - OutputFormat: viper.GetString(cli.OutputFlag), - Height: viper.GetInt64(flags.FlagHeight), - HomeDir: homedir, - TrustNode: trustNode, - UseLedger: viper.GetBool(flags.FlagUseLedger), - BroadcastMode: viper.GetString(flags.FlagBroadcastMode), - Simulate: viper.GetBool(flags.FlagDryRun), - GenerateOnly: genOnly, - Offline: offline, - FromAddress: fromAddress, - FromName: fromName, - Indent: viper.GetBool(flags.FlagIndentResponse), - SkipConfirm: viper.GetBool(flags.FlagSkipConfirmation), - } - - if offline { - return ctx - } - - // create a verifier for the specific chain ID and RPC client - verifier, err := CreateVerifier(ctx, DefaultVerifierCacheSize) - if err != nil && !trustNode { - fmt.Printf("failed to create verifier: %s\n", err) - os.Exit(1) - } - - return ctx.WithVerifier(verifier) + ctx := CLIContext{} + return ctx.InitWithInputAndFrom(input, from) } // NewCLIContextWithFrom returns a new initialized CLIContext with parameters from the @@ -147,6 +84,103 @@ func NewCLIContextWithInput(input io.Reader) CLIContext { return NewCLIContextWithInputAndFrom(input, viper.GetString(flags.FlagFrom)) } +// InitWithInputAndFrom returns a new CLIContext re-initialized from an existing +// CLIContext with a new io.Reader and from parameter +func (ctx CLIContext) InitWithInputAndFrom(input io.Reader, from string) CLIContext { + input = bufio.NewReader(input) + + var ( + nodeURI string + rpc rpcclient.Client + err error + ) + + offline := viper.GetBool(flags.FlagOffline) + if !offline { + nodeURI = viper.GetString(flags.FlagNode) + if nodeURI != "" { + rpc, err = rpchttp.New(nodeURI, "/websocket") + if err != nil { + fmt.Printf("failted to get client: %v\n", err) + os.Exit(1) + } + } + } + + trustNode := viper.GetBool(flags.FlagTrustNode) + + ctx.Client = rpc + ctx.ChainID = viper.GetString(flags.FlagChainID) + ctx.Input = input + ctx.Output = os.Stdout + ctx.NodeURI = nodeURI + ctx.From = viper.GetString(flags.FlagFrom) + ctx.OutputFormat = viper.GetString(cli.OutputFlag) + ctx.Height = viper.GetInt64(flags.FlagHeight) + ctx.TrustNode = trustNode + ctx.UseLedger = viper.GetBool(flags.FlagUseLedger) + ctx.BroadcastMode = viper.GetString(flags.FlagBroadcastMode) + ctx.Simulate = viper.GetBool(flags.FlagDryRun) + ctx.Offline = offline + ctx.Indent = viper.GetBool(flags.FlagIndentResponse) + ctx.SkipConfirm = viper.GetBool(flags.FlagSkipConfirmation) + + homedir := viper.GetString(flags.FlagHome) + genOnly := viper.GetBool(flags.FlagGenerateOnly) + backend := viper.GetString(flags.FlagKeyringBackend) + if len(backend) == 0 { + backend = keyring.BackendMemory + } + + kr, err := newKeyringFromFlags(backend, homedir, input, genOnly) + if err != nil { + panic(fmt.Errorf("couldn't acquire keyring: %v", err)) + } + + fromAddress, fromName, err := GetFromFields(kr, from, genOnly) + if err != nil { + fmt.Printf("failed to get from fields: %v\n", err) + os.Exit(1) + } + + ctx.HomeDir = homedir + + ctx.Keyring = kr + ctx.FromAddress = fromAddress + ctx.FromName = fromName + ctx.GenerateOnly = genOnly + + if offline { + return ctx + } + + // create a verifier for the specific chain ID and RPC client + verifier, err := CreateVerifier(ctx, DefaultVerifierCacheSize) + if err != nil && !trustNode { + fmt.Printf("failed to create verifier: %s\n", err) + os.Exit(1) + } + + ctx.Verifier = verifier + return ctx +} + +// InitWithFrom returns a new CLIContext re-initialized from an existing +// CLIContext with a new from parameter +func (ctx CLIContext) InitWithFrom(from string) CLIContext { + return ctx.InitWithInputAndFrom(os.Stdin, from) +} + +// Init returns a new CLIContext re-initialized from an existing +// CLIContext with parameters from the command line using Viper. +func (ctx CLIContext) Init() CLIContext { return ctx.InitWithFrom(viper.GetString(flags.FlagFrom)) } + +// InitWithInput returns a new CLIContext re-initialized from an existing +// CLIContext with a new io.Reader and from parameter +func (ctx CLIContext) InitWithInput(input io.Reader) CLIContext { + return ctx.InitWithInputAndFrom(input, viper.GetString(flags.FlagFrom)) +} + // WithKeyring returns a copy of the context with an updated keyring. func (ctx CLIContext) WithKeyring(k keyring.Keyring) CLIContext { ctx.Keyring = k @@ -159,9 +193,9 @@ func (ctx CLIContext) WithInput(r io.Reader) CLIContext { return ctx } -// WithMarshaler returns a copy of the CLIContext with an updated Marshaler. -func (ctx CLIContext) WithMarshaler(m codec.Marshaler) CLIContext { - ctx.Marshaler = m +// WithJSONMarshaler returns a copy of the CLIContext with an updated JSONMarshaler. +func (ctx CLIContext) WithJSONMarshaler(m codec.JSONMarshaler) CLIContext { + ctx.JSONMarshaler = m return ctx } @@ -265,9 +299,21 @@ func (ctx CLIContext) WithBroadcastMode(mode string) CLIContext { return ctx } +// WithTxGenerator returns the context with an updated TxGenerator +func (ctx CLIContext) WithTxGenerator(generator TxGenerator) CLIContext { + ctx.TxGenerator = generator + return ctx +} + +// WithAccountRetriever returns the context with an updated AccountRetriever +func (ctx CLIContext) WithAccountRetriever(retriever AccountRetriever) CLIContext { + ctx.AccountRetriever = retriever + return ctx +} + // Println outputs toPrint to the ctx.Output based on ctx.OutputFormat which is // either text or json. If text, toPrint will be YAML encoded. Otherwise, toPrint -// will be JSON encoded using ctx.Marshaler. An error is returned upon failure. +// will be JSON encoded using ctx.JSONMarshaler. An error is returned upon failure. func (ctx CLIContext) Println(toPrint interface{}) error { var ( out []byte @@ -279,11 +325,11 @@ func (ctx CLIContext) Println(toPrint interface{}) error { out, err = yaml.Marshal(&toPrint) case "json": - out, err = ctx.Marshaler.MarshalJSON(toPrint) + out, err = ctx.JSONMarshaler.MarshalJSON(toPrint) // To JSON indent, we re-encode the already encoded JSON given there is no // error. The re-encoded JSON uses the standard library as the initial encoded - // JSON should have the correct output produced by ctx.Marshaler. + // JSON should have the correct output produced by ctx.JSONMarshaler. if ctx.Indent && err == nil { out, err = codec.MarshalIndentFromJSON(out) } diff --git a/client/context/tx_generator.go b/client/context/tx_generator.go new file mode 100644 index 0000000000..ff023fcec0 --- /dev/null +++ b/client/context/tx_generator.go @@ -0,0 +1,51 @@ +package context + +import ( + "github.com/tendermint/tendermint/crypto" + + "github.com/cosmos/cosmos-sdk/types" +) + +type ( + // TxGenerator defines an interface a client can utilize to generate an + // application-defined concrete transaction type. The type returned must + // implement TxBuilder. + TxGenerator interface { + NewTx() TxBuilder + NewFee() ClientFee + NewSignature() ClientSignature + MarshalTx(tx types.Tx) ([]byte, error) + } + + ClientFee interface { + types.Fee + SetGas(uint64) + SetAmount(types.Coins) + } + + ClientSignature interface { + types.Signature + SetPubKey(crypto.PubKey) error + SetSignature([]byte) + } + + // TxBuilder defines an interface which an application-defined concrete transaction + // type must implement. Namely, it must be able to set messages, generate + // signatures, and provide canonical bytes to sign over. The transaction must + // also know how to encode itself. + TxBuilder interface { + GetTx() types.Tx + + SetMsgs(...types.Msg) error + GetSignatures() []types.Signature + SetSignatures(...ClientSignature) error + GetFee() types.Fee + SetFee(ClientFee) error + GetMemo() string + SetMemo(string) + + // CanonicalSignBytes returns the canonical sign bytes to sign over, given a + // chain ID, along with an account and sequence number. + CanonicalSignBytes(cid string, num, seq uint64) ([]byte, error) + } +) diff --git a/client/tx/factory.go b/client/tx/factory.go index e83590091e..dc1b2c6dfc 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -5,25 +5,18 @@ import ( "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" ) -// AccountRetriever defines the interfaces required for use by the Factory to -// ensure an account exists and to be able to query for account fields necessary -// for signing. -type AccountRetriever interface { - EnsureExists(addr sdk.AccAddress) error - GetAccountNumberSequence(addr sdk.AccAddress) (uint64, uint64, error) -} - // Factory defines a client transaction factory that facilitates generating and // signing an application-specific transaction. type Factory struct { keybase keyring.Keyring - txGenerator Generator - accountRetriever AccountRetriever + txGenerator context.TxGenerator + accountRetriever context.AccountRetriever accountNumber uint64 sequence uint64 gas uint64 @@ -63,29 +56,29 @@ func NewFactoryFromCLI(input io.Reader) Factory { return f } -func (f Factory) AccountNumber() uint64 { return f.accountNumber } -func (f Factory) Sequence() uint64 { return f.sequence } -func (f Factory) Gas() uint64 { return f.gas } -func (f Factory) GasAdjustment() float64 { return f.gasAdjustment } -func (f Factory) Keybase() keyring.Keyring { return f.keybase } -func (f Factory) ChainID() string { return f.chainID } -func (f Factory) Memo() string { return f.memo } -func (f Factory) Fees() sdk.Coins { return f.fees } -func (f Factory) GasPrices() sdk.DecCoins { return f.gasPrices } -func (f Factory) AccountRetriever() AccountRetriever { return f.accountRetriever } +func (f Factory) AccountNumber() uint64 { return f.accountNumber } +func (f Factory) Sequence() uint64 { return f.sequence } +func (f Factory) Gas() uint64 { return f.gas } +func (f Factory) GasAdjustment() float64 { return f.gasAdjustment } +func (f Factory) Keybase() keyring.Keyring { return f.keybase } +func (f Factory) ChainID() string { return f.chainID } +func (f Factory) Memo() string { return f.memo } +func (f Factory) Fees() sdk.Coins { return f.fees } +func (f Factory) GasPrices() sdk.DecCoins { return f.gasPrices } +func (f Factory) AccountRetriever() context.AccountRetriever { return f.accountRetriever } // SimulateAndExecute returns the option to simulate and then execute the transaction // using the gas from the simulation results func (f Factory) SimulateAndExecute() bool { return f.simulateAndExecute } -// WithTxGenerator returns a copy of the Factory with an updated Generator. -func (f Factory) WithTxGenerator(g Generator) Factory { +// WithTxGenerator returns a copy of the Factory with an updated TxGenerator. +func (f Factory) WithTxGenerator(g context.TxGenerator) Factory { f.txGenerator = g return f } // WithAccountRetriever returns a copy of the Factory with an updated AccountRetriever. -func (f Factory) WithAccountRetriever(ar AccountRetriever) Factory { +func (f Factory) WithAccountRetriever(ar context.AccountRetriever) Factory { f.accountRetriever = ar return f } diff --git a/client/tx/tx.go b/client/tx/tx.go index 7ae89d0aff..b7548cda10 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -9,67 +9,26 @@ import ( "strings" "github.com/gogo/protobuf/jsonpb" - "github.com/tendermint/tendermint/crypto" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" clientkeys "github.com/cosmos/cosmos-sdk/client/keys" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/rest" ) -type ( - // Generator defines an interface a client can utilize to generate an - // application-defined concrete transaction type. The type returned must - // implement ClientTx. - Generator interface { - NewTx() ClientTx - NewFee() ClientFee - NewSignature() ClientSignature - } - - ClientFee interface { - sdk.Fee - SetGas(uint64) - SetAmount(sdk.Coins) - } - - ClientSignature interface { - sdk.Signature - SetPubKey(crypto.PubKey) error - SetSignature([]byte) - } - - // ClientTx defines an interface which an application-defined concrete transaction - // type must implement. Namely, it must be able to set messages, generate - // signatures, and provide canonical bytes to sign over. The transaction must - // also know how to encode itself. - ClientTx interface { - sdk.Tx - codec.ProtoMarshaler - - SetMsgs(...sdk.Msg) error - GetSignatures() []sdk.Signature - SetSignatures(...ClientSignature) error - GetFee() sdk.Fee - SetFee(ClientFee) error - GetMemo() string - SetMemo(string) - - // CanonicalSignBytes returns the canonical JSON bytes to sign over, given a - // chain ID, along with an account and sequence number. The JSON encoding - // ensures all field names adhere to their proto definition, default values - // are omitted, and follows the JSON Canonical Form. - CanonicalSignBytes(cid string, num, seq uint64) ([]byte, error) - } -) - // GenerateOrBroadcastTx will either generate and print and unsigned transaction // or sign it and broadcast it returning an error upon failure. -func GenerateOrBroadcastTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { +func GenerateOrBroadcastTx(ctx context.CLIContext, msgs ...sdk.Msg) error { + txf := NewFactoryFromCLI(ctx.Input).WithTxGenerator(ctx.TxGenerator).WithAccountRetriever(ctx.AccountRetriever) + return GenerateOrBroadcastTxWithFactory(ctx, txf, msgs...) +} + +// GenerateOrBroadcastTxWithFactory will either generate and print and unsigned transaction +// or sign it and broadcast it returning an error upon failure. +func GenerateOrBroadcastTxWithFactory(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { if ctx.GenerateOnly { return GenerateTx(ctx, txf, msgs...) } @@ -101,7 +60,7 @@ func GenerateTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { return err } - return ctx.Println(tx) + return ctx.Println(tx.GetTx()) } // BroadcastTx attempts to generate, sign and broadcast a transaction with the @@ -133,7 +92,7 @@ func BroadcastTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { } if !ctx.SkipConfirm { - out, err := ctx.Marshaler.MarshalJSON(tx) + out, err := ctx.JSONMarshaler.MarshalJSON(tx) if err != nil { return err } @@ -167,7 +126,7 @@ func BroadcastTx(ctx context.CLIContext, txf Factory, msgs ...sdk.Msg) error { // provided http.ResponseWriter. It will simulate gas costs if requested by the // BaseReq. Upon any error, the error will be written to the http.ResponseWriter. func WriteGeneratedTxResponse( - ctx context.CLIContext, w http.ResponseWriter, txg Generator, br rest.BaseReq, msgs ...sdk.Msg, + ctx context.CLIContext, w http.ResponseWriter, br rest.BaseReq, msgs ...sdk.Msg, ) { gasAdj, ok := rest.ParseFloat64OrReturnBadRequest(w, br.GasAdjustment, flags.DefaultGasAdjustment) if !ok { @@ -186,7 +145,8 @@ func WriteGeneratedTxResponse( WithGasAdjustment(gasAdj). WithMemo(br.Memo). WithChainID(br.ChainID). - WithSimulateAndExecute(br.Simulate) + WithSimulateAndExecute(br.Simulate). + WithTxGenerator(ctx.TxGenerator) if br.Simulate || simAndExec { if gasAdj < 0 { @@ -202,7 +162,7 @@ func WriteGeneratedTxResponse( txf = txf.WithGas(adjusted) if br.Simulate { - rest.WriteSimulationResponse(w, ctx.Marshaler, txf.Gas()) + rest.WriteSimulationResponse(w, ctx.JSONMarshaler, txf.Gas()) return } } @@ -212,7 +172,7 @@ func WriteGeneratedTxResponse( return } - output, err := ctx.Marshaler.MarshalJSON(tx) + output, err := ctx.JSONMarshaler.MarshalJSON(tx) if rest.CheckInternalServerError(w, err) { return } @@ -225,7 +185,7 @@ func WriteGeneratedTxResponse( // BuildUnsignedTx builds a transaction to be signed given a set of messages. The // transaction is initially created via the provided factory's generator. Once // created, the fee, memo, and messages are set. -func BuildUnsignedTx(txf Factory, msgs ...sdk.Msg) (ClientTx, error) { +func BuildUnsignedTx(txf Factory, msgs ...sdk.Msg) (context.TxBuilder, error) { if txf.chainID == "" { return nil, fmt.Errorf("chain ID required but not specified") } @@ -288,7 +248,7 @@ func BuildSimTx(txf Factory, msgs ...sdk.Msg) ([]byte, error) { return nil, err } - return tx.Marshal() + return txf.txGenerator.MarshalTx(tx.GetTx()) } // CalculateGas simulates the execution of a transaction and returns the @@ -321,13 +281,13 @@ func CalculateGas( func PrepareFactory(ctx context.CLIContext, txf Factory) (Factory, error) { from := ctx.GetFromAddress() - if err := txf.accountRetriever.EnsureExists(from); err != nil { + if err := txf.accountRetriever.EnsureExists(ctx, from); err != nil { return txf, err } initNum, initSeq := txf.accountNumber, txf.sequence if initNum == 0 || initSeq == 0 { - num, seq, err := txf.accountRetriever.GetAccountNumberSequence(from) + num, seq, err := txf.accountRetriever.GetAccountNumberSequence(ctx, from) if err != nil { return txf, err } @@ -352,7 +312,7 @@ func PrepareFactory(ctx context.CLIContext, txf Factory) (Factory, error) { // // Note, It is assumed the Factory has the necessary fields set that are required // by the CanonicalSignBytes call. -func Sign(txf Factory, name, passphrase string, tx ClientTx) ([]byte, error) { +func Sign(txf Factory, name, passphrase string, tx context.TxBuilder) ([]byte, error) { if txf.keybase == nil { return nil, errors.New("keybase must be set prior to signing a transaction") } @@ -378,7 +338,7 @@ func Sign(txf Factory, name, passphrase string, tx ClientTx) ([]byte, error) { return nil, err } - return tx.Marshal() + return txf.txGenerator.MarshalTx(tx.GetTx()) } // GasEstimateResponse defines a response definition for tx gas estimation. diff --git a/client/tx/tx_test.go b/client/tx/tx_test.go index 8b2cc365bf..85f6973679 100644 --- a/client/tx/tx_test.go +++ b/client/tx/tx_test.go @@ -1,108 +1,109 @@ package tx_test -// TODO: re-enable this test code in #5989 when there are proper implementations again +import ( + "errors" + "testing" -//import ( -// "errors" -// "testing" -// -// "github.com/stretchr/testify/require" -// -// "github.com/cosmos/cosmos-sdk/client/tx" -// "github.com/cosmos/cosmos-sdk/codec" -// "github.com/cosmos/cosmos-sdk/std" -// sdk "github.com/cosmos/cosmos-sdk/types" -// "github.com/cosmos/cosmos-sdk/x/bank" -//) -// -//func TestCalculateGas(t *testing.T) { -// makeQueryFunc := func(gasUsed uint64, wantErr bool) func(string, []byte) ([]byte, int64, error) { -// return func(string, []byte) ([]byte, int64, error) { -// if wantErr { -// return nil, 0, errors.New("query failed") -// } -// simRes := &sdk.SimulationResponse{ -// GasInfo: sdk.GasInfo{GasUsed: gasUsed, GasWanted: gasUsed}, -// Result: &sdk.Result{Data: []byte("tx data"), Log: "log"}, -// } -// -// bz, err := codec.ProtoMarshalJSON(simRes) -// if err != nil { -// return nil, 0, err -// } -// -// return bz, 0, nil -// } -// } -// -// type args struct { -// queryFuncGasUsed uint64 -// queryFuncWantErr bool -// adjustment float64 -// } -// -// testCases := []struct { -// name string -// args args -// wantEstimate uint64 -// wantAdjusted uint64 -// expPass bool -// }{ -// {"error", args{0, true, 1.2}, 0, 0, false}, -// {"adjusted gas", args{10, false, 1.2}, 10, 12, true}, -// } -// -// for _, tc := range testCases { -// stc := tc -// txf := tx.Factory{}.WithChainID("test-chain").WithTxGenerator(std.TxGenerator{}) -// -// t.Run(stc.name, func(t *testing.T) { -// queryFunc := makeQueryFunc(stc.args.queryFuncGasUsed, stc.args.queryFuncWantErr) -// simRes, gotAdjusted, err := tx.CalculateGas(queryFunc, txf.WithGasAdjustment(stc.args.adjustment)) -// if stc.expPass { -// require.NoError(t, err) -// require.Equal(t, simRes.GasInfo.GasUsed, stc.wantEstimate) -// require.Equal(t, gotAdjusted, stc.wantAdjusted) -// require.NotNil(t, simRes.Result) -// } else { -// require.Error(t, err) -// require.Nil(t, simRes.Result) -// } -// }) -// } -//} -// -//func TestBuildSimTx(t *testing.T) { -// txf := tx.Factory{}. -// WithTxGenerator(std.TxGenerator{}). -// WithAccountNumber(50). -// WithSequence(23). -// WithFees("50stake"). -// WithMemo("memo"). -// WithChainID("test-chain") -// -// msg := bank.NewMsgSend(sdk.AccAddress("from"), sdk.AccAddress("to"), nil) -// bz, err := tx.BuildSimTx(txf, msg) -// require.NoError(t, err) -// require.NotNil(t, bz) -// -// tx := &std.Transaction{} -// require.NoError(t, tx.Unmarshal(bz)) -// require.Equal(t, []sdk.Signature{sdk.Signature(std.StdSignature{})}, tx.GetSignatures()) -//} -// -//func TestBuildUnsignedTx(t *testing.T) { -// txf := tx.Factory{}. -// WithTxGenerator(std.TxGenerator{}). -// WithAccountNumber(50). -// WithSequence(23). -// WithFees("50stake"). -// WithMemo("memo"). -// WithChainID("test-chain") -// -// msg := bank.NewMsgSend(sdk.AccAddress("from"), sdk.AccAddress("to"), nil) -// tx, err := tx.BuildUnsignedTx(txf, msg) -// require.NoError(t, err) -// require.NotNil(t, tx) -// require.Equal(t, []sdk.Signature{}, tx.GetSignatures()) -//} + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/bank" +) + +func NewTestTxGenerator() context.TxGenerator { + _, cdc := simapp.MakeCodecs() + return types.StdTxGenerator{Cdc: cdc} +} + +func TestCalculateGas(t *testing.T) { + makeQueryFunc := func(gasUsed uint64, wantErr bool) func(string, []byte) ([]byte, int64, error) { + return func(string, []byte) ([]byte, int64, error) { + if wantErr { + return nil, 0, errors.New("query failed") + } + simRes := &sdk.SimulationResponse{ + GasInfo: sdk.GasInfo{GasUsed: gasUsed, GasWanted: gasUsed}, + Result: &sdk.Result{Data: []byte("tx data"), Log: "log"}, + } + + bz, err := codec.ProtoMarshalJSON(simRes) + if err != nil { + return nil, 0, err + } + + return bz, 0, nil + } + } + + type args struct { + queryFuncGasUsed uint64 + queryFuncWantErr bool + adjustment float64 + } + + testCases := []struct { + name string + args args + wantEstimate uint64 + wantAdjusted uint64 + expPass bool + }{ + {"error", args{0, true, 1.2}, 0, 0, false}, + {"adjusted gas", args{10, false, 1.2}, 10, 12, true}, + } + + for _, tc := range testCases { + stc := tc + txf := tx.Factory{}.WithChainID("test-chain").WithTxGenerator(NewTestTxGenerator()) + + t.Run(stc.name, func(t *testing.T) { + queryFunc := makeQueryFunc(stc.args.queryFuncGasUsed, stc.args.queryFuncWantErr) + simRes, gotAdjusted, err := tx.CalculateGas(queryFunc, txf.WithGasAdjustment(stc.args.adjustment)) + if stc.expPass { + require.NoError(t, err) + require.Equal(t, simRes.GasInfo.GasUsed, stc.wantEstimate) + require.Equal(t, gotAdjusted, stc.wantAdjusted) + require.NotNil(t, simRes.Result) + } else { + require.Error(t, err) + require.Nil(t, simRes.Result) + } + }) + } +} + +func TestBuildSimTx(t *testing.T) { + txf := tx.Factory{}. + WithTxGenerator(NewTestTxGenerator()). + WithAccountNumber(50). + WithSequence(23). + WithFees("50stake"). + WithMemo("memo"). + WithChainID("test-chain") + + msg := bank.NewMsgSend(sdk.AccAddress("from"), sdk.AccAddress("to"), nil) + bz, err := tx.BuildSimTx(txf, msg) + require.NoError(t, err) + require.NotNil(t, bz) +} + +func TestBuildUnsignedTx(t *testing.T) { + txf := tx.Factory{}. + WithTxGenerator(NewTestTxGenerator()). + WithAccountNumber(50). + WithSequence(23). + WithFees("50stake"). + WithMemo("memo"). + WithChainID("test-chain") + + msg := bank.NewMsgSend(sdk.AccAddress("from"), sdk.AccAddress("to"), nil) + tx, err := tx.BuildUnsignedTx(txf, msg) + require.NoError(t, err) + require.NotNil(t, tx) + require.Equal(t, []sdk.Signature{}, tx.GetSignatures()) +} diff --git a/crypto/types/multisig/multisignature.go b/crypto/types/multisig/multisignature.go index cef36be3a6..2e21935f26 100644 --- a/crypto/types/multisig/multisignature.go +++ b/crypto/types/multisig/multisignature.go @@ -4,8 +4,9 @@ import ( "fmt" "strings" - "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/tendermint/tendermint/crypto" + + "github.com/cosmos/cosmos-sdk/crypto/types" ) // Multisignature is used to represent the signature object used in the multisigs. diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md index 98670b0269..811f557039 100644 --- a/docs/architecture/adr-020-protobuf-transaction-encoding.md +++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md @@ -297,17 +297,19 @@ and messages. ```go type AccountRetriever interface { - EnsureExists(addr sdk.AccAddress) error - GetAccountNumberSequence(addr sdk.AccAddress) (uint64, uint64, error) + EnsureExists(querier NodeQuerier, addr sdk.AccAddress) error + GetAccountNumberSequence(querier NodeQuerier, addr sdk.AccAddress) (uint64, uint64, error) } type Generator interface { - NewTx() ClientTx + NewTx() TxBuilder + NewFee() ClientFee + NewSignature() ClientSignature + MarshalTx(tx types.Tx) ([]byte, error) } -type ClientTx interface { - sdk.Tx - codec.ProtoMarshaler +type TxBuilder interface { + GetTx() sdk.Tx SetMsgs(...sdk.Msg) error GetSignatures() []sdk.Signature @@ -321,11 +323,29 @@ type ClientTx interface { } ``` -We then update `CLIContext` to have a new field: `Marshaler`. +We then update `CLIContext` to have new fields: `JSONMarshaler`, `TxGenerator`, +and `AccountRetriever`, and we update `AppModuleBasic.GetTxCmd` to take +a `CLIContext` which should have all of these fields pre-populated. -Then, each module's client handler will at the minimum accept a `Marshaler` instead -of a concrete Amino codec and a `Generator` along with an `AccountRetriever` so -that account fields can be retrieved for signing. +Each client method should then use one of the `Init` methods to re-initialize +the pre-populated `CLIContext`. `tx.GenerateOrBroadcastTx` can be used to +generate or broadcast a transaction. For example: + +```go +import "github.com/spf13/cobra" +import "github.com/cosmos/cosmos-sdk/client/tx" +import "github.com/cosmos/cosmos-sdk/client/context" + +func NewCmdDoSomething(ctx context.CLIContext) *cobra.Command { + return &cobra.Command{ + RunE: func(cmd *cobra.Command, args []string) error { + ctx := ctx.InitWithInput(cmd.InOrStdin()) + msg := NewSomeMsg{...} + tx.GenerateOrBroadcastTx(cliCtx, msg) + }, + } +} +``` ## Future Improvements diff --git a/go.sum b/go.sum index fb321d359b..a8ae328a8b 100644 --- a/go.sum +++ b/go.sum @@ -629,6 +629,7 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2 h1:V9r/14uGBqLgNlHRYWdVqjMdWkcOHnE2KG8DwVqQSEc= golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/simapp/cmd/simcli/main.go b/simapp/cmd/simcli/main.go index d2207f31dd..0ae3f1c5dc 100644 --- a/simapp/cmd/simcli/main.go +++ b/simapp/cmd/simcli/main.go @@ -5,22 +5,23 @@ import ( "os" "path" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/lcd" "github.com/cosmos/cosmos-sdk/client/rpc" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" + "github.com/cosmos/cosmos-sdk/x/auth/types" bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli" ) @@ -117,8 +118,15 @@ func txCmd(cdc *codec.Codec) *cobra.Command { RunE: client.ValidateCmd, } + cliCtx := context.CLIContext{} + cliCtx = cliCtx. + WithJSONMarshaler(appCodec). + WithTxGenerator(types.StdTxGenerator{Cdc: cdc}). + WithAccountRetriever(types.NewAccountRetriever(appCodec)). + WithCodec(cdc) + txCmd.AddCommand( - bankcmd.SendTxCmd(cdc), + bankcmd.NewSendTxCmd(cliCtx), flags.LineBreak, authcmd.GetSignCommand(cdc), authcmd.GetMultiSignCommand(cdc), @@ -131,7 +139,7 @@ func txCmd(cdc *codec.Codec) *cobra.Command { ) // add modules' tx commands - simapp.ModuleBasics.AddTxCommands(txCmd, cdc) + simapp.ModuleBasics.AddTxCommands(txCmd, cliCtx) return txCmd } diff --git a/tests/mocks/account_retriever.go b/tests/mocks/account_retriever.go index a3086c77bd..f0e089f288 100644 --- a/tests/mocks/account_retriever.go +++ b/tests/mocks/account_retriever.go @@ -1,14 +1,69 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: x/auth/types/account_retriever.go +// Source: client/context/account_retriever.go // Package mocks is a generated GoMock package. package mocks import ( + context "github.com/cosmos/cosmos-sdk/client/context" + types "github.com/cosmos/cosmos-sdk/types" gomock "github.com/golang/mock/gomock" reflect "reflect" ) +// MockAccountRetriever is a mock of AccountRetriever interface +type MockAccountRetriever struct { + ctrl *gomock.Controller + recorder *MockAccountRetrieverMockRecorder +} + +// MockAccountRetrieverMockRecorder is the mock recorder for MockAccountRetriever +type MockAccountRetrieverMockRecorder struct { + mock *MockAccountRetriever +} + +// NewMockAccountRetriever creates a new mock instance +func NewMockAccountRetriever(ctrl *gomock.Controller) *MockAccountRetriever { + mock := &MockAccountRetriever{ctrl: ctrl} + mock.recorder = &MockAccountRetrieverMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockAccountRetriever) EXPECT() *MockAccountRetrieverMockRecorder { + return m.recorder +} + +// EnsureExists mocks base method +func (m *MockAccountRetriever) EnsureExists(nodeQuerier context.NodeQuerier, addr types.AccAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EnsureExists", nodeQuerier, addr) + ret0, _ := ret[0].(error) + return ret0 +} + +// EnsureExists indicates an expected call of EnsureExists +func (mr *MockAccountRetrieverMockRecorder) EnsureExists(nodeQuerier, addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureExists", reflect.TypeOf((*MockAccountRetriever)(nil).EnsureExists), nodeQuerier, addr) +} + +// GetAccountNumberSequence mocks base method +func (m *MockAccountRetriever) GetAccountNumberSequence(nodeQuerier context.NodeQuerier, addr types.AccAddress) (uint64, uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAccountNumberSequence", nodeQuerier, addr) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(uint64) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GetAccountNumberSequence indicates an expected call of GetAccountNumberSequence +func (mr *MockAccountRetrieverMockRecorder) GetAccountNumberSequence(nodeQuerier, addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountNumberSequence", reflect.TypeOf((*MockAccountRetriever)(nil).GetAccountNumberSequence), nodeQuerier, addr) +} + // MockNodeQuerier is a mock of NodeQuerier interface type MockNodeQuerier struct { ctrl *gomock.Controller diff --git a/tests/mocks/tendermint_tm_db_DB.go b/tests/mocks/tendermint_tm_db_DB.go index bed59a498d..cdf5e5ab0a 100644 --- a/tests/mocks/tendermint_tm_db_DB.go +++ b/tests/mocks/tendermint_tm_db_DB.go @@ -6,7 +6,7 @@ package mocks import ( gomock "github.com/golang/mock/gomock" - tm_db "github.com/tendermint/tm-db" + db "github.com/tendermint/tm-db" reflect "reflect" ) @@ -106,10 +106,10 @@ func (mr *MockDBMockRecorder) Has(arg0 interface{}) *gomock.Call { } // Iterator mocks base method -func (m *MockDB) Iterator(arg0, arg1 []byte) (tm_db.Iterator, error) { +func (m *MockDB) Iterator(arg0, arg1 []byte) (db.Iterator, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Iterator", arg0, arg1) - ret0, _ := ret[0].(tm_db.Iterator) + ret0, _ := ret[0].(db.Iterator) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -121,10 +121,10 @@ func (mr *MockDBMockRecorder) Iterator(arg0, arg1 interface{}) *gomock.Call { } // NewBatch mocks base method -func (m *MockDB) NewBatch() tm_db.Batch { +func (m *MockDB) NewBatch() db.Batch { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "NewBatch") - ret0, _ := ret[0].(tm_db.Batch) + ret0, _ := ret[0].(db.Batch) return ret0 } @@ -149,10 +149,10 @@ func (mr *MockDBMockRecorder) Print() *gomock.Call { } // ReverseIterator mocks base method -func (m *MockDB) ReverseIterator(arg0, arg1 []byte) (tm_db.Iterator, error) { +func (m *MockDB) ReverseIterator(arg0, arg1 []byte) (db.Iterator, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ReverseIterator", arg0, arg1) - ret0, _ := ret[0].(tm_db.Iterator) + ret0, _ := ret[0].(db.Iterator) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/tests/mocks/types_module_module.go b/tests/mocks/types_module_module.go index 274ac5c063..0d52cde999 100644 --- a/tests/mocks/types_module_module.go +++ b/tests/mocks/types_module_module.go @@ -106,7 +106,7 @@ func (mr *MockAppModuleBasicMockRecorder) RegisterRESTRoutes(arg0, arg1 interfac } // GetTxCmd mocks base method -func (m *MockAppModuleBasic) GetTxCmd(arg0 *codec.Codec) *cobra.Command { +func (m *MockAppModuleBasic) GetTxCmd(arg0 context.CLIContext) *cobra.Command { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetTxCmd", arg0) ret0, _ := ret[0].(*cobra.Command) @@ -223,7 +223,7 @@ func (mr *MockAppModuleGenesisMockRecorder) RegisterRESTRoutes(arg0, arg1 interf } // GetTxCmd mocks base method -func (m *MockAppModuleGenesis) GetTxCmd(arg0 *codec.Codec) *cobra.Command { +func (m *MockAppModuleGenesis) GetTxCmd(arg0 context.CLIContext) *cobra.Command { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetTxCmd", arg0) ret0, _ := ret[0].(*cobra.Command) @@ -368,7 +368,7 @@ func (mr *MockAppModuleMockRecorder) RegisterRESTRoutes(arg0, arg1 interface{}) } // GetTxCmd mocks base method -func (m *MockAppModule) GetTxCmd(arg0 *codec.Codec) *cobra.Command { +func (m *MockAppModule) GetTxCmd(arg0 context.CLIContext) *cobra.Command { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetTxCmd", arg0) ret0, _ := ret[0].(*cobra.Command) diff --git a/types/module/module.go b/types/module/module.go index 4a34472308..d3bdd2155c 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -52,7 +52,7 @@ type AppModuleBasic interface { // client functionality RegisterRESTRoutes(context.CLIContext, *mux.Router) - GetTxCmd(*codec.Codec) *cobra.Command + GetTxCmd(context.CLIContext) *cobra.Command GetQueryCmd(*codec.Codec) *cobra.Command } @@ -104,9 +104,9 @@ func (bm BasicManager) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Route } // AddTxCommands adds all tx commands to the rootTxCmd -func (bm BasicManager) AddTxCommands(rootTxCmd *cobra.Command, cdc *codec.Codec) { +func (bm BasicManager) AddTxCommands(rootTxCmd *cobra.Command, ctx context.CLIContext) { for _, b := range bm { - if cmd := b.GetTxCmd(cdc); cmd != nil { + if cmd := b.GetTxCmd(ctx); cmd != nil { rootTxCmd.AddCommand(cmd) } } diff --git a/types/module/module_test.go b/types/module/module_test.go index fa5b17ab35..1f5e1f247b 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -24,6 +24,8 @@ func TestBasicManager(t *testing.T) { mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) cdc := codec.New() + ctx := context.CLIContext{} + ctx = ctx.WithCodec(cdc) wantDefaultGenesis := map[string]json.RawMessage{"mockAppModuleBasic1": json.RawMessage(``)} mockAppModuleBasic1 := mocks.NewMockAppModuleBasic(mockCtrl) @@ -33,7 +35,7 @@ func TestBasicManager(t *testing.T) { mockAppModuleBasic1.EXPECT().ValidateGenesis(gomock.Eq(cdc), gomock.Eq(wantDefaultGenesis["mockAppModuleBasic1"])).Times(1).Return(errFoo) mockAppModuleBasic1.EXPECT().RegisterRESTRoutes(gomock.Eq(context.CLIContext{}), gomock.Eq(&mux.Router{})).Times(1) mockAppModuleBasic1.EXPECT().RegisterCodec(gomock.Eq(cdc)).Times(1) - mockAppModuleBasic1.EXPECT().GetTxCmd(cdc).Times(1).Return(nil) + mockAppModuleBasic1.EXPECT().GetTxCmd(ctx).Times(1).Return(nil) mockAppModuleBasic1.EXPECT().GetQueryCmd(cdc).Times(1).Return(nil) mm := module.NewBasicManager(mockAppModuleBasic1) @@ -51,7 +53,7 @@ func TestBasicManager(t *testing.T) { mm.RegisterRESTRoutes(context.CLIContext{}, &mux.Router{}) mockCmd := &cobra.Command{Use: "root"} - mm.AddTxCommands(mockCmd, cdc) + mm.AddTxCommands(mockCmd, ctx) mm.AddQueryCommands(mockCmd, cdc) diff --git a/types/rest/rest.go b/types/rest/rest.go index b730676a44..8395c983c3 100644 --- a/types/rest/rest.go +++ b/types/rest/rest.go @@ -264,8 +264,8 @@ func PostProcessResponseBare(w http.ResponseWriter, ctx context.CLIContext, body // ref: https://github.com/cosmos/cosmos-sdk/issues/5864 var marshaler codec.JSONMarshaler - if ctx.Marshaler != nil { - marshaler = ctx.Marshaler + if ctx.JSONMarshaler != nil { + marshaler = ctx.JSONMarshaler } else { marshaler = ctx.Codec } @@ -308,8 +308,8 @@ func PostProcessResponse(w http.ResponseWriter, ctx context.CLIContext, resp int // ref: https://github.com/cosmos/cosmos-sdk/issues/5864 var marshaler codec.JSONMarshaler - if ctx.Marshaler != nil { - marshaler = ctx.Marshaler + if ctx.JSONMarshaler != nil { + marshaler = ctx.JSONMarshaler } else { marshaler = ctx.Codec } diff --git a/x/auth/alias.go b/x/auth/alias.go index 5c57f75e77..9895210c9d 100644 --- a/x/auth/alias.go +++ b/x/auth/alias.go @@ -82,7 +82,6 @@ type ( SignatureVerificationGasConsumer = ante.SignatureVerificationGasConsumer AccountKeeper = keeper.AccountKeeper BaseAccount = types.BaseAccount - NodeQuerier = types.NodeQuerier AccountRetriever = types.AccountRetriever GenesisState = types.GenesisState Params = types.Params diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index ccff833b3c..2e428e1e54 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -83,14 +83,14 @@ func GetAccountCmd(cdc *codec.Codec) *cobra.Command { Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - accGetter := types.NewAccountRetriever(authclient.Codec, cliCtx) + accGetter := types.NewAccountRetriever(authclient.Codec) key, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } - acc, err := accGetter.GetAccount(key) + acc, err := accGetter.GetAccount(cliCtx, key) if err != nil { return err } diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index 71375da72e..42b4daada5 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -85,7 +85,7 @@ func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) txBldr := types.NewTxBuilderFromCLI(inBuf) if !cliCtx.Offline { - accnum, seq, err := types.NewAccountRetriever(client.Codec, cliCtx).GetAccountNumberSequence(multisigInfo.GetAddress()) + accnum, seq, err := types.NewAccountRetriever(client.Codec).GetAccountNumberSequence(cliCtx, multisigInfo.GetAddress()) if err != nil { return err } diff --git a/x/auth/client/cli/validate_sigs.go b/x/auth/client/cli/validate_sigs.go index a7b87d3878..07846fc6e7 100644 --- a/x/auth/client/cli/validate_sigs.go +++ b/x/auth/client/cli/validate_sigs.go @@ -89,7 +89,7 @@ func printAndValidateSigs( // Validate the actual signature over the transaction bytes since we can // reach out to a full node to query accounts. if !offline && success { - acc, err := types.NewAccountRetriever(client.Codec, cliCtx).GetAccount(sigAddr) + acc, err := types.NewAccountRetriever(client.Codec).GetAccount(cliCtx, sigAddr) if err != nil { cmd.Printf("failed to get account: %s\n", sigAddr) return false diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index a350bed555..1107fd92a8 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -32,13 +32,13 @@ func QueryAccountRequestHandlerFn(storeName string, cliCtx context.CLIContext) h return } - accGetter := types.NewAccountRetriever(client.Codec, cliCtx) + accGetter := types.NewAccountRetriever(client.Codec) - account, height, err := accGetter.GetAccountWithHeight(addr) + account, height, err := accGetter.GetAccountWithHeight(cliCtx, addr) if err != nil { // TODO: Handle more appropriately based on the error type. // Ref: https://github.com/cosmos/cosmos-sdk/issues/4923 - if err := accGetter.EnsureExists(addr); err != nil { + if err := accGetter.EnsureExists(cliCtx, addr); err != nil { cliCtx = cliCtx.WithHeight(height) rest.PostProcessResponse(w, cliCtx, types.BaseAccount{}) return diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index 90678f32d0..a6846cfac7 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -255,7 +255,7 @@ func populateAccountFromState( txBldr authtypes.TxBuilder, cliCtx context.CLIContext, addr sdk.AccAddress, ) (authtypes.TxBuilder, error) { - num, seq, err := authtypes.NewAccountRetriever(Codec, cliCtx).GetAccountNumberSequence(addr) + num, seq, err := authtypes.NewAccountRetriever(Codec).GetAccountNumberSequence(cliCtx, addr) if err != nil { return txBldr, err } @@ -302,8 +302,8 @@ func parseQueryResponse(bz []byte) (sdk.SimulationResponse, error) { func PrepareTxBuilder(txBldr authtypes.TxBuilder, cliCtx context.CLIContext) (authtypes.TxBuilder, error) { from := cliCtx.GetFromAddress() - accGetter := authtypes.NewAccountRetriever(Codec, cliCtx) - if err := accGetter.EnsureExists(from); err != nil { + accGetter := authtypes.NewAccountRetriever(Codec) + if err := accGetter.EnsureExists(cliCtx, from); err != nil { return txBldr, err } @@ -311,7 +311,7 @@ func PrepareTxBuilder(txBldr authtypes.TxBuilder, cliCtx context.CLIContext) (au // TODO: (ref #1903) Allow for user supplied account number without // automatically doing a manual lookup. if txbldrAccNum == 0 || txbldrAccSeq == 0 { - num, seq, err := authtypes.NewAccountRetriever(Codec, cliCtx).GetAccountNumberSequence(from) + num, seq, err := authtypes.NewAccountRetriever(Codec).GetAccountNumberSequence(cliCtx, from) if err != nil { return txBldr, err } diff --git a/x/auth/module.go b/x/auth/module.go index 11875b6356..4b7eac343c 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -63,8 +63,8 @@ func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router } // GetTxCmd returns the root tx command for the auth module. -func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetTxCmd(cdc) +func (AppModuleBasic) GetTxCmd(ctx context.CLIContext) *cobra.Command { + return cli.GetTxCmd(ctx.Codec) } // GetQueryCmd returns the root query command for the auth module. diff --git a/x/auth/types/account_retriever.go b/x/auth/types/account_retriever.go index 88f15ebc24..90884b0a60 100644 --- a/x/auth/types/account_retriever.go +++ b/x/auth/types/account_retriever.go @@ -3,47 +3,39 @@ package types import ( "fmt" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" ) -// NodeQuerier is an interface that is satisfied by types that provide the QueryWithData method -type NodeQuerier interface { - // QueryWithData performs a query to a Tendermint node with the provided path - // and a data payload. It returns the result and height of the query upon success - // or an error if the query fails. - QueryWithData(path string, data []byte) ([]byte, int64, error) -} - // AccountRetriever defines the properties of a type that can be used to // retrieve accounts. type AccountRetriever struct { - codec codec.Marshaler - querier NodeQuerier + codec codec.Marshaler } // NewAccountRetriever initialises a new AccountRetriever instance. -func NewAccountRetriever(codec codec.Marshaler, querier NodeQuerier) AccountRetriever { - return AccountRetriever{codec: codec, querier: querier} +func NewAccountRetriever(codec codec.Marshaler) AccountRetriever { + return AccountRetriever{codec: codec} } // GetAccount queries for an account given an address and a block height. An // error is returned if the query or decoding fails. -func (ar AccountRetriever) GetAccount(addr sdk.AccAddress) (AccountI, error) { - account, _, err := ar.GetAccountWithHeight(addr) +func (ar AccountRetriever) GetAccount(querier context.NodeQuerier, addr sdk.AccAddress) (AccountI, error) { + account, _, err := ar.GetAccountWithHeight(querier, addr) return account, err } // GetAccountWithHeight queries for an account given an address. Returns the // height of the query with the account. An error is returned if the query // or decoding fails. -func (ar AccountRetriever) GetAccountWithHeight(addr sdk.AccAddress) (AccountI, int64, error) { +func (ar AccountRetriever) GetAccountWithHeight(querier context.NodeQuerier, addr sdk.AccAddress) (AccountI, int64, error) { bs, err := ar.codec.MarshalJSON(NewQueryAccountParams(addr)) if err != nil { return nil, 0, err } - bz, height, err := ar.querier.QueryWithData(fmt.Sprintf("custom/%s/%s", QuerierRoute, QueryAccount), bs) + bz, height, err := querier.QueryWithData(fmt.Sprintf("custom/%s/%s", QuerierRoute, QueryAccount), bs) if err != nil { return nil, height, err } @@ -57,8 +49,8 @@ func (ar AccountRetriever) GetAccountWithHeight(addr sdk.AccAddress) (AccountI, } // EnsureExists returns an error if no account exists for the given address else nil. -func (ar AccountRetriever) EnsureExists(addr sdk.AccAddress) error { - if _, err := ar.GetAccount(addr); err != nil { +func (ar AccountRetriever) EnsureExists(querier context.NodeQuerier, addr sdk.AccAddress) error { + if _, err := ar.GetAccount(querier, addr); err != nil { return err } return nil @@ -66,8 +58,8 @@ func (ar AccountRetriever) EnsureExists(addr sdk.AccAddress) error { // GetAccountNumberSequence returns sequence and account number for the given address. // It returns an error if the account couldn't be retrieved from the state. -func (ar AccountRetriever) GetAccountNumberSequence(addr sdk.AccAddress) (uint64, uint64, error) { - acc, err := ar.GetAccount(addr) +func (ar AccountRetriever) GetAccountNumberSequence(nodeQuerier context.NodeQuerier, addr sdk.AccAddress) (uint64, uint64, error) { + acc, err := ar.GetAccount(nodeQuerier, addr) if err != nil { return 0, 0, err } diff --git a/x/auth/types/account_retriever_test.go b/x/auth/types/account_retriever_test.go index 99310d1170..ad61a41e66 100644 --- a/x/auth/types/account_retriever_test.go +++ b/x/auth/types/account_retriever_test.go @@ -19,7 +19,7 @@ func TestAccountRetriever(t *testing.T) { defer mockCtrl.Finish() mockNodeQuerier := mocks.NewMockNodeQuerier(mockCtrl) - accRetr := types.NewAccountRetriever(appCodec, mockNodeQuerier) + accRetr := types.NewAccountRetriever(appCodec) addr := []byte("test") bs, err := appCodec.MarshalJSON(types.NewQueryAccountParams(addr)) require.NoError(t, err) @@ -28,17 +28,17 @@ func TestAccountRetriever(t *testing.T) { mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq(route), gomock.Eq(bs)).Return(nil, int64(0), errFoo).Times(1) - _, err = accRetr.GetAccount(addr) + _, err = accRetr.GetAccount(mockNodeQuerier, addr) require.Error(t, err) mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq(route), gomock.Eq(bs)).Return(nil, int64(0), errFoo).Times(1) - n, s, err := accRetr.GetAccountNumberSequence(addr) + n, s, err := accRetr.GetAccountNumberSequence(mockNodeQuerier, addr) require.Error(t, err) require.Equal(t, uint64(0), n) require.Equal(t, uint64(0), s) mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq(route), gomock.Eq(bs)).Return(nil, int64(0), errFoo).Times(1) - require.Error(t, accRetr.EnsureExists(addr)) + require.Error(t, accRetr.EnsureExists(mockNodeQuerier, addr)) } diff --git a/x/auth/types/client_tx.go b/x/auth/types/client_tx.go new file mode 100644 index 0000000000..ccc0618f06 --- /dev/null +++ b/x/auth/types/client_tx.go @@ -0,0 +1,127 @@ +package types + +import ( + "github.com/tendermint/tendermint/crypto" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// StdTxBuilder wraps StdTx to implement to the context.TxBuilder interface +type StdTxBuilder struct { + StdTx +} + +var _ context.TxBuilder = &StdTxBuilder{} + +// GetTx implements TxBuilder.GetTx +func (s *StdTxBuilder) GetTx() sdk.Tx { + return s.StdTx +} + +// SetMsgs implements TxBuilder.SetMsgs +func (s *StdTxBuilder) SetMsgs(msgs ...sdk.Msg) error { + s.Msgs = msgs + return nil +} + +// GetSignatures implements TxBuilder.GetSignatures +func (s StdTxBuilder) GetSignatures() []sdk.Signature { + res := make([]sdk.Signature, len(s.Signatures)) + for i, sig := range s.Signatures { + res[i] = sig + } + return res +} + +// SetSignatures implements TxBuilder.SetSignatures +func (s *StdTxBuilder) SetSignatures(signatures ...context.ClientSignature) error { + sigs := make([]StdSignature, len(signatures)) + for i, sig := range signatures { + pubKey := sig.GetPubKey() + var pubKeyBz []byte + if pubKey != nil { + pubKeyBz = pubKey.Bytes() + } + sigs[i] = StdSignature{ + PubKey: pubKeyBz, + Signature: sig.GetSignature(), + } + } + s.Signatures = sigs + return nil +} + +// GetFee implements TxBuilder.GetFee +func (s StdTxBuilder) GetFee() sdk.Fee { + return s.Fee +} + +// SetFee implements TxBuilder.SetFee +func (s *StdTxBuilder) SetFee(fee context.ClientFee) error { + s.Fee = StdFee{Amount: fee.GetAmount(), Gas: fee.GetGas()} + return nil +} + +// SetMemo implements TxBuilder.SetMemo +func (s *StdTxBuilder) SetMemo(memo string) { + s.Memo = memo +} + +// CanonicalSignBytes implements TxBuilder.CanonicalSignBytes +func (s StdTxBuilder) CanonicalSignBytes(cid string, num, seq uint64) ([]byte, error) { + return StdSignBytes(cid, num, seq, s.Fee, s.Msgs, s.Memo), nil +} + +// StdTxGenerator is a context.TxGenerator for StdTx +type StdTxGenerator struct { + Cdc *codec.Codec +} + +var _ context.TxGenerator = StdTxGenerator{} + +// NewTx implements TxGenerator.NewTx +func (s StdTxGenerator) NewTx() context.TxBuilder { + return &StdTxBuilder{} +} + +// NewFee implements TxGenerator.NewFee +func (s StdTxGenerator) NewFee() context.ClientFee { + return &StdFee{} +} + +// NewSignature implements TxGenerator.NewSignature +func (s StdTxGenerator) NewSignature() context.ClientSignature { + return &StdSignature{} +} + +// MarshalTx implements TxGenerator.MarshalTx +func (s StdTxGenerator) MarshalTx(tx sdk.Tx) ([]byte, error) { + return DefaultTxEncoder(s.Cdc)(tx) +} + +var _ context.ClientFee = &StdFee{} + +// SetGas implements ClientFee.SetGas +func (fee *StdFee) SetGas(gas uint64) { + fee.Gas = gas +} + +// SetAmount implements ClientFee.SetAmount +func (fee *StdFee) SetAmount(coins sdk.Coins) { + fee.Amount = coins +} + +var _ context.ClientSignature = &StdSignature{} + +// SetPubKey implements ClientSignature.SetPubKey +func (ss *StdSignature) SetPubKey(key crypto.PubKey) error { + ss.PubKey = key.Bytes() + return nil +} + +// SetSignature implements ClientSignature.SetSignature +func (ss *StdSignature) SetSignature(bytes []byte) { + ss.Signature = bytes +} diff --git a/x/bank/client/cli/cli_test.go b/x/bank/client/cli/cli_test.go index fa35b5b6f0..743d348731 100644 --- a/x/bank/client/cli/cli_test.go +++ b/x/bank/client/cli/cli_test.go @@ -42,8 +42,8 @@ func TestCLISend(t *testing.T) { tests.WaitForNextNBlocksTM(1, f.Port) // Ensure account balances match expected - require.Equal(t, sendTokens, testutil.QueryBalances(f, barAddr).AmountOf(cli.Denom)) - require.Equal(t, startTokens.Sub(sendTokens), testutil.QueryBalances(f, fooAddr).AmountOf(cli.Denom)) + require.Equal(t, sendTokens.String(), testutil.QueryBalances(f, barAddr).AmountOf(cli.Denom).String()) + require.Equal(t, startTokens.Sub(sendTokens).String(), testutil.QueryBalances(f, fooAddr).AmountOf(cli.Denom).String()) // Test --dry-run success, _, _ = testutil.TxSend(f, cli.KeyFoo, barAddr, sdk.NewCoin(cli.Denom, sendTokens), "--dry-run") diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index 597004519f..f0ddf275e0 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -1,23 +1,18 @@ package cli import ( - "bufio" - "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/bank/types" ) // NewTxCmd returns a root CLI command handler for all x/bank transaction commands. -func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewTxCmd(cliCtx context.CLIContext) *cobra.Command { txCmd := &cobra.Command{ Use: types.ModuleName, Short: "Bank transaction subcommands", @@ -26,21 +21,19 @@ func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobr RunE: client.ValidateCmd, } - txCmd.AddCommand(NewSendTxCmd(m, txg, ar)) + txCmd.AddCommand(NewSendTxCmd(cliCtx)) return txCmd } // NewSendTxCmd returns a CLI command handler for creating a MsgSend transaction. -func NewSendTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewSendTxCmd(cliCtx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "send [from_key_or_address] [to_address] [amount]", Short: "Create and/or sign and broadcast a MsgSend transaction", Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m) - txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) + cliCtx = cliCtx.InitWithInputAndFrom(cmd.InOrStdin(), args[0]) toAddr, err := sdk.AccAddressFromBech32(args[1]) if err != nil { @@ -57,69 +50,9 @@ func NewSendTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) * return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } return flags.PostCommands(cmd)[0] } - -// --------------------------------------------------------------------------- -// Deprecated -// -// TODO: Remove once client-side Protobuf migration has been completed. -// --------------------------------------------------------------------------- - -// GetTxCmd returns the transaction commands for this module -// -// TODO: Remove once client-side Protobuf migration has been completed. -// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 -func GetTxCmd(cdc *codec.Codec) *cobra.Command { - txCmd := &cobra.Command{ - Use: types.ModuleName, - Short: "Bank transaction subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - txCmd.AddCommand( - SendTxCmd(cdc), - ) - return txCmd -} - -// SendTxCmd will create a send tx and sign it with the given key. -// -// TODO: Remove once client-side Protobuf migration has been completed. -// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 -func SendTxCmd(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "send [from_key_or_address] [to_address] [amount]", - Short: "Create and sign a send tx", - Args: cobra.ExactArgs(3), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithCodec(cdc) - - to, err := sdk.AccAddressFromBech32(args[1]) - if err != nil { - return err - } - - // parse coins trying to be sent - coins, err := sdk.ParseCoins(args[2]) - if err != nil { - return err - } - - // build and sign the transaction, then broadcast to Tendermint - msg := types.NewMsgSend(cliCtx.GetFromAddress(), to, coins) - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } - - cmd = flags.PostCommands(cmd)[0] - - return cmd -} diff --git a/x/bank/client/rest/query.go b/x/bank/client/rest/query.go index ec6b39ad88..aec6ed7be5 100644 --- a/x/bank/client/rest/query.go +++ b/x/bank/client/rest/query.go @@ -41,8 +41,8 @@ func QueryBalancesRequestHandlerFn(ctx context.CLIContext) http.HandlerFunc { // ref: https://github.com/cosmos/cosmos-sdk/issues/5864 var marshaler codec.JSONMarshaler - if ctx.Marshaler != nil { - marshaler = ctx.Marshaler + if ctx.JSONMarshaler != nil { + marshaler = ctx.JSONMarshaler } else { marshaler = ctx.Codec } diff --git a/x/bank/client/rest/rest.go b/x/bank/client/rest/rest.go index 439000012e..28bdec6907 100644 --- a/x/bank/client/rest/rest.go +++ b/x/bank/client/rest/rest.go @@ -4,15 +4,15 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" ) // RegisterHandlers registers all x/bank transaction and query HTTP REST handlers // on the provided mux router. -func RegisterHandlers(ctx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { - r.HandleFunc("/bank/accounts/{address}/transfers", NewSendRequestHandlerFn(ctx, m, txg)).Methods("POST") +func RegisterHandlers(ctx context.CLIContext, r *mux.Router) { + r.HandleFunc("/bank/accounts/{address}/transfers", NewSendRequestHandlerFn(ctx)).Methods("POST") r.HandleFunc("/bank/balances/{address}", QueryBalancesRequestHandlerFn(ctx)).Methods("GET") + r.HandleFunc("/bank/total", totalSupplyHandlerFn(ctx)).Methods("GET") + r.HandleFunc("/bank/total/{denom}", supplyOfHandlerFn(ctx)).Methods("GET") } // --------------------------------------------------------------------------- diff --git a/x/bank/client/rest/tx.go b/x/bank/client/rest/tx.go index db671b741b..60202c9aa4 100644 --- a/x/bank/client/rest/tx.go +++ b/x/bank/client/rest/tx.go @@ -7,7 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" @@ -22,10 +21,8 @@ type SendReq struct { // NewSendRequestHandlerFn returns an HTTP REST handler for creating a MsgSend // transaction. -func NewSendRequestHandlerFn(ctx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { +func NewSendRequestHandlerFn(ctx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - ctx = ctx.WithMarshaler(m) - vars := mux.Vars(r) bech32Addr := vars["address"] @@ -35,7 +32,7 @@ func NewSendRequestHandlerFn(ctx context.CLIContext, m codec.Marshaler, txg tx.G } var req SendReq - if !rest.ReadRESTReq(w, r, ctx.Marshaler, &req) { + if !rest.ReadRESTReq(w, r, ctx.JSONMarshaler, &req) { return } @@ -50,7 +47,7 @@ func NewSendRequestHandlerFn(ctx context.CLIContext, m codec.Marshaler, txg tx.G } msg := types.NewMsgSend(fromAddr, toAddr, req.Amount) - tx.WriteGeneratedTxResponse(ctx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(ctx, w, req.BaseReq, msg) } } diff --git a/x/bank/module.go b/x/bank/module.go index 721c243e26..71721fb658 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -58,12 +58,12 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessag // RegisterRESTRoutes registers the REST routes for the bank module. func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { - rest.RegisterRoutes(ctx, rtr) + rest.RegisterHandlers(ctx, rtr) } // GetTxCmd returns the root tx command for the bank module. -func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetTxCmd(cdc) +func (AppModuleBasic) GetTxCmd(ctx context.CLIContext) *cobra.Command { + return cli.NewTxCmd(ctx) } // GetQueryCmd returns no root query command for the bank module. diff --git a/x/capability/module.go b/x/capability/module.go index a7b285bdd3..911d6921ce 100644 --- a/x/capability/module.go +++ b/x/capability/module.go @@ -65,7 +65,7 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessag func (a AppModuleBasic) RegisterRESTRoutes(_ context.CLIContext, _ *mux.Router) {} // GetTxCmd returns the capability module's root tx command. -func (a AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil } +func (a AppModuleBasic) GetTxCmd(_ context.CLIContext) *cobra.Command { return nil } // GetQueryCmd returns the capability module's root query command. func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil } diff --git a/x/crisis/client/cli/tx.go b/x/crisis/client/cli/tx.go index 320515123a..2d6780a7cf 100644 --- a/x/crisis/client/cli/tx.go +++ b/x/crisis/client/cli/tx.go @@ -1,23 +1,17 @@ package cli import ( - "bufio" - "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/crisis/types" ) // NewTxCmd returns a root CLI command handler for all x/crisis transaction commands. -func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewTxCmd(ctx context.CLIContext) *cobra.Command { txCmd := &cobra.Command{ Use: types.ModuleName, Short: "Crisis transactions subcommands", @@ -26,22 +20,20 @@ func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobr RunE: client.ValidateCmd, } - txCmd.AddCommand(NewMsgVerifyInvariantTxCmd(m, txg, ar)) + txCmd.AddCommand(NewMsgVerifyInvariantTxCmd(ctx)) return txCmd } // NewMsgVerifyInvariantTxCmd returns a CLI command handler for creating a // MsgVerifyInvariant transaction. -func NewMsgVerifyInvariantTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewMsgVerifyInvariantTxCmd(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "invariant-broken [module-name] [invariant-route]", Short: "Submit proof that an invariant broken to halt the chain", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) - txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) senderAddr := cliCtx.GetFromAddress() moduleName, route := args[0], args[1] @@ -51,52 +43,9 @@ func NewMsgVerifyInvariantTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.Accou return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } return flags.PostCommands(cmd)[0] } - -// --------------------------------------------------------------------------- -// Deprecated -// -// TODO: Remove once client-side Protobuf migration has been completed. -// --------------------------------------------------------------------------- - -// GetTxCmd returns the transaction commands for this module -func GetTxCmd(cdc *codec.Codec) *cobra.Command { - txCmd := &cobra.Command{ - Use: types.ModuleName, - Short: "Crisis transactions subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - txCmd.AddCommand(flags.PostCommands( - GetCmdInvariantBroken(cdc), - )...) - return txCmd -} - -// command to replace a delegator's withdrawal address -func GetCmdInvariantBroken(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "invariant-broken [module-name] [invariant-route]", - Short: "submit proof that an invariant broken to halt the chain", - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - senderAddr := cliCtx.GetFromAddress() - moduleName, route := args[0], args[1] - msg := types.NewMsgVerifyInvariant(senderAddr, moduleName, route) - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } - return cmd -} diff --git a/x/crisis/module.go b/x/crisis/module.go index 93d30ee360..52393973fa 100644 --- a/x/crisis/module.go +++ b/x/crisis/module.go @@ -56,8 +56,8 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessag func (AppModuleBasic) RegisterRESTRoutes(_ context.CLIContext, _ *mux.Router) {} // GetTxCmd returns the root tx command for the crisis module. -func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetTxCmd(cdc) +func (b AppModuleBasic) GetTxCmd(ctx context.CLIContext) *cobra.Command { + return cli.NewTxCmd(ctx) } // GetQueryCmd returns no root query command for the crisis module. diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index 6f67ed21ac..d050387cef 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -2,27 +2,21 @@ package cli import ( - "bufio" "fmt" "strings" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/auth" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client" - "github.com/cosmos/cosmos-sdk/x/gov" - "github.com/cosmos/cosmos-sdk/x/distribution/client/common" "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/gov" ) var ( @@ -37,7 +31,7 @@ const ( ) // NewTxCmd returns a root CLI command handler for all x/distribution transaction commands. -func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewTxCmd(ctx context.CLIContext) *cobra.Command { distTxCmd := &cobra.Command{ Use: types.ModuleName, Short: "Distribution transactions subcommands", @@ -47,26 +41,25 @@ func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobr } distTxCmd.AddCommand(flags.PostCommands( - NewWithdrawRewardsCmd(m, txg, ar), - NewWithdrawAllRewardsCmd(m, txg, ar), - NewSetWithdrawAddrCmd(m, txg, ar), - NewFundCommunityPoolCmd(m, txg, ar), + NewWithdrawRewardsCmd(ctx), + NewWithdrawAllRewardsCmd(ctx), + NewSetWithdrawAddrCmd(ctx), + NewFundCommunityPoolCmd(ctx), )...) return distTxCmd } -type newGenerateOrBroadcastFunc func(ctx context.CLIContext, txf tx.Factory, msgs ...sdk.Msg) error +type newGenerateOrBroadcastFunc func(ctx context.CLIContext, msgs ...sdk.Msg) error func newSplitAndApply( newGenerateOrBroadcast newGenerateOrBroadcastFunc, cliCtx context.CLIContext, - txBldr tx.Factory, msgs []sdk.Msg, chunkSize int, ) error { if chunkSize == 0 { - return newGenerateOrBroadcast(cliCtx, txBldr, msgs...) + return newGenerateOrBroadcast(cliCtx, msgs...) } // split messages into slices of length chunkSize @@ -79,7 +72,7 @@ func newSplitAndApply( } msgChunk := msgs[i:sliceEnd] - if err := newGenerateOrBroadcast(cliCtx, txBldr, msgChunk...); err != nil { + if err := newGenerateOrBroadcast(cliCtx, msgChunk...); err != nil { return err } } @@ -87,7 +80,7 @@ func newSplitAndApply( return nil } -func NewWithdrawRewardsCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewWithdrawRewardsCmd(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "withdraw-rewards [validator-addr]", Short: "Withdraw rewards from a given delegation address, and optionally withdraw validator commission if the delegation address given is a validator operator", @@ -104,11 +97,7 @@ $ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fx ), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txf := tx.NewFactoryFromCLI(inBuf). - WithTxGenerator(txg). - WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) delAddr := cliCtx.GetFromAddress() valAddr, err := sdk.ValAddressFromBech32(args[0]) @@ -127,14 +116,14 @@ $ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fx } } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msgs...) + return tx.GenerateOrBroadcastTx(cliCtx, msgs...) }, } cmd.Flags().Bool(flagCommission, false, "also withdraw validator's commission") - return flags.PostCommands(cmd)[0] + return cmd } -func NewWithdrawAllRewardsCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewWithdrawAllRewardsCmd(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "withdraw-all-rewards", Short: "withdraw all delegations rewards for a delegator", @@ -149,11 +138,7 @@ $ %s tx distribution withdraw-all-rewards --from mykey ), Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txf := tx.NewFactoryFromCLI(inBuf). - WithTxGenerator(txg). - WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) delAddr := cliCtx.GetFromAddress() @@ -169,13 +154,13 @@ $ %s tx distribution withdraw-all-rewards --from mykey } chunkSize := viper.GetInt(flagMaxMessagesPerTx) - return newSplitAndApply(tx.GenerateOrBroadcastTx, cliCtx, txf, msgs, chunkSize) + return newSplitAndApply(tx.GenerateOrBroadcastTx, cliCtx, msgs, chunkSize) }, } - return flags.PostCommands(cmd)[0] + return cmd } -func NewSetWithdrawAddrCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewSetWithdrawAddrCmd(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "set-withdraw-addr [withdraw-addr]", Short: "change the default withdraw address for rewards associated with an address", @@ -190,11 +175,7 @@ $ %s tx distribution set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75 ), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txf := tx.NewFactoryFromCLI(inBuf). - WithTxGenerator(txg). - WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) delAddr := cliCtx.GetFromAddress() withdrawAddr, err := sdk.AccAddressFromBech32(args[0]) @@ -207,13 +188,13 @@ $ %s tx distribution set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75 return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } - return flags.PostCommands(cmd)[0] + return cmd } -func NewFundCommunityPoolCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewFundCommunityPoolCmd(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "community-pool-spend [proposal-file]", Args: cobra.ExactArgs(1), @@ -239,11 +220,7 @@ Where proposal.json contains: ), ), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txf := tx.NewFactoryFromCLI(inBuf). - WithTxGenerator(txg). - WithAccountRetriever(ar) - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) depositorAddr := cliCtx.GetFromAddress() amount, err := sdk.ParseCoins(args[0]) @@ -256,185 +233,14 @@ Where proposal.json contains: return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } - return flags.PostCommands(cmd)[0] -} - -// --------------------------------------------------------------------------- -// Deprecated -// -// TODO: Remove once client-side Protobuf migration has been completed. -// --------------------------------------------------------------------------- -// GetTxCmd returns the transaction commands for this module -func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - distTxCmd := &cobra.Command{ - Use: types.ModuleName, - Short: "Distribution transactions subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - distTxCmd.AddCommand(flags.PostCommands( - GetCmdWithdrawRewards(cdc), - GetCmdSetWithdrawAddr(cdc), - GetCmdWithdrawAllRewards(cdc, storeKey), - GetCmdFundCommunityPool(cdc), - )...) - - return distTxCmd -} - -type generateOrBroadcastFunc func(context.CLIContext, auth.TxBuilder, []sdk.Msg) error - -func splitAndApply( - generateOrBroadcast generateOrBroadcastFunc, - cliCtx context.CLIContext, - txBldr auth.TxBuilder, - msgs []sdk.Msg, - chunkSize int, -) error { - - if chunkSize == 0 { - return generateOrBroadcast(cliCtx, txBldr, msgs) - } - - // split messages into slices of length chunkSize - totalMessages := len(msgs) - for i := 0; i < len(msgs); i += chunkSize { - - sliceEnd := i + chunkSize - if sliceEnd > totalMessages { - sliceEnd = totalMessages - } - - msgChunk := msgs[i:sliceEnd] - if err := generateOrBroadcast(cliCtx, txBldr, msgChunk); err != nil { - return err - } - } - - return nil -} - -// command to withdraw rewards -func GetCmdWithdrawRewards(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "withdraw-rewards [validator-addr]", - Short: "Withdraw rewards from a given delegation address, and optionally withdraw validator commission if the delegation address given is a validator operator", - Long: strings.TrimSpace( - fmt.Sprintf(`Withdraw rewards from a given delegation address, -and optionally withdraw validator commission if the delegation address given is a validator operator. - -Example: -$ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj --from mykey -$ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj --from mykey --commission -`, - version.ClientName, version.ClientName, - ), - ), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - delAddr := cliCtx.GetFromAddress() - valAddr, err := sdk.ValAddressFromBech32(args[0]) - if err != nil { - return err - } - - msgs := []sdk.Msg{types.NewMsgWithdrawDelegatorReward(delAddr, valAddr)} - if viper.GetBool(flagCommission) { - msgs = append(msgs, types.NewMsgWithdrawValidatorCommission(valAddr)) - } - - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, msgs) - }, - } - cmd.Flags().Bool(flagCommission, false, "also withdraw validator's commission") return cmd } -// command to withdraw all rewards -func GetCmdWithdrawAllRewards(cdc *codec.Codec, queryRoute string) *cobra.Command { - cmd := &cobra.Command{ - Use: "withdraw-all-rewards", - Short: "withdraw all delegations rewards for a delegator", - Long: strings.TrimSpace( - fmt.Sprintf(`Withdraw all rewards for a single delegator. - -Example: -$ %s tx distribution withdraw-all-rewards --from mykey -`, - version.ClientName, - ), - ), - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - delAddr := cliCtx.GetFromAddress() - - // The transaction cannot be generated offline since it requires a query - // to get all the validators. - if cliCtx.Offline { - return fmt.Errorf("cannot generate tx in offline mode") - } - - msgs, err := common.WithdrawAllDelegatorRewards(cliCtx, queryRoute, delAddr) - if err != nil { - return err - } - - chunkSize := viper.GetInt(flagMaxMessagesPerTx) - return splitAndApply(authclient.GenerateOrBroadcastMsgs, cliCtx, txBldr, msgs, chunkSize) - }, - } - - cmd.Flags().Int(flagMaxMessagesPerTx, MaxMessagesPerTxDefault, "Limit the number of messages per tx (0 for unlimited)") - return cmd -} - -// command to replace a delegator's withdrawal address -func GetCmdSetWithdrawAddr(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "set-withdraw-addr [withdraw-addr]", - Short: "change the default withdraw address for rewards associated with an address", - Long: strings.TrimSpace( - fmt.Sprintf(`Set the withdraw address for rewards associated with a delegator address. - -Example: -$ %s tx distribution set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p --from mykey -`, - version.ClientName, - ), - ), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - delAddr := cliCtx.GetFromAddress() - withdrawAddr, err := sdk.AccAddressFromBech32(args[0]) - if err != nil { - return err - } - - msg := types.NewMsgSetWithdrawAddress(delAddr, withdrawAddr) - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } -} - // GetCmdSubmitProposal implements the command to submit a community-pool-spend proposal -func GetCmdSubmitProposal(cdc *codec.Codec) *cobra.Command { +func GetCmdSubmitProposal(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "community-pool-spend [proposal-file]", Args: cobra.ExactArgs(1), @@ -460,11 +266,9 @@ Where proposal.json contains: ), ), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) - proposal, err := ParseCommunityPoolSpendProposalJSON(cdc, args[0]) + proposal, err := ParseCommunityPoolSpendProposalJSON(ctx.JSONMarshaler, args[0]) if err != nil { return err } @@ -489,46 +293,40 @@ Where proposal.json contains: return err } - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } return cmd } -// GetCmdFundCommunityPool returns a command implementation that supports directly -// funding the community pool. -func GetCmdFundCommunityPool(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "fund-community-pool [amount]", - Args: cobra.ExactArgs(1), - Short: "Funds the community pool with the specified amount", - Long: strings.TrimSpace( - fmt.Sprintf(`Funds the community pool with the specified amount +type generateOrBroadcastFunc func(context.CLIContext, []sdk.Msg) error -Example: -$ %s tx distribution fund-community-pool 100uatom --from mykey -`, - version.ClientName, - ), - ), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) +func splitAndApply( + generateOrBroadcast generateOrBroadcastFunc, + cliCtx context.CLIContext, + msgs []sdk.Msg, + chunkSize int, +) error { - depositorAddr := cliCtx.GetFromAddress() - amount, err := sdk.ParseCoins(args[0]) - if err != nil { - return err - } - - msg := types.NewMsgFundCommunityPool(amount, depositorAddr) - if err := msg.ValidateBasic(); err != nil { - return err - } - - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, + if chunkSize == 0 { + return generateOrBroadcast(cliCtx, msgs) } + + // split messages into slices of length chunkSize + totalMessages := len(msgs) + for i := 0; i < len(msgs); i += chunkSize { + + sliceEnd := i + chunkSize + if sliceEnd > totalMessages { + sliceEnd = totalMessages + } + + msgChunk := msgs[i:sliceEnd] + if err := generateOrBroadcast(cliCtx, msgChunk); err != nil { + return err + } + } + + return nil } diff --git a/x/distribution/client/cli/tx_test.go b/x/distribution/client/cli/tx_test.go index d75f448367..f07478a546 100644 --- a/x/distribution/client/cli/tx_test.go +++ b/x/distribution/client/cli/tx_test.go @@ -12,37 +12,17 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client" ) -func createFakeTxBuilder() auth.TxBuilder { - cdc := codec.New() - return auth.NewTxBuilder( - authclient.GetTxEncoder(cdc), - 123, - 9876, - 0, - 1.2, - false, - "test_chain", - "hello", - sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))), - sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDecWithPrec(10000, sdk.Precision))}, - ) -} - func Test_splitAndCall_NoMessages(t *testing.T) { ctx := context.CLIContext{} - txBldr := createFakeTxBuilder() - err := splitAndApply(nil, ctx, txBldr, nil, 10) + err := splitAndApply(nil, ctx, nil, 10) assert.NoError(t, err, "") } func Test_splitAndCall_Splitting(t *testing.T) { ctx := context.CLIContext{} - txBldr := createFakeTxBuilder() addr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) @@ -60,11 +40,10 @@ func Test_splitAndCall_Splitting(t *testing.T) { callCount := 0 err := splitAndApply( - func(ctx context.CLIContext, txBldr auth.TxBuilder, msgs []sdk.Msg) error { + func(ctx context.CLIContext, msgs []sdk.Msg) error { callCount++ assert.NotNil(t, ctx) - assert.NotNil(t, txBldr) assert.NotNil(t, msgs) if callCount < 3 { @@ -75,7 +54,7 @@ func Test_splitAndCall_Splitting(t *testing.T) { return nil }, - ctx, txBldr, msgs, chunkSize) + ctx, msgs, chunkSize) assert.NoError(t, err, "") assert.Equal(t, 3, callCount) diff --git a/x/distribution/client/cli/utils.go b/x/distribution/client/cli/utils.go index 4d4169a7fa..c5310f6469 100644 --- a/x/distribution/client/cli/utils.go +++ b/x/distribution/client/cli/utils.go @@ -19,7 +19,7 @@ type ( ) // ParseCommunityPoolSpendProposalJSON reads and parses a CommunityPoolSpendProposalJSON from a file. -func ParseCommunityPoolSpendProposalJSON(cdc *codec.Codec, proposalFile string) (CommunityPoolSpendProposalJSON, error) { +func ParseCommunityPoolSpendProposalJSON(cdc codec.JSONMarshaler, proposalFile string) (CommunityPoolSpendProposalJSON, error) { proposal := CommunityPoolSpendProposalJSON{} contents, err := ioutil.ReadFile(proposalFile) diff --git a/x/distribution/client/rest/rest.go b/x/distribution/client/rest/rest.go index f8d1fa91a1..a1db89d41d 100644 --- a/x/distribution/client/rest/rest.go +++ b/x/distribution/client/rest/rest.go @@ -6,8 +6,6 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" @@ -16,9 +14,9 @@ import ( govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" ) -func RegisterHandlers(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { +func RegisterHandlers(cliCtx context.CLIContext, r *mux.Router) { registerQueryRoutes(cliCtx, r) - registerTxHandlers(cliCtx, m, txg, r) + registerTxHandlers(cliCtx, r) } // RegisterRoutes register distribution REST routes. diff --git a/x/distribution/client/rest/tx.go b/x/distribution/client/rest/tx.go index d36a0a4eab..86d6d0d4b2 100644 --- a/x/distribution/client/rest/tx.go +++ b/x/distribution/client/rest/tx.go @@ -7,7 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" @@ -31,41 +30,40 @@ type ( } ) -func registerTxHandlers(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { +func registerTxHandlers(cliCtx context.CLIContext, r *mux.Router) { // Withdraw all delegator rewards r.HandleFunc( "/distribution/delegators/{delegatorAddr}/rewards", - newWithdrawDelegatorRewardsHandlerFn(cliCtx, m, txg), + newWithdrawDelegatorRewardsHandlerFn(cliCtx), ).Methods("POST") // Withdraw delegation rewards r.HandleFunc( "/distribution/delegators/{delegatorAddr}/rewards/{validatorAddr}", - newWithdrawDelegationRewardsHandlerFn(cliCtx, m, txg), + newWithdrawDelegationRewardsHandlerFn(cliCtx), ).Methods("POST") // Replace the rewards withdrawal address r.HandleFunc( "/distribution/delegators/{delegatorAddr}/withdraw_address", - newSetDelegatorWithdrawalAddrHandlerFn(cliCtx, m, txg), + newSetDelegatorWithdrawalAddrHandlerFn(cliCtx), ).Methods("POST") // Withdraw validator rewards and commission r.HandleFunc( "/distribution/validators/{validatorAddr}/rewards", - newWithdrawValidatorRewardsHandlerFn(cliCtx, m, txg), + newWithdrawValidatorRewardsHandlerFn(cliCtx), ).Methods("POST") // Fund the community pool r.HandleFunc( "/distribution/community_pool", - newFundCommunityPoolHandlerFn(cliCtx, m, txg), + newFundCommunityPoolHandlerFn(cliCtx), ).Methods("POST") } -func newWithdrawDelegatorRewardsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { +func newWithdrawDelegatorRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - cliCtx = cliCtx.WithMarshaler(m) var req withdrawRewardsReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { return @@ -87,13 +85,12 @@ func newWithdrawDelegatorRewardsHandlerFn(cliCtx context.CLIContext, m codec.Mar return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msgs...) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msgs...) } } -func newWithdrawDelegationRewardsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { +func newWithdrawDelegationRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - cliCtx = cliCtx.WithMarshaler(m) var req withdrawRewardsReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { return @@ -120,13 +117,12 @@ func newWithdrawDelegationRewardsHandlerFn(cliCtx context.CLIContext, m codec.Ma return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) } } -func newSetDelegatorWithdrawalAddrHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { +func newSetDelegatorWithdrawalAddrHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - cliCtx = cliCtx.WithMarshaler(m) var req setWithdrawalAddrReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { return @@ -148,13 +144,12 @@ func newSetDelegatorWithdrawalAddrHandlerFn(cliCtx context.CLIContext, m codec.M return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) } } -func newWithdrawValidatorRewardsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { +func newWithdrawValidatorRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - cliCtx = cliCtx.WithMarshaler(m) var req withdrawRewardsReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { return @@ -177,13 +172,12 @@ func newWithdrawValidatorRewardsHandlerFn(cliCtx context.CLIContext, m codec.Mar return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msgs...) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msgs...) } } -func newFundCommunityPoolHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { +func newFundCommunityPoolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - cliCtx = cliCtx.WithMarshaler(m) var req fundCommunityPoolReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { return @@ -204,7 +198,7 @@ func newFundCommunityPoolHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) } } diff --git a/x/distribution/module.go b/x/distribution/module.go index b350294214..1a7206ce1b 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -5,14 +5,13 @@ import ( "fmt" "math/rand" - cdctypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/gorilla/mux" "github.com/spf13/cobra" abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" @@ -63,12 +62,12 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessag // RegisterRESTRoutes registers the REST routes for the distribution module. func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { - rest.RegisterRoutes(ctx, rtr, StoreKey) + rest.RegisterHandlers(ctx, rtr) } // GetTxCmd returns the root tx command for the distribution module. -func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetTxCmd(StoreKey, cdc) +func (AppModuleBasic) GetTxCmd(ctx context.CLIContext) *cobra.Command { + return cli.NewTxCmd(ctx) } // GetQueryCmd returns the root query command for the distribution module. diff --git a/x/evidence/client/cli/tx.go b/x/evidence/client/cli/tx.go index c14c3d5d05..3ee0dcd963 100644 --- a/x/evidence/client/cli/tx.go +++ b/x/evidence/client/cli/tx.go @@ -2,8 +2,8 @@ package cli import ( "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/evidence/types" "github.com/spf13/cobra" @@ -14,7 +14,7 @@ import ( // modules, under a sub-command. This allows external modules to implement custom // Evidence types and Handlers while having the ability to create and sign txs // containing them all from a single root command. -func GetTxCmd(storeKey string, cdc *codec.Codec, childCmds []*cobra.Command) *cobra.Command { +func GetTxCmd(ctx context.CLIContext, childCmds []*cobra.Command) *cobra.Command { cmd := &cobra.Command{ Use: types.ModuleName, Short: "Evidence transaction subcommands", @@ -23,7 +23,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec, childCmds []*cobra.Command) *co RunE: client.ValidateCmd, } - submitEvidenceCmd := SubmitEvidenceCmd(cdc) + submitEvidenceCmd := SubmitEvidenceCmd(ctx) for _, childCmd := range childCmds { submitEvidenceCmd.AddCommand(flags.PostCommands(childCmd)[0]) } @@ -36,7 +36,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec, childCmds []*cobra.Command) *co // SubmitEvidenceCmd returns the top-level evidence submission command handler. // All concrete evidence submission child command handlers should be registered // under this command. -func SubmitEvidenceCmd(cdc *codec.Codec) *cobra.Command { +func SubmitEvidenceCmd(_ context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "submit", Short: "Submit arbitrary evidence of misbehavior", diff --git a/x/evidence/client/evidence_handler.go b/x/evidence/client/evidence_handler.go index 0b56b4c4cb..335894a567 100644 --- a/x/evidence/client/evidence_handler.go +++ b/x/evidence/client/evidence_handler.go @@ -4,7 +4,6 @@ import ( "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/evidence/client/rest" ) @@ -13,7 +12,7 @@ type ( RESTHandlerFn func(context.CLIContext) rest.EvidenceRESTHandler // CLIHandlerFn defines a CLI command handler for evidence submission - CLIHandlerFn func(*codec.Codec) *cobra.Command + CLIHandlerFn func(context.CLIContext) *cobra.Command // EvidenceHandler defines a type that exposes REST and CLI client handlers for // evidence submission. diff --git a/x/evidence/module.go b/x/evidence/module.go index 99a2174c4f..6e1380985c 100644 --- a/x/evidence/module.go +++ b/x/evidence/module.go @@ -82,14 +82,14 @@ func (a AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Rout } // GetTxCmd returns the evidence module's root tx command. -func (a AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { +func (a AppModuleBasic) GetTxCmd(ctx context.CLIContext) *cobra.Command { evidenceCLIHandlers := make([]*cobra.Command, len(a.evidenceHandlers)) for i, evidenceHandler := range a.evidenceHandlers { - evidenceCLIHandlers[i] = evidenceHandler.CLIHandler(cdc) + evidenceCLIHandlers[i] = evidenceHandler.CLIHandler(ctx) } - return cli.GetTxCmd(StoreKey, cdc, evidenceCLIHandlers) + return cli.GetTxCmd(ctx, evidenceCLIHandlers) } // GetTxCmd returns the evidence module's root query command. diff --git a/x/genutil/module.go b/x/genutil/module.go index 5853274f3b..11fd49381b 100644 --- a/x/genutil/module.go +++ b/x/genutil/module.go @@ -52,7 +52,7 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessag func (AppModuleBasic) RegisterRESTRoutes(_ context.CLIContext, _ *mux.Router) {} // GetTxCmd returns no root tx command for the genutil module. -func (AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil } +func (AppModuleBasic) GetTxCmd(_ context.CLIContext) *cobra.Command { return nil } // GetQueryCmd returns no root query command for the genutil module. func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil } diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index e35ccd4ae6..d36fbff839 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -1,24 +1,18 @@ package cli import ( - "bufio" "fmt" "strconv" "strings" - "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/auth" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client" govutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -58,11 +52,9 @@ var ProposalFlags = []string{ // to proposal type handlers that are implemented in other modules but are mounted // under the governance CLI (eg. parameter change proposals). func NewTxCmd( - cdc codec.Marshaler, - txg tx.Generator, - ar tx.AccountRetriever, - newMsgFn func() types.MsgSubmitProposalI, - pcmds []*cobra.Command) *cobra.Command { + ctx context.CLIContext, + pcmds []*cobra.Command, +) *cobra.Command { govTxCmd := &cobra.Command{ Use: types.ModuleName, Short: "Governance transactions subcommands", @@ -71,14 +63,14 @@ func NewTxCmd( RunE: client.ValidateCmd, } - cmdSubmitProp := NewCmdSubmitProposal(cdc, txg, ar, newMsgFn) + cmdSubmitProp := NewCmdSubmitProposal(ctx) for _, pcmd := range pcmds { cmdSubmitProp.AddCommand(flags.PostCommands(pcmd)[0]) } govTxCmd.AddCommand(flags.PostCommands( - NewCmdDeposit(cdc, txg, ar), - NewCmdVote(cdc, txg, ar), + NewCmdDeposit(ctx), + NewCmdVote(ctx), cmdSubmitProp, )...) @@ -86,11 +78,7 @@ func NewTxCmd( } // NewCmdSubmitProposal implements submitting a proposal transaction command. -func NewCmdSubmitProposal( - cdc codec.Marshaler, - txg tx.Generator, - ar tx.AccountRetriever, - newMsgFn func() types.MsgSubmitProposalI) *cobra.Command { +func NewCmdSubmitProposal(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "submit-proposal", Short: "Submit a proposal along with an initial deposit", @@ -118,9 +106,7 @@ $ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome pr ), ), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(cdc) - txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) proposal, err := parseSubmitProposalFlags() if err != nil { @@ -134,19 +120,16 @@ $ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome pr content := types.ContentFromProposalType(proposal.Title, proposal.Description, proposal.Type) - msg := newMsgFn() - err = msg.SetContent(content) + msg, err := types.NewMsgSubmitProposal(content, amount, cliCtx.FromAddress) if err != nil { return err } - msg.SetInitialDeposit(amount) - msg.SetProposer(cliCtx.FromAddress) if err = msg.ValidateBasic(); err != nil { return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } @@ -160,7 +143,7 @@ $ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome pr } // NewCmdDeposit implements depositing tokens for an active proposal. -func NewCmdDeposit(cdc codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewCmdDeposit(ctx context.CLIContext) *cobra.Command { return &cobra.Command{ Use: "deposit [proposal-id] [deposit]", Args: cobra.ExactArgs(2), @@ -176,9 +159,7 @@ $ %s tx gov deposit 1 10stake --from mykey ), ), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(cdc) - txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) // validate that the proposal id is a uint proposalID, err := strconv.ParseUint(args[0], 10, 64) @@ -201,13 +182,13 @@ $ %s tx gov deposit 1 10stake --from mykey return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } } // NewCmdVote implements creating a new vote command. -func NewCmdVote(cdc codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewCmdVote(ctx context.CLIContext) *cobra.Command { return &cobra.Command{ Use: "vote [proposal-id] [option]", Args: cobra.ExactArgs(2), @@ -224,9 +205,7 @@ $ %s tx gov vote 1 yes --from mykey ), ), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(cdc) - txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) // Get voting address from := cliCtx.GetFromAddress() @@ -250,197 +229,7 @@ $ %s tx gov vote 1 yes --from mykey return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) - }, - } -} - -// GetTxCmd returns the transaction commands for this module -// governance ModuleClient is slightly different from other ModuleClients in that -// it contains a slice of "proposal" child commands. These commands are respective -// to proposal type handlers that are implemented in other modules but are mounted -// under the governance CLI (eg. parameter change proposals). -func GetTxCmd(storeKey string, cdc *codec.Codec, pcmds []*cobra.Command) *cobra.Command { - govTxCmd := &cobra.Command{ - Use: types.ModuleName, - Short: "Governance transactions subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmdSubmitProp := GetCmdSubmitProposal(cdc) - for _, pcmd := range pcmds { - cmdSubmitProp.AddCommand(flags.PostCommands(pcmd)[0]) - } - - govTxCmd.AddCommand(flags.PostCommands( - GetCmdDeposit(cdc), - GetCmdVote(cdc), - cmdSubmitProp, - )...) - - return govTxCmd -} - -// GetCmdSubmitProposal implements submitting a proposal transaction command. -func GetCmdSubmitProposal(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "submit-proposal", - Short: "Submit a proposal along with an initial deposit", - Long: strings.TrimSpace( - fmt.Sprintf(`Submit a proposal along with an initial deposit. -Proposal title, description, type and deposit can be given directly or through a proposal JSON file. - -Example: -$ %s tx gov submit-proposal --proposal="path/to/proposal.json" --from mykey - -Where proposal.json contains: - -{ - "title": "Test Proposal", - "description": "My awesome proposal", - "type": "Text", - "deposit": "10test" -} - -Which is equivalent to: - -$ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="10test" --from mykey -`, - version.ClientName, version.ClientName, - ), - ), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - proposal, err := parseSubmitProposalFlags() - if err != nil { - return err - } - - amount, err := sdk.ParseCoins(proposal.Deposit) - if err != nil { - return err - } - - content := types.ContentFromProposalType(proposal.Title, proposal.Description, proposal.Type) - - msg, err := types.NewMsgSubmitProposal(content, amount, cliCtx.GetFromAddress()) - if err != nil { - return errors.Wrap(err, "can't create new MsgSubmitProposal") - } - if err := msg.ValidateBasic(); err != nil { - return err - } - - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } - - cmd.Flags().String(FlagTitle, "", "title of proposal") - cmd.Flags().String(FlagDescription, "", "description of proposal") - cmd.Flags().String(flagProposalType, "", "proposalType of proposal, types: text/parameter_change/software_upgrade") - cmd.Flags().String(FlagDeposit, "", "deposit of proposal") - cmd.Flags().String(FlagProposal, "", "proposal file path (if this path is given, other proposal flags are ignored)") - - return cmd -} - -// GetCmdDeposit implements depositing tokens for an active proposal. -func GetCmdDeposit(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "deposit [proposal-id] [deposit]", - Args: cobra.ExactArgs(2), - Short: "Deposit tokens for an active proposal", - Long: strings.TrimSpace( - fmt.Sprintf(`Submit a deposit for an active proposal. You can -find the proposal-id by running "%s query gov proposals". - -Example: -$ %s tx gov deposit 1 10stake --from mykey -`, - version.ClientName, version.ClientName, - ), - ), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - // validate that the proposal id is a uint - proposalID, err := strconv.ParseUint(args[0], 10, 64) - if err != nil { - return fmt.Errorf("proposal-id %s not a valid uint, please input a valid proposal-id", args[0]) - } - - // Get depositor address - from := cliCtx.GetFromAddress() - - // Get amount of coins - amount, err := sdk.ParseCoins(args[1]) - if err != nil { - return err - } - - msg := types.NewMsgDeposit(from, proposalID, amount) - err = msg.ValidateBasic() - if err != nil { - return err - } - - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } -} - -// GetCmdVote implements creating a new vote command. -func GetCmdVote(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "vote [proposal-id] [option]", - Args: cobra.ExactArgs(2), - Short: "Vote for an active proposal, options: yes/no/no_with_veto/abstain", - Long: strings.TrimSpace( - fmt.Sprintf(`Submit a vote for an active proposal. You can -find the proposal-id by running "%s query gov proposals". - - -Example: -$ %s tx gov vote 1 yes --from mykey -`, - version.ClientName, version.ClientName, - ), - ), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - // Get voting address - from := cliCtx.GetFromAddress() - - // validate that the proposal id is a uint - proposalID, err := strconv.ParseUint(args[0], 10, 64) - if err != nil { - return fmt.Errorf("proposal-id %s not a valid int, please input a valid proposal-id", args[0]) - } - - // Find out which vote option user chose - byteVoteOption, err := types.VoteOptionFromString(govutils.NormalizeVoteOption(args[1])) - if err != nil { - return err - } - - // Build vote message and run basic validation - msg := types.NewMsgVote(from, proposalID, byteVoteOption) - err = msg.ValidateBasic() - if err != nil { - return err - } - - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } } diff --git a/x/gov/client/proposal_handler.go b/x/gov/client/proposal_handler.go index cdfc0115e0..10de527db6 100644 --- a/x/gov/client/proposal_handler.go +++ b/x/gov/client/proposal_handler.go @@ -4,7 +4,6 @@ import ( "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/gov/client/rest" ) @@ -12,7 +11,7 @@ import ( type RESTHandlerFn func(context.CLIContext) rest.ProposalRESTHandler // function to create the cli handler -type CLIHandlerFn func(*codec.Codec) *cobra.Command +type CLIHandlerFn func(context.CLIContext) *cobra.Command // The combined type for a proposal handler for both cli and rest type ProposalHandler struct { diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 0522566dde..f56222da76 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -3,9 +3,6 @@ package rest import ( "net/http" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" @@ -31,14 +28,9 @@ type ProposalRESTHandler struct { Handler func(http.ResponseWriter, *http.Request) } -func RegisterHandlers( - cliCtx context.CLIContext, - txg tx.Generator, - r *mux.Router, - newMsgFn func() types.MsgSubmitProposalI, - phs []ProposalRESTHandler) { +func RegisterHandlers(cliCtx context.CLIContext, r *mux.Router, phs []ProposalRESTHandler) { registerQueryRoutes(cliCtx, r) - registerTxHandlers(cliCtx, txg, r, newMsgFn, phs) + registerTxHandlers(cliCtx, r, phs) } // RegisterRoutes - Central function to define routes that get registered by the main application diff --git a/x/gov/client/rest/tx.go b/x/gov/client/rest/tx.go index 5fc94d1e8e..e40f107cf8 100644 --- a/x/gov/client/rest/tx.go +++ b/x/gov/client/rest/tx.go @@ -15,18 +15,18 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov/types" ) -func registerTxHandlers(cliCtx context.CLIContext, txg tx.Generator, r *mux.Router, newMsgFn func() types.MsgSubmitProposalI, phs []ProposalRESTHandler) { +func registerTxHandlers(cliCtx context.CLIContext, r *mux.Router, phs []ProposalRESTHandler) { propSubRtr := r.PathPrefix("/gov/proposals").Subrouter() for _, ph := range phs { propSubRtr.HandleFunc(fmt.Sprintf("/%s", ph.SubRoute), ph.Handler).Methods("POST") } - r.HandleFunc("/gov/proposals", newPostProposalHandlerFn(cliCtx, txg, newMsgFn)).Methods("POST") - r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), newDepositHandlerFn(cliCtx, txg)).Methods("POST") - r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), newVoteHandlerFn(cliCtx, txg)).Methods("POST") + r.HandleFunc("/gov/proposals", newPostProposalHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), newDepositHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), newVoteHandlerFn(cliCtx)).Methods("POST") } -func newPostProposalHandlerFn(cliCtx context.CLIContext, txg tx.Generator, newMsgFn func() types.MsgSubmitProposalI) http.HandlerFunc { +func newPostProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req PostProposalReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { @@ -41,22 +41,19 @@ func newPostProposalHandlerFn(cliCtx context.CLIContext, txg tx.Generator, newMs proposalType := gcutils.NormalizeProposalType(req.ProposalType) content := types.ContentFromProposalType(req.Title, req.Description, proposalType) - msg := newMsgFn() - err := msg.SetContent(content) + msg, err := types.NewMsgSubmitProposal(content, req.InitialDeposit, req.Proposer) if rest.CheckBadRequestError(w, err) { return } - msg.SetInitialDeposit(req.InitialDeposit) - msg.SetProposer(req.Proposer) if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) } } -func newDepositHandlerFn(cliCtx context.CLIContext, txg tx.Generator) http.HandlerFunc { +func newDepositHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) strProposalID := vars[RestProposalID] @@ -87,11 +84,11 @@ func newDepositHandlerFn(cliCtx context.CLIContext, txg tx.Generator) http.Handl return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) } } -func newVoteHandlerFn(cliCtx context.CLIContext, txg tx.Generator) http.HandlerFunc { +func newVoteHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) strProposalID := vars[RestProposalID] @@ -127,7 +124,7 @@ func newVoteHandlerFn(cliCtx context.CLIContext, txg tx.Generator) http.HandlerF return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) } } diff --git a/x/gov/module.go b/x/gov/module.go index 54d7e3817c..9a47a3c9cc 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -78,18 +78,17 @@ func (a AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Rout proposalRESTHandlers = append(proposalRESTHandlers, proposalHandler.RESTHandler(ctx)) } - rest.RegisterRoutes(ctx, rtr, proposalRESTHandlers) + rest.RegisterHandlers(ctx, rtr, proposalRESTHandlers) } // GetTxCmd returns the root tx command for the gov module. -func (a AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { - +func (a AppModuleBasic) GetTxCmd(ctx context.CLIContext) *cobra.Command { proposalCLIHandlers := make([]*cobra.Command, 0, len(a.proposalHandlers)) for _, proposalHandler := range a.proposalHandlers { - proposalCLIHandlers = append(proposalCLIHandlers, proposalHandler.CLIHandler(cdc)) + proposalCLIHandlers = append(proposalCLIHandlers, proposalHandler.CLIHandler(ctx)) } - return cli.GetTxCmd(StoreKey, cdc, proposalCLIHandlers) + return cli.NewTxCmd(ctx, proposalCLIHandlers) } // GetQueryCmd returns the root query command for the gov module. diff --git a/x/ibc-transfer/module.go b/x/ibc-transfer/module.go index cca17d18d0..2aa0b7dd60 100644 --- a/x/ibc-transfer/module.go +++ b/x/ibc-transfer/module.go @@ -70,8 +70,8 @@ func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router } // GetTxCmd implements AppModuleBasic interface -func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetTxCmd(cdc) +func (AppModuleBasic) GetTxCmd(ctx context.CLIContext) *cobra.Command { + return cli.GetTxCmd(ctx.Codec) } // GetQueryCmd implements AppModuleBasic interface diff --git a/x/ibc/module.go b/x/ibc/module.go index 84bea0207b..bac0447cae 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -66,8 +66,8 @@ func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router } // GetTxCmd returns the root tx command for the ibc module. -func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetTxCmd(StoreKey, cdc) +func (AppModuleBasic) GetTxCmd(ctx context.CLIContext) *cobra.Command { + return cli.GetTxCmd(StoreKey, ctx.Codec) } // GetQueryCmd returns no root query command for the ibc module. diff --git a/x/mint/module.go b/x/mint/module.go index 34a75f991a..1c8f1765b7 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -63,7 +63,7 @@ func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router } // GetTxCmd returns no root tx command for the mint module. -func (AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil } +func (AppModuleBasic) GetTxCmd(_ context.CLIContext) *cobra.Command { return nil } // GetQueryCmd returns the root query command for the mint module. func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { diff --git a/x/params/client/cli/query.go b/x/params/client/cli/query.go index 39a7390d04..2db5814728 100644 --- a/x/params/client/cli/query.go +++ b/x/params/client/cli/query.go @@ -13,7 +13,7 @@ import ( ) // NewQueryCmd returns a root CLI command handler for all x/params query commands. -func NewQueryCmd(m codec.Marshaler) *cobra.Command { +func NewQueryCmd(m codec.JSONMarshaler) *cobra.Command { cmd := &cobra.Command{ Use: types.ModuleName, Short: "Querying commands for the params module", @@ -29,13 +29,13 @@ func NewQueryCmd(m codec.Marshaler) *cobra.Command { // NewQuerySubspaceParamsCmd returns a CLI command handler for querying subspace // parameters managed by the x/params module. -func NewQuerySubspaceParamsCmd(m codec.Marshaler) *cobra.Command { +func NewQuerySubspaceParamsCmd(m codec.JSONMarshaler) *cobra.Command { cmd := &cobra.Command{ Use: "subspace [subspace] [key]", Short: "Query for raw parameters by subspace and key", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - cliCtx := context.NewCLIContext().WithMarshaler(m) + cliCtx := context.NewCLIContext().WithJSONMarshaler(m) params := types.NewQuerySubspaceParams(args[0], args[1]) route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParams) diff --git a/x/params/client/cli/tx.go b/x/params/client/cli/tx.go index 839875f09b..a02ca0b316 100644 --- a/x/params/client/cli/tx.go +++ b/x/params/client/cli/tx.go @@ -1,7 +1,6 @@ package cli import ( - "bufio" "fmt" "strings" @@ -9,11 +8,8 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/auth" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" paramscutils "github.com/cosmos/cosmos-sdk/x/params/client/utils" paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" @@ -21,7 +17,7 @@ import ( // NewSubmitParamChangeProposalTxCmd returns a CLI command handler for creating // a parameter change proposal governance transaction. -func NewSubmitParamChangeProposalTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewSubmitParamChangeProposalTxCmd(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "param-change [proposal-file]", Args: cobra.ExactArgs(1), @@ -61,11 +57,9 @@ Where proposal.json contains: ), ), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) - txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) - proposal, err := paramscutils.ParseParamChangeProposalJSON(m, args[0]) + proposal, err := paramscutils.ParseParamChangeProposalJSON(ctx.JSONMarshaler, args[0]) if err != nil { return err } @@ -88,90 +82,7 @@ Where proposal.json contains: return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) - }, - } - - return cmd -} - -// --------------------------------------------------------------------------- -// Deprecated -// -// TODO: Remove once client-side Protobuf migration has been completed. -// --------------------------------------------------------------------------- - -// GetCmdSubmitProposal implements a command handler for submitting a parameter -// change proposal transaction. -// -// TODO: Remove once client-side Protobuf migration has been completed. -// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 -func GetCmdSubmitProposal(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "param-change [proposal-file]", - Args: cobra.ExactArgs(1), - Short: "Submit a parameter change proposal", - Long: strings.TrimSpace( - fmt.Sprintf(`Submit a parameter proposal along with an initial deposit. -The proposal details must be supplied via a JSON file. For values that contains -objects, only non-empty fields will be updated. - -IMPORTANT: Currently parameter changes are evaluated but not validated, so it is -very important that any "value" change is valid (ie. correct type and within bounds) -for its respective parameter, eg. "MaxValidators" should be an integer and not a decimal. - -Proper vetting of a parameter change proposal should prevent this from happening -(no deposits should occur during the governance process), but it should be noted -regardless. - -Example: -$ %s tx gov submit-proposal param-change --from= - -Where proposal.json contains: - -{ - "title": "Staking Param Change", - "description": "Update max validators", - "changes": [ - { - "subspace": "staking", - "key": "MaxValidators", - "value": 105 - } - ], - "deposit": "1000stake" -} -`, - version.ClientName, - ), - ), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - proposal, err := paramscutils.ParseParamChangeProposalJSON(cdc, args[0]) - if err != nil { - return err - } - - from := cliCtx.GetFromAddress() - content := paramproposal.NewParameterChangeProposal(proposal.Title, proposal.Description, proposal.Changes.ToParamChanges()) - - deposit, err := sdk.ParseCoins(proposal.Deposit) - if err != nil { - return err - } - - msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from) - if err != nil { - return err - } - if err := msg.ValidateBasic(); err != nil { - return err - } - - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } diff --git a/x/params/client/proposal_handler.go b/x/params/client/proposal_handler.go index dd93e9bdd2..77a672d89c 100644 --- a/x/params/client/proposal_handler.go +++ b/x/params/client/proposal_handler.go @@ -7,4 +7,4 @@ import ( ) // ProposalHandler is the param change proposal handler. -var ProposalHandler = govclient.NewProposalHandler(cli.GetCmdSubmitProposal, rest.ProposalRESTHandler) +var ProposalHandler = govclient.NewProposalHandler(cli.NewSubmitParamChangeProposalTxCmd, rest.ProposalRESTHandler) diff --git a/x/params/module.go b/x/params/module.go index 628b1c8365..9dab3b572f 100644 --- a/x/params/module.go +++ b/x/params/module.go @@ -50,7 +50,7 @@ func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, _ json.RawMessage) func (AppModuleBasic) RegisterRESTRoutes(_ context.CLIContext, _ *mux.Router) {} // GetTxCmd returns no root tx command for the params module. -func (AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil } +func (AppModuleBasic) GetTxCmd(_ context.CLIContext) *cobra.Command { return nil } // GetQueryCmd returns no root query command for the params module. func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index 0389cc6316..3cae546e09 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -1,23 +1,18 @@ package cli import ( - "bufio" - "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // NewTxCmd returns a root CLI command handler for all x/slashing transaction commands. -func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewTxCmd(ctx context.CLIContext) *cobra.Command { slashingTxCmd := &cobra.Command{ Use: types.ModuleName, Short: "Slashing transaction subcommands", @@ -26,11 +21,11 @@ func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobr RunE: client.ValidateCmd, } - slashingTxCmd.AddCommand(NewUnjailTxCmd(m, txg, ar)) + slashingTxCmd.AddCommand(NewUnjailTxCmd(ctx)) return slashingTxCmd } -func NewUnjailTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewUnjailTxCmd(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "unjail", Args: cobra.NoArgs, @@ -40,12 +35,7 @@ func NewUnjailTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) $ tx slashing unjail --from mykey `, RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txf := tx.NewFactoryFromCLI(inBuf). - WithTxGenerator(txg). - WithAccountRetriever(ar) - - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) valAddr := cliCtx.GetFromAddress() msg := types.NewMsgUnjail(sdk.ValAddress(valAddr)) @@ -53,60 +43,8 @@ $ tx slashing unjail --from mykey return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } return flags.PostCommands(cmd)[0] } - -// --------------------------------------------------------------------------- -// Deprecated -// -// TODO: Remove once client-side Protobuf migration has been completed. -// --------------------------------------------------------------------------- - -// GetTxCmd returns the transaction commands for this module -// -// TODO: Remove once client-side Protobuf migration has been completed. -// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 -func GetTxCmd(cdc *codec.Codec) *cobra.Command { - slashingTxCmd := &cobra.Command{ - Use: types.ModuleName, - Short: "Slashing transactions subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - slashingTxCmd.AddCommand(flags.PostCommands( - GetCmdUnjail(cdc), - )...) - - return slashingTxCmd -} - -// GetCmdUnjail implements the create unjail validator command. -// -// TODO: Remove once client-side Protobuf migration has been completed. -// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 -func GetCmdUnjail(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "unjail", - Args: cobra.NoArgs, - Short: "unjail validator previously jailed for downtime", - Long: `unjail a jailed validator: - -$ tx slashing unjail --from mykey -`, - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - valAddr := cliCtx.GetFromAddress() - - msg := types.NewMsgUnjail(sdk.ValAddress(valAddr)) - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } -} diff --git a/x/slashing/client/rest/rest.go b/x/slashing/client/rest/rest.go index d4c500f84c..32515fbe4f 100644 --- a/x/slashing/client/rest/rest.go +++ b/x/slashing/client/rest/rest.go @@ -4,13 +4,11 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" ) -func RegisterHandlers(ctx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { +func RegisterHandlers(ctx context.CLIContext, r *mux.Router) { registerQueryRoutes(ctx, r) - registerTxHandlers(ctx, m, txg, r) + registerTxHandlers(ctx, r) } // RegisterRoutes registers staking-related REST handlers to a router diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index dba316db84..e01536b3e3 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -8,15 +8,14 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/slashing/types" ) -func registerTxHandlers(ctx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { - r.HandleFunc("/slashing/validators/{validatorAddr}/unjail", NewUnjailRequestHandlerFn(ctx, m, txg)).Methods("POST") +func registerTxHandlers(ctx context.CLIContext, r *mux.Router) { + r.HandleFunc("/slashing/validators/{validatorAddr}/unjail", NewUnjailRequestHandlerFn(ctx)).Methods("POST") } // Unjail TX body @@ -26,14 +25,13 @@ type UnjailReq struct { // NewUnjailRequestHandlerFn returns an HTTP REST handler for creating a MsgUnjail // transaction. -func NewUnjailRequestHandlerFn(ctx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { +func NewUnjailRequestHandlerFn(ctx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - ctx = ctx.WithMarshaler(m) vars := mux.Vars(r) bech32Validator := vars["validatorAddr"] var req UnjailReq - if !rest.ReadRESTReq(w, r, ctx.Marshaler, &req) { + if !rest.ReadRESTReq(w, r, ctx.JSONMarshaler, &req) { return } @@ -61,7 +59,7 @@ func NewUnjailRequestHandlerFn(ctx context.CLIContext, m codec.Marshaler, txg tx if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } - tx.WriteGeneratedTxResponse(ctx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(ctx, w, req.BaseReq, msg) } } diff --git a/x/slashing/module.go b/x/slashing/module.go index 79730152e5..0bc65c296c 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -63,12 +63,12 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessag // RegisterRESTRoutes registers the REST routes for the slashing module. func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { - rest.RegisterRoutes(ctx, rtr) + rest.RegisterHandlers(ctx, rtr) } // GetTxCmd returns the root tx command for the slashing module. -func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetTxCmd(cdc) +func (AppModuleBasic) GetTxCmd(ctx context.CLIContext) *cobra.Command { + return cli.NewTxCmd(ctx) } // GetQueryCmd returns no root query command for the slashing module. diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index bac834fd51..c3c9c4b6e5 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -1,11 +1,12 @@ package cli import ( - "bufio" "fmt" "os" "strings" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/spf13/cobra" flag "github.com/spf13/pflag" "github.com/spf13/viper" @@ -17,11 +18,8 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/auth" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -37,7 +35,7 @@ var ( ) // NewTxCmd returns a root CLI command handler for all x/staking transaction commands. -func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewTxCmd(ctx context.CLIContext) *cobra.Command { stakingTxCmd := &cobra.Command{ Use: types.ModuleName, Short: "Staking transaction subcommands", @@ -47,33 +45,29 @@ func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobr } stakingTxCmd.AddCommand(flags.PostCommands( - NewCreateValidatorCmd(m, txg, ar), - NewEditValidatorCmd(m, txg, ar), - NewDelegateCmd(m, txg, ar), - NewRedelegateCmd(m, txg, ar), - NewUnbondCmd(m, txg, ar), + NewCreateValidatorCmd(ctx), + NewEditValidatorCmd(ctx), + NewDelegateCmd(ctx), + NewRedelegateCmd(ctx), + NewUnbondCmd(ctx), )...) return stakingTxCmd } -func NewCreateValidatorCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewCreateValidatorCmd(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "create-validator", Short: "create new validator initialized with a self-delegation to it", RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txf := tx.NewFactoryFromCLI(inBuf). - WithTxGenerator(txg). - WithAccountRetriever(ar) - - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) + txf := tx.NewFactoryFromCLI(ctx.Input).WithTxGenerator(ctx.TxGenerator).WithAccountRetriever(ctx.AccountRetriever) txf, msg, err := NewBuildCreateValidatorMsg(cliCtx, txf) if err != nil { return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTxWithFactory(cliCtx, txf, msg) }, } cmd.Flags().AddFlagSet(FsPk) @@ -90,20 +84,15 @@ func NewCreateValidatorCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRet _ = cmd.MarkFlagRequired(FlagPubKey) _ = cmd.MarkFlagRequired(FlagMoniker) - return flags.PostCommands(cmd)[0] + return cmd } -func NewEditValidatorCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewEditValidatorCmd(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "edit-validator", Short: "edit an existing validator account", RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txf := tx.NewFactoryFromCLI(inBuf). - WithTxGenerator(txg). - WithAccountRetriever(ar) - - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) valAddr := cliCtx.GetFromAddress() description := types.NewDescription( @@ -144,14 +133,14 @@ func NewEditValidatorCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetri } // build and sign the transaction, then broadcast to Tendermint - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } - return flags.PostCommands(cmd)[0] + return cmd } -func NewDelegateCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewDelegateCmd(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "delegate [validator-addr] [amount]", Args: cobra.ExactArgs(2), @@ -166,12 +155,7 @@ $ %s tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 10 ), ), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txf := tx.NewFactoryFromCLI(inBuf). - WithTxGenerator(txg). - WithAccountRetriever(ar) - - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) amount, err := sdk.ParseCoin(args[1]) if err != nil { @@ -189,17 +173,17 @@ $ %s tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 10 return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } cmd.Flags().AddFlagSet(fsDescriptionEdit) cmd.Flags().AddFlagSet(fsCommissionUpdate) cmd.Flags().AddFlagSet(FsMinSelfDelegation) - return flags.PostCommands(cmd)[0] + return cmd } -func NewRedelegateCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewRedelegateCmd(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "redelegate [src-validator-addr] [dst-validator-addr] [amount]", Short: "Redelegate illiquid tokens from one validator to another", @@ -214,12 +198,8 @@ $ %s tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj ), ), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txf := tx.NewFactoryFromCLI(inBuf). - WithTxGenerator(txg). - WithAccountRetriever(ar) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) delAddr := cliCtx.GetFromAddress() valSrcAddr, err := sdk.ValAddressFromBech32(args[0]) if err != nil { @@ -241,14 +221,14 @@ $ %s tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } - return flags.PostCommands(cmd)[0] + return cmd } -func NewUnbondCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command { +func NewUnbondCmd(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "unbond [validator-addr] [amount]", Short: "Unbond shares from a validator", @@ -263,12 +243,7 @@ $ %s tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100s ), ), RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txf := tx.NewFactoryFromCLI(inBuf). - WithTxGenerator(txg). - WithAccountRetriever(ar) - - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) delAddr := cliCtx.GetFromAddress() valAddr, err := sdk.ValAddressFromBech32(args[0]) @@ -286,11 +261,11 @@ $ %s tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100s return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } - return flags.PostCommands(cmd)[0] + return cmd } func NewBuildCreateValidatorMsg(cliCtx context.CLIContext, txf tx.Factory) (tx.Factory, sdk.Msg, error) { @@ -432,247 +407,6 @@ func PrepareFlagsForTxCreateValidator( } } -// --------------------------------------------------------------------------- -// Deprecated -// -// TODO: Remove once client-side Protobuf migration has been completed. -// --------------------------------------------------------------------------- - -// GetTxCmd returns the transaction commands for this module -// -// TODO: Remove once client-side Protobuf migration has been completed. -// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 -// GetTxCmd returns the transaction commands for this module -func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - stakingTxCmd := &cobra.Command{ - Use: types.ModuleName, - Short: "Staking transaction subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - stakingTxCmd.AddCommand(flags.PostCommands( - GetCmdCreateValidator(cdc), - GetCmdEditValidator(cdc), - GetCmdDelegate(cdc), - GetCmdRedelegate(storeKey, cdc), - GetCmdUnbond(storeKey, cdc), - )...) - - return stakingTxCmd -} - -// GetCmdCreateValidator implements the create validator command handler. -func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "create-validator", - Short: "create new validator initialized with a self-delegation to it", - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - txBldr, msg, err := BuildCreateValidatorMsg(cliCtx, txBldr) - if err != nil { - return err - } - - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } - - cmd.Flags().AddFlagSet(FsPk) - cmd.Flags().AddFlagSet(FsAmount) - cmd.Flags().AddFlagSet(fsDescriptionCreate) - cmd.Flags().AddFlagSet(FsCommissionCreate) - cmd.Flags().AddFlagSet(FsMinSelfDelegation) - - cmd.Flags().String(FlagIP, "", fmt.Sprintf("The node's public IP. It takes effect only when used in combination with --%s", flags.FlagGenerateOnly)) - cmd.Flags().String(FlagNodeID, "", "The node's ID") - - _ = cmd.MarkFlagRequired(flags.FlagFrom) - _ = cmd.MarkFlagRequired(FlagAmount) - _ = cmd.MarkFlagRequired(FlagPubKey) - _ = cmd.MarkFlagRequired(FlagMoniker) - - return cmd -} - -// GetCmdEditValidator implements the create edit validator command. -// TODO: add full description -func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "edit-validator", - Short: "edit an existing validator account", - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - valAddr := cliCtx.GetFromAddress() - description := types.NewDescription( - viper.GetString(FlagMoniker), - viper.GetString(FlagIdentity), - viper.GetString(FlagWebsite), - viper.GetString(FlagSecurityContact), - viper.GetString(FlagDetails), - ) - - var newRate *sdk.Dec - - commissionRate := viper.GetString(FlagCommissionRate) - if commissionRate != "" { - rate, err := sdk.NewDecFromStr(commissionRate) - if err != nil { - return fmt.Errorf("invalid new commission rate: %v", err) - } - - newRate = &rate - } - - var newMinSelfDelegation *sdk.Int - - minSelfDelegationString := viper.GetString(FlagMinSelfDelegation) - if minSelfDelegationString != "" { - msb, ok := sdk.NewIntFromString(minSelfDelegationString) - if !ok { - return types.ErrMinSelfDelegationInvalid - } - - newMinSelfDelegation = &msb - } - - msg := types.NewMsgEditValidator(sdk.ValAddress(valAddr), description, newRate, newMinSelfDelegation) - - // build and sign the transaction, then broadcast to Tendermint - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } - - cmd.Flags().AddFlagSet(fsDescriptionEdit) - cmd.Flags().AddFlagSet(fsCommissionUpdate) - cmd.Flags().AddFlagSet(FsMinSelfDelegation) - - return cmd -} - -// GetCmdDelegate implements the delegate command. -func GetCmdDelegate(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "delegate [validator-addr] [amount]", - Args: cobra.ExactArgs(2), - Short: "Delegate liquid tokens to a validator", - Long: strings.TrimSpace( - fmt.Sprintf(`Delegate an amount of liquid coins to a validator from your wallet. - -Example: -$ %s tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 1000stake --from mykey -`, - version.ClientName, - ), - ), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - amount, err := sdk.ParseCoin(args[1]) - if err != nil { - return err - } - - delAddr := cliCtx.GetFromAddress() - valAddr, err := sdk.ValAddressFromBech32(args[0]) - if err != nil { - return err - } - - msg := types.NewMsgDelegate(delAddr, valAddr, amount) - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } -} - -// GetCmdRedelegate the begin redelegation command. -func GetCmdRedelegate(storeName string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "redelegate [src-validator-addr] [dst-validator-addr] [amount]", - Short: "Redelegate illiquid tokens from one validator to another", - Args: cobra.ExactArgs(3), - Long: strings.TrimSpace( - fmt.Sprintf(`Redelegate an amount of illiquid staking tokens from one validator to another. - -Example: -$ %s tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 100stake --from mykey -`, - version.ClientName, - ), - ), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - delAddr := cliCtx.GetFromAddress() - valSrcAddr, err := sdk.ValAddressFromBech32(args[0]) - if err != nil { - return err - } - - valDstAddr, err := sdk.ValAddressFromBech32(args[1]) - if err != nil { - return err - } - - amount, err := sdk.ParseCoin(args[2]) - if err != nil { - return err - } - - msg := types.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, amount) - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } -} - -// GetCmdUnbond implements the unbond validator command. -func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "unbond [validator-addr] [amount]", - Short: "Unbond shares from a validator", - Args: cobra.ExactArgs(2), - Long: strings.TrimSpace( - fmt.Sprintf(`Unbond an amount of bonded shares from a validator. - -Example: -$ %s tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from mykey -`, - version.ClientName, - ), - ), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - - delAddr := cliCtx.GetFromAddress() - valAddr, err := sdk.ValAddressFromBech32(args[0]) - if err != nil { - return err - } - - amount, err := sdk.ParseCoin(args[1]) - if err != nil { - return err - } - - msg := types.NewMsgUndelegate(delAddr, valAddr, amount) - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } -} - // BuildCreateValidatorMsg makes a new MsgCreateValidator. func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr auth.TxBuilder) (auth.TxBuilder, sdk.Msg, error) { amounstStr := viper.GetString(FlagAmount) diff --git a/x/staking/client/rest/rest.go b/x/staking/client/rest/rest.go index b43cf152c6..e112341e9f 100644 --- a/x/staking/client/rest/rest.go +++ b/x/staking/client/rest/rest.go @@ -4,13 +4,11 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" ) -func RegisterHandlers(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { +func RegisterHandlers(cliCtx context.CLIContext, r *mux.Router) { registerQueryRoutes(cliCtx, r) - registerTxHandlers(cliCtx, m, txg, r) + registerTxHandlers(cliCtx, r) } // RegisterRoutes registers staking-related REST handlers to a router diff --git a/x/staking/client/rest/tx.go b/x/staking/client/rest/tx.go index 812709e0a0..965cf3da47 100644 --- a/x/staking/client/rest/tx.go +++ b/x/staking/client/rest/tx.go @@ -8,25 +8,24 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/staking/types" ) -func registerTxHandlers(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router) { +func registerTxHandlers(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc( "/staking/delegators/{delegatorAddr}/delegations", - newPostDelegationsHandlerFn(cliCtx, m, txg), + newPostDelegationsHandlerFn(cliCtx), ).Methods("POST") r.HandleFunc( "/staking/delegators/{delegatorAddr}/unbonding_delegations", - newPostUnbondingDelegationsHandlerFn(cliCtx, m, txg), + newPostUnbondingDelegationsHandlerFn(cliCtx), ).Methods("POST") r.HandleFunc( "/staking/delegators/{delegatorAddr}/redelegations", - newPostRedelegationsHandlerFn(cliCtx, m, txg), + newPostRedelegationsHandlerFn(cliCtx), ).Methods("POST") } @@ -57,10 +56,8 @@ type ( } ) -func newPostDelegationsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { +func newPostDelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - cliCtx = cliCtx.WithMarshaler(m) - var req DelegateRequest if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { return @@ -86,14 +83,12 @@ func newPostDelegationsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, t return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) } } -func newPostRedelegationsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { +func newPostRedelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - cliCtx = cliCtx.WithMarshaler(m) - var req RedelegateRequest if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { return @@ -119,14 +114,12 @@ func newPostRedelegationsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) } } -func newPostUnbondingDelegationsHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator) http.HandlerFunc { +func newPostUnbondingDelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - cliCtx = cliCtx.WithMarshaler(m) - var req UndelegateRequest if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { return @@ -152,7 +145,7 @@ func newPostUnbondingDelegationsHandlerFn(cliCtx context.CLIContext, m codec.Mar return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) } } diff --git a/x/staking/module.go b/x/staking/module.go index 721e66bdd0..4d6c9fc6f8 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -66,12 +66,12 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessag // RegisterRESTRoutes registers the REST routes for the staking module. func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { - rest.RegisterRoutes(ctx, rtr) + rest.RegisterHandlers(ctx, rtr) } // GetTxCmd returns the root tx command for the staking module. -func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetTxCmd(StoreKey, cdc) +func (AppModuleBasic) GetTxCmd(ctx context.CLIContext) *cobra.Command { + return cli.NewTxCmd(ctx) } // GetQueryCmd returns no root query command for the staking module. diff --git a/x/upgrade/client/cli/tx.go b/x/upgrade/client/cli/tx.go index cf302463ea..218399ce8b 100644 --- a/x/upgrade/client/cli/tx.go +++ b/x/upgrade/client/cli/tx.go @@ -1,22 +1,18 @@ package cli import ( - "bufio" "fmt" "time" "github.com/cosmos/cosmos-sdk/client/tx" gov "github.com/cosmos/cosmos-sdk/x/gov/types" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/gov/client/cli" "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) @@ -30,10 +26,7 @@ const ( ) // NewCmdSubmitUpgradeProposal implements a command handler for submitting a software upgrade proposal transaction. -func NewCmdSubmitUpgradeProposal( - m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever, - newMsgFn func() gov.MsgSubmitProposalI, -) *cobra.Command { +func NewCmdSubmitUpgradeProposal(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "software-upgrade [name] (--upgrade-height [height] | --upgrade-time [time]) (--upgrade-info [info]) [flags]", @@ -49,9 +42,7 @@ func NewCmdSubmitUpgradeProposal( return err } - inBuf := bufio.NewReader(cmd.InOrStdin()) - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) - txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) from := cliCtx.GetFromAddress() depositStr, err := cmd.Flags().GetString(cli.FlagDeposit) @@ -63,19 +54,16 @@ func NewCmdSubmitUpgradeProposal( return err } - msg := newMsgFn() - err = msg.SetContent(content) + msg, err := gov.NewMsgSubmitProposal(content, deposit, from) if err != nil { return err } - msg.SetInitialDeposit(deposit) - msg.SetProposer(from) if err = msg.ValidateBasic(); err != nil { return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } @@ -90,20 +78,14 @@ func NewCmdSubmitUpgradeProposal( } // NewCmdSubmitCancelUpgradeProposal implements a command handler for submitting a software upgrade cancel proposal transaction. -func NewCmdSubmitCancelUpgradeProposal( - m codec.Marshaler, - txg tx.Generator, - ar tx.AccountRetriever, - newMsgFn func() gov.MsgSubmitProposalI) *cobra.Command { +func NewCmdSubmitCancelUpgradeProposal(ctx context.CLIContext) *cobra.Command { cmd := &cobra.Command{ Use: "cancel-software-upgrade [flags]", Args: cobra.ExactArgs(0), Short: "Submit a software upgrade proposal", Long: "Cancel a software upgrade along with an initial deposit.", RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) - txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) + cliCtx := ctx.InitWithInput(cmd.InOrStdin()) from := cliCtx.GetFromAddress() depositStr, err := cmd.Flags().GetString(cli.FlagDeposit) @@ -128,19 +110,16 @@ func NewCmdSubmitCancelUpgradeProposal( content := types.NewCancelSoftwareUpgradeProposal(title, description) - msg := newMsgFn() - err = msg.SetContent(content) + msg, err := gov.NewMsgSubmitProposal(content, deposit, from) if err != nil { return err } - msg.SetInitialDeposit(deposit) - msg.SetProposer(from) if err = msg.ValidateBasic(); err != nil { return err } - return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + return tx.GenerateOrBroadcastTx(cliCtx, msg) }, } @@ -193,108 +172,3 @@ func parseArgsToContent(cmd *cobra.Command, name string) (gov.Content, error) { content := types.NewSoftwareUpgradeProposal(title, description, plan) return content, nil } - -// GetCmdSubmitUpgradeProposal implements a command handler for submitting a software upgrade proposal transaction. -func GetCmdSubmitUpgradeProposal(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "software-upgrade [name] (--upgrade-height [height] | --upgrade-time [time]) (--upgrade-info [info]) [flags]", - Args: cobra.ExactArgs(1), - Short: "Submit a software upgrade proposal", - Long: "Submit a software upgrade along with an initial deposit.\n" + - "Please specify a unique name and height OR time for the upgrade to take effect.\n" + - "You may include info to reference a binary download link, in a format compatible with: https://github.com/regen-network/cosmosd", - RunE: func(cmd *cobra.Command, args []string) error { - name := args[0] - content, err := parseArgsToContent(cmd, name) - if err != nil { - return err - } - - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - from := cliCtx.GetFromAddress() - - depositStr, err := cmd.Flags().GetString(cli.FlagDeposit) - if err != nil { - return err - } - deposit, err := sdk.ParseCoins(depositStr) - if err != nil { - return err - } - - msg, err := gov.NewMsgSubmitProposal(content, deposit, from) - if err != nil { - return err - } - if err := msg.ValidateBasic(); err != nil { - return err - } - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } - - cmd.Flags().String(cli.FlagTitle, "", "title of proposal") - cmd.Flags().String(cli.FlagDescription, "", "description of proposal") - cmd.Flags().String(cli.FlagDeposit, "", "deposit of proposal") - cmd.Flags().Int64(FlagUpgradeHeight, 0, "The height at which the upgrade must happen (not to be used together with --upgrade-time)") - cmd.Flags().String(FlagUpgradeTime, "", fmt.Sprintf("The time at which the upgrade must happen (ex. %s) (not to be used together with --upgrade-height)", TimeFormat)) - cmd.Flags().String(FlagUpgradeInfo, "", "Optional info for the planned upgrade such as commit hash, etc.") - - return cmd -} - -// GetCmdSubmitCancelUpgradeProposal implements a command handler for submitting a software upgrade cancel proposal transaction. -func GetCmdSubmitCancelUpgradeProposal(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "cancel-software-upgrade [flags]", - Args: cobra.ExactArgs(0), - Short: "Submit a software upgrade proposal", - Long: "Cancel a software upgrade along with an initial deposit.", - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) - from := cliCtx.GetFromAddress() - - depositStr, err := cmd.Flags().GetString(cli.FlagDeposit) - if err != nil { - return err - } - - deposit, err := sdk.ParseCoins(depositStr) - if err != nil { - return err - } - - title, err := cmd.Flags().GetString(cli.FlagTitle) - if err != nil { - return err - } - - description, err := cmd.Flags().GetString(cli.FlagDescription) - if err != nil { - return err - } - - content := types.NewCancelSoftwareUpgradeProposal(title, description) - - msg, err := gov.NewMsgSubmitProposal(content, deposit, from) - if err != nil { - return err - } - if err := msg.ValidateBasic(); err != nil { - return err - } - - return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } - - cmd.Flags().String(cli.FlagTitle, "", "title of proposal") - cmd.Flags().String(cli.FlagDescription, "", "description of proposal") - cmd.Flags().String(cli.FlagDeposit, "", "deposit of proposal") - - return cmd -} diff --git a/x/upgrade/client/proposal_handler.go b/x/upgrade/client/proposal_handler.go index 314c8ac587..7cf0f9d778 100644 --- a/x/upgrade/client/proposal_handler.go +++ b/x/upgrade/client/proposal_handler.go @@ -6,4 +6,4 @@ import ( "github.com/cosmos/cosmos-sdk/x/upgrade/client/rest" ) -var ProposalHandler = govclient.NewProposalHandler(cli.GetCmdSubmitUpgradeProposal, rest.ProposalRESTHandler) +var ProposalHandler = govclient.NewProposalHandler(cli.NewCmdSubmitUpgradeProposal, rest.ProposalRESTHandler) diff --git a/x/upgrade/client/rest/tx.go b/x/upgrade/client/rest/tx.go index 3e0ab0119a..656f492d86 100644 --- a/x/upgrade/client/rest/tx.go +++ b/x/upgrade/client/rest/tx.go @@ -21,7 +21,7 @@ import ( // nolint func newRegisterTxRoutes( cliCtx context.CLIContext, - txg tx.Generator, + txg context.TxGenerator, newMsgFn func() gov.MsgSubmitProposalI, r *mux.Router) { r.HandleFunc("/upgrade/plan", newPostPlanHandler(cliCtx, txg, newMsgFn)).Methods("POST") @@ -61,7 +61,7 @@ func ProposalRESTHandler(cliCtx context.CLIContext) govrest.ProposalRESTHandler } // nolint -func newPostPlanHandler(cliCtx context.CLIContext, txg tx.Generator, newMsgFn func() gov.MsgSubmitProposalI) http.HandlerFunc { +func newPostPlanHandler(cliCtx context.CLIContext, txg context.TxGenerator, newMsgFn func() gov.MsgSubmitProposalI) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req PlanRequest @@ -101,12 +101,12 @@ func newPostPlanHandler(cliCtx context.CLIContext, txg tx.Generator, newMsgFn fu return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) } } // nolint -func newCancelPlanHandler(cliCtx context.CLIContext, txg tx.Generator, newMsgFn func() gov.MsgSubmitProposalI) http.HandlerFunc { +func newCancelPlanHandler(cliCtx context.CLIContext, txg context.TxGenerator, newMsgFn func() gov.MsgSubmitProposalI) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req CancelRequest @@ -137,7 +137,7 @@ func newCancelPlanHandler(cliCtx context.CLIContext, txg tx.Generator, newMsgFn return } - tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) } } diff --git a/x/upgrade/module.go b/x/upgrade/module.go index f2c94d7627..d0a8ee5197 100644 --- a/x/upgrade/module.go +++ b/x/upgrade/module.go @@ -65,7 +65,7 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { } // GetTxCmd returns the transaction commands for this module -func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { +func (AppModuleBasic) GetTxCmd(_ context.CLIContext) *cobra.Command { txCmd := &cobra.Command{ Use: "upgrade", Short: "Upgrade transaction subcommands",