Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: Make tags and responses legible #3451

Merged
merged 12 commits into from
Feb 5, 2019
2 changes: 1 addition & 1 deletion baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re

// Append Data and Tags
data = append(data, msgResult.Data...)
tags = append(tags, sdk.MakeTag(sdk.TagAction, []byte(msg.Type())))
tags = append(tags, sdk.MakeTag(sdk.TagAction, msg.Type()))
tags = append(tags, msgResult.Tags...)

// Stop execution and return on first failed message.
Expand Down
140 changes: 25 additions & 115 deletions client/context/broadcast.go
Original file line number Diff line number Diff line change
@@ -1,170 +1,80 @@
package context

import (
"fmt"
"io"

"github.com/pkg/errors"

abci "github.com/tendermint/tendermint/abci/types"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

// TODO: This should get deleted eventually, and perhaps
// ctypes.ResultBroadcastTx be stripped of unused fields, and
// ctypes.ResultBroadcastTxCommit returned for tendermint RPC BroadcastTxSync.
//
// The motivation is that we want a unified type to return, and the better
// option is the one that can hold CheckTx/DeliverTx responses optionally.
func resultBroadcastTxToCommit(res *ctypes.ResultBroadcastTx) *ctypes.ResultBroadcastTxCommit {
return &ctypes.ResultBroadcastTxCommit{
Hash: res.Hash,
// NOTE: other fields are unused for async.
}
}

// BroadcastTx broadcasts a transactions either synchronously or asynchronously
// based on the context parameters. The result of the broadcast is parsed into
// an intermediate structure which is logged if the context has a logger
// defined.
func (ctx CLIContext) BroadcastTx(txBytes []byte) (*ctypes.ResultBroadcastTxCommit, error) {
func (ctx CLIContext) BroadcastTx(txBytes []byte) (res sdk.TxResponse, err error) {
if ctx.Async {
res, err := ctx.broadcastTxAsync(txBytes)
if err != nil {
return nil, err
if res, err = ctx.BroadcastTxAsync(txBytes); err != nil {
return
}
return
}

resCommit := resultBroadcastTxToCommit(res)
return resCommit, err
if res, err = ctx.BroadcastTxAndAwaitCommit(txBytes); err != nil {
return
}

return ctx.broadcastTxCommit(txBytes)
return
}

// BroadcastTxAndAwaitCommit broadcasts transaction bytes to a Tendermint node
// and waits for a commit.
func (ctx CLIContext) BroadcastTxAndAwaitCommit(tx []byte) (*ctypes.ResultBroadcastTxCommit, error) {
func (ctx CLIContext) BroadcastTxAndAwaitCommit(tx []byte) (sdk.TxResponse, error) {
node, err := ctx.GetNode()
if err != nil {
return nil, err
return sdk.TxResponse{}, err
}

res, err := node.BroadcastTxCommit(tx)
if err != nil {
return res, err
return sdk.NewResponseFormatBroadcastTxCommit(res), err
}

if !res.CheckTx.IsOK() {
return res, errors.Errorf(res.CheckTx.Log)
return sdk.NewResponseFormatBroadcastTxCommit(res), errors.Errorf(res.CheckTx.Log)
}

if !res.DeliverTx.IsOK() {
return res, errors.Errorf(res.DeliverTx.Log)
return sdk.NewResponseFormatBroadcastTxCommit(res), errors.Errorf(res.DeliverTx.Log)
}

return res, err
return sdk.NewResponseFormatBroadcastTxCommit(res), err
}

// BroadcastTxSync broadcasts transaction bytes to a Tendermint node
// synchronously.
func (ctx CLIContext) BroadcastTxSync(tx []byte) (*ctypes.ResultBroadcastTx, error) {
// BroadcastTxSync broadcasts transaction bytes to a Tendermint node synchronously.
func (ctx CLIContext) BroadcastTxSync(tx []byte) (sdk.TxResponse, error) {
node, err := ctx.GetNode()
if err != nil {
return nil, err
return sdk.TxResponse{}, err
}

res, err := node.BroadcastTxSync(tx)
if err != nil {
return res, err
return sdk.NewResponseFormatBroadcastTx(res), err
}

return res, err
return sdk.NewResponseFormatBroadcastTx(res), err
}

// BroadcastTxAsync broadcasts transaction bytes to a Tendermint node
// asynchronously.
func (ctx CLIContext) BroadcastTxAsync(tx []byte) (*ctypes.ResultBroadcastTx, error) {
// BroadcastTxAsync broadcasts transaction bytes to a Tendermint node asynchronously.
func (ctx CLIContext) BroadcastTxAsync(tx []byte) (sdk.TxResponse, error) {
node, err := ctx.GetNode()
if err != nil {
return nil, err
return sdk.TxResponse{}, err
}

res, err := node.BroadcastTxAsync(tx)
if err != nil {
return res, err
}

return res, err
}

func (ctx CLIContext) broadcastTxAsync(txBytes []byte) (*ctypes.ResultBroadcastTx, error) {
res, err := ctx.BroadcastTxAsync(txBytes)
if err != nil {
return res, err
}

if ctx.Output != nil {
if ctx.OutputFormat == "json" {
type toJSON struct {
TxHash string
}

resJSON := toJSON{res.Hash.String()}
bz, err := ctx.Codec.MarshalJSON(resJSON)
if err != nil {
return res, err
}

ctx.Output.Write(bz)
io.WriteString(ctx.Output, "\n")
} else {
io.WriteString(ctx.Output, fmt.Sprintf("async tx sent (tx hash: %s)\n", res.Hash))
}
}

return res, nil
}

func (ctx CLIContext) broadcastTxCommit(txBytes []byte) (*ctypes.ResultBroadcastTxCommit, error) {
res, err := ctx.BroadcastTxAndAwaitCommit(txBytes)
if err != nil {
return res, err
}

if ctx.OutputFormat == "json" {
// Since JSON is intended for automated scripts, always include response in
// JSON mode.
type toJSON struct {
Height int64
TxHash string
Response abci.ResponseDeliverTx
}

if ctx.Output != nil {
resJSON := toJSON{res.Height, res.Hash.String(), res.DeliverTx}
bz, err := ctx.Codec.MarshalJSON(resJSON)
if err != nil {
return res, err
}

ctx.Output.Write(bz)
io.WriteString(ctx.Output, "\n")
}

return res, nil
}

if ctx.Output != nil {
resStr := fmt.Sprintf("Committed at block %d (tx hash: %s)\n", res.Height, res.Hash.String())

if ctx.PrintResponse {
resStr = fmt.Sprintf("Committed at block %d (tx hash: %s, response: %+v)\n",
res.Height, res.Hash.String(), res.DeliverTx,
)
}

io.WriteString(ctx.Output, resStr)
return sdk.NewResponseFormatBroadcastTx(res), err
}

return res, nil
return sdk.NewResponseFormatBroadcastTx(res), err
}
5 changes: 5 additions & 0 deletions client/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@ func (ctx CLIContext) WithFromAddress(addr sdk.AccAddress) CLIContext {
return ctx
}

// OutputIsJSON true if the output format for the CLI is json and false otherwise
func (ctx CLIContext) OutputIsJSON() bool {
jackzampolin marked this conversation as resolved.
Show resolved Hide resolved
return ctx.OutputFormat == "json"
}

// PrintOutput prints output while respecting output and indent flags
// NOTE: pass in marshalled structs that have been unmarshaled
// because this function will panic on marshaling errors
Expand Down
Loading