171 lines
4.0 KiB
Go
171 lines
4.0 KiB
Go
package context
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
ctypes "github.com/tendermint/tendermint/rpc/core/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) {
|
|
if ctx.Async {
|
|
res, err := ctx.broadcastTxAsync(txBytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
resCommit := resultBroadcastTxToCommit(res)
|
|
return resCommit, err
|
|
}
|
|
|
|
return ctx.broadcastTxCommit(txBytes)
|
|
}
|
|
|
|
// BroadcastTxAndAwaitCommit broadcasts transaction bytes to a Tendermint node
|
|
// and waits for a commit.
|
|
func (ctx CLIContext) BroadcastTxAndAwaitCommit(tx []byte) (*ctypes.ResultBroadcastTxCommit, error) {
|
|
node, err := ctx.GetNode()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
res, err := node.BroadcastTxCommit(tx)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
if !res.CheckTx.IsOK() {
|
|
return res, errors.Errorf(res.CheckTx.Log)
|
|
}
|
|
|
|
if !res.DeliverTx.IsOK() {
|
|
return res, errors.Errorf(res.DeliverTx.Log)
|
|
}
|
|
|
|
return res, err
|
|
}
|
|
|
|
// BroadcastTxSync broadcasts transaction bytes to a Tendermint node
|
|
// synchronously.
|
|
func (ctx CLIContext) BroadcastTxSync(tx []byte) (*ctypes.ResultBroadcastTx, error) {
|
|
node, err := ctx.GetNode()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
res, err := node.BroadcastTxSync(tx)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
return res, err
|
|
}
|
|
|
|
// BroadcastTxAsync broadcasts transaction bytes to a Tendermint node
|
|
// asynchronously.
|
|
func (ctx CLIContext) BroadcastTxAsync(tx []byte) (*ctypes.ResultBroadcastTx, error) {
|
|
node, err := ctx.GetNode()
|
|
if err != nil {
|
|
return nil, 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.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.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 res, nil
|
|
}
|