Merge PR #3688: JSON Decode Log in REST Client

This commit is contained in:
Alexander Bezobchuk 2019-02-22 06:54:31 -05:00 committed by Christopher Goes
parent 2121160d29
commit 0611d2eda2
6 changed files with 76 additions and 30 deletions

View File

@ -39,6 +39,9 @@
### Gaia REST API
* Update the `TxResponse` type allowing for the `Logs` result to be JSON
decoded automatically.
### Gaia CLI
### Gaia

View File

@ -629,15 +629,9 @@ func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) (ctx sdk.Con
return
}
type indexedABCILog struct {
MsgIndex int `json:"msg_index"`
Success bool `json:"success"`
Log string `json:"log"`
}
// runMsgs iterates through all the messages and executes them.
func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (result sdk.Result) {
idxlogs := make([]indexedABCILog, 0, len(msgs)) // a list of JSON-encoded logs with msg index
idxlogs := make([]sdk.ABCIMessageLog, 0, len(msgs)) // a list of JSON-encoded logs with msg index
var data []byte // NOTE: we just append them all (?!)
var tags sdk.Tags // also just append them all
@ -666,7 +660,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
tags = append(tags, sdk.MakeTag(sdk.TagAction, msg.Type()))
tags = append(tags, msgResult.Tags...)
idxLog := indexedABCILog{MsgIndex: msgIdx, Log: msgResult.Log}
idxLog := sdk.ABCIMessageLog{MsgIndex: msgIdx, Log: msgResult.Log}
// stop execution and return on first failed message
if !msgResult.IsOK() {

View File

@ -254,6 +254,7 @@ func (ctx CLIContext) PrintOutput(toPrint fmt.Stringer) (err error) {
switch ctx.OutputFormat {
case "text":
out = []byte(toPrint.String())
case "json":
if ctx.Indent {
out, err = ctx.Codec.MarshalJSONIndent(toPrint, "", " ")

View File

@ -192,6 +192,9 @@ func PostProcessResponse(w http.ResponseWriter, cdc *codec.Codec, response inter
var output []byte
switch response.(type) {
case []byte:
output = response.([]byte)
default:
var err error
if indent {
@ -203,8 +206,6 @@ func PostProcessResponse(w http.ResponseWriter, cdc *codec.Codec, response inter
WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
case []byte:
output = response.([]byte)
}
w.Header().Set("Content-Type", "application/json")

View File

@ -1,6 +1,7 @@
package types
import (
"encoding/json"
"fmt"
"strings"
@ -9,7 +10,6 @@ import (
// Result is the union of ResponseFormat and ResponseCheckTx.
type Result struct {
// Code is the response code, is stored back on the chain.
Code CodeType
@ -21,7 +21,7 @@ type Result struct {
// results from multiple msgs executions
Data []byte
// Log is just debug information. NOTE: nondeterministic.
// Log contains the txs log information. NOTE: nondeterministic.
Log string
// GasWanted is the maximum units of work we allow this tx to perform.
@ -39,13 +39,36 @@ func (res Result) IsOK() bool {
return res.Code.IsOK()
}
// Is a version of TxResponse where the tags are StringTags rather than []byte tags
// ABCIMessageLogs represents a slice of ABCIMessageLog.
type ABCIMessageLogs []ABCIMessageLog
// ABCIMessageLog defines a structure containing an indexed tx ABCI message log.
type ABCIMessageLog struct {
MsgIndex int `json:"msg_index"`
Success bool `json:"success"`
Log string `json:"log"`
}
// String implements the fmt.Stringer interface for the ABCIMessageLogs type.
func (logs ABCIMessageLogs) String() (str string) {
if logs != nil {
raw, err := json.Marshal(logs)
if err == nil {
str = string(raw)
}
}
return str
}
// TxResponse defines a structure containing relevant tx data and metadata. The
// tags are stringified and the log is JSON decoded.
type TxResponse struct {
Height int64 `json:"height"`
TxHash string `json:"txhash"`
Code uint32 `json:"code,omitempty"`
Data []byte `json:"data,omitempty"`
Log string `json:"log,omitempty"`
Logs ABCIMessageLogs `json:"logs,omitempty"`
Info string `json:"info,omitempty"`
GasWanted int64 `json:"gas_wanted,omitempty"`
GasUsed int64 `json:"gas_used,omitempty"`
@ -60,12 +83,14 @@ func NewResponseResultTx(res *ctypes.ResultTx, tx Tx) TxResponse {
return TxResponse{}
}
parsedLogs, _ := ParseABCILogs(res.TxResult.Log)
return TxResponse{
TxHash: res.Hash.String(),
Height: res.Height,
Code: res.TxResult.Code,
Data: res.TxResult.Data,
Log: res.TxResult.Log,
Logs: parsedLogs,
Info: res.TxResult.Info,
GasWanted: res.TxResult.GasWanted,
GasUsed: res.TxResult.GasUsed,
@ -85,12 +110,14 @@ func NewResponseFormatBroadcastTxCommit(res *ctypes.ResultBroadcastTxCommit) TxR
txHash = res.Hash.String()
}
parsedLogs, _ := ParseABCILogs(res.DeliverTx.Log)
return TxResponse{
Height: res.Height,
TxHash: txHash,
Code: res.DeliverTx.Code,
Data: res.DeliverTx.Data,
Log: res.DeliverTx.Log,
Logs: parsedLogs,
Info: res.DeliverTx.Info,
GasWanted: res.DeliverTx.GasWanted,
GasUsed: res.DeliverTx.GasUsed,
@ -106,10 +133,12 @@ func NewResponseFormatBroadcastTx(res *ctypes.ResultBroadcastTx) TxResponse {
return TxResponse{}
}
parsedLogs, _ := ParseABCILogs(res.Log)
return TxResponse{
Code: res.Code,
Data: res.Data.Bytes(),
Log: res.Log,
Logs: parsedLogs,
TxHash: res.Hash.String(),
}
}
@ -134,8 +163,8 @@ func (r TxResponse) String() string {
sb.WriteString(fmt.Sprintf(" Data: %s\n", string(r.Data)))
}
if r.Log != "" {
sb.WriteString(fmt.Sprintf(" Log: %s\n", r.Log))
if r.Logs != nil {
sb.WriteString(fmt.Sprintf(" Logs: %s\n", r.Logs))
}
if r.Info != "" {
@ -163,5 +192,12 @@ func (r TxResponse) String() string {
// Empty returns true if the response is empty
func (r TxResponse) Empty() bool {
return r.TxHash == "" && r.Log == ""
return r.TxHash == "" && r.Logs == nil
}
// ParseABCILogs attempts to parse a stringified ABCI tx log into a slice of
// ABCIMessageLog types. It returns an error upon JSON decoding failure.
func ParseABCILogs(logs string) (res ABCIMessageLogs, err error) {
err = json.Unmarshal([]byte(logs), &res)
return res, err
}

View File

@ -16,3 +16,14 @@ func TestResult(t *testing.T) {
res.Code = CodeType(1)
require.False(t, res.IsOK())
}
func TestParseABCILog(t *testing.T) {
logs := `[{"log":"","msg_index":1,"success":true}]`
res, err := ParseABCILogs(logs)
require.NoError(t, err)
require.Len(t, res, 1)
require.Equal(t, res[0].Log, "")
require.Equal(t, res[0].MsgIndex, 1)
require.True(t, res[0].Success)
}