Merge PR #3642: Tx Query return values
This commit is contained in:
parent
c0eec30840
commit
5ccad4723f
|
@ -3,6 +3,7 @@
|
||||||
BREAKING CHANGES
|
BREAKING CHANGES
|
||||||
|
|
||||||
* Gaia REST API
|
* Gaia REST API
|
||||||
|
* [\#3642](https://github.com/cosmos/cosmos-sdk/pull/3642) `GET /tx/{hash}` now returns `404` instead of `500` if the transaction is not found
|
||||||
|
|
||||||
* Gaia CLI
|
* Gaia CLI
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -503,6 +504,17 @@ func TestTxs(t *testing.T) {
|
||||||
txs = getTransactions(t, port, fmt.Sprintf("recipient=%s", receiveAddr.String()))
|
txs = getTransactions(t, port, fmt.Sprintf("recipient=%s", receiveAddr.String()))
|
||||||
require.Len(t, txs, 1)
|
require.Len(t, txs, 1)
|
||||||
require.Equal(t, resultTx.Height, txs[0].Height)
|
require.Equal(t, resultTx.Height, txs[0].Height)
|
||||||
|
|
||||||
|
// query transaction that doesn't exist
|
||||||
|
validTxHash := "9ADBECAAD8DACBEC3F4F535704E7CF715C765BDCEDBEF086AFEAD31BA664FB0B"
|
||||||
|
res, body := getTransactionRequest(t, port, validTxHash)
|
||||||
|
require.True(t, strings.Contains(body, validTxHash))
|
||||||
|
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||||
|
|
||||||
|
// bad query string
|
||||||
|
res, body = getTransactionRequest(t, port, "badtxhash")
|
||||||
|
require.True(t, strings.Contains(body, "encoding/hex"))
|
||||||
|
require.Equal(t, http.StatusInternalServerError, res.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPoolParamsQuery(t *testing.T) {
|
func TestPoolParamsQuery(t *testing.T) {
|
||||||
|
|
|
@ -513,7 +513,7 @@ func getValidatorSets(t *testing.T, port string, height int, expectFail bool) rp
|
||||||
// GET /txs/{hash} get tx by hash
|
// GET /txs/{hash} get tx by hash
|
||||||
func getTransaction(t *testing.T, port string, hash string) sdk.TxResponse {
|
func getTransaction(t *testing.T, port string, hash string) sdk.TxResponse {
|
||||||
var tx sdk.TxResponse
|
var tx sdk.TxResponse
|
||||||
res, body := Request(t, port, "GET", fmt.Sprintf("/txs/%s", hash), nil)
|
res, body := getTransactionRequest(t, port, hash)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
err := cdc.UnmarshalJSON([]byte(body), &tx)
|
err := cdc.UnmarshalJSON([]byte(body), &tx)
|
||||||
|
@ -521,6 +521,10 @@ func getTransaction(t *testing.T, port string, hash string) sdk.TxResponse {
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTransactionRequest(t *testing.T, port, hash string) (*http.Response, string) {
|
||||||
|
return Request(t, port, "GET", fmt.Sprintf("/txs/%s", hash), nil)
|
||||||
|
}
|
||||||
|
|
||||||
// POST /txs broadcast txs
|
// POST /txs broadcast txs
|
||||||
|
|
||||||
// GET /txs search transactions
|
// GET /txs search transactions
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -26,18 +27,18 @@ func QueryTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||||
Short: "Matches this txhash over all committed blocks",
|
Short: "Matches this txhash over all committed blocks",
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
// find the key to look up the account
|
|
||||||
hashHexStr := args[0]
|
|
||||||
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
|
|
||||||
output, err := queryTx(cdc, cliCtx, hashHexStr)
|
output, err := queryTx(cdc, cliCtx, args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(string(output))
|
if output.Empty() {
|
||||||
return nil
|
return fmt.Errorf("No transaction found with hash %s", args[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return cliCtx.PrintOutput(output)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,50 +49,46 @@ func QueryTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryTx(cdc *codec.Codec, cliCtx context.CLIContext, hashHexStr string) ([]byte, error) {
|
func queryTx(cdc *codec.Codec, cliCtx context.CLIContext, hashHexStr string) (out sdk.TxResponse, err error) {
|
||||||
hash, err := hex.DecodeString(hashHexStr)
|
hash, err := hex.DecodeString(hashHexStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := cliCtx.GetNode()
|
node, err := cliCtx.GetNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := node.Tx(hash, !cliCtx.TrustNode)
|
res, err := node.Tx(hash, !cliCtx.TrustNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cliCtx.TrustNode {
|
if !cliCtx.TrustNode {
|
||||||
err := ValidateTxResult(cliCtx, res)
|
if err = ValidateTxResult(cliCtx, res); err != nil {
|
||||||
if err != nil {
|
return out, err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := formatTxResult(cdc, res)
|
if out, err = formatTxResult(cdc, res); err != nil {
|
||||||
if err != nil {
|
return out, err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if cliCtx.Indent {
|
return out, nil
|
||||||
return cdc.MarshalJSONIndent(info, "", " ")
|
|
||||||
}
|
|
||||||
return cdc.MarshalJSON(info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateTxResult performs transaction verification
|
// ValidateTxResult performs transaction verification
|
||||||
func ValidateTxResult(cliCtx context.CLIContext, res *ctypes.ResultTx) error {
|
func ValidateTxResult(cliCtx context.CLIContext, res *ctypes.ResultTx) error {
|
||||||
check, err := cliCtx.Verify(res.Height)
|
if !cliCtx.TrustNode {
|
||||||
if err != nil {
|
check, err := cliCtx.Verify(res.Height)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
err = res.Proof.Validate(check.Header.DataHash)
|
err = res.Proof.Validate(check.Header.DataHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -118,7 +115,7 @@ func parseTx(cdc *codec.Codec, txBytes []byte) (sdk.Tx, error) {
|
||||||
|
|
||||||
// REST
|
// REST
|
||||||
|
|
||||||
// transaction query REST handler
|
// QueryTxRequestHandlerFn transaction query REST handler
|
||||||
func QueryTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
func QueryTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
|
@ -126,9 +123,18 @@ func QueryTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.H
|
||||||
|
|
||||||
output, err := queryTx(cdc, cliCtx, hashHexStr)
|
output, err := queryTx(cdc, cliCtx, hashHexStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), hashHexStr) {
|
||||||
|
rest.WriteErrorResponse(w, http.StatusNotFound, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if output.Empty() {
|
||||||
|
rest.WriteErrorResponse(w, http.StatusNotFound, fmt.Sprintf("no transaction found with hash %s", hashHexStr))
|
||||||
|
}
|
||||||
|
|
||||||
rest.PostProcessResponse(w, cdc, output, cliCtx.Indent)
|
rest.PostProcessResponse(w, cdc, output, cliCtx.Indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ type TxResponse struct {
|
||||||
Tx Tx `json:"tx,omitempty"`
|
Tx Tx `json:"tx,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewResponseResultTx returns a TxResponse given a ResultTx from tendermint
|
||||||
func NewResponseResultTx(res *ctypes.ResultTx, tx Tx) TxResponse {
|
func NewResponseResultTx(res *ctypes.ResultTx, tx Tx) TxResponse {
|
||||||
if res == nil {
|
if res == nil {
|
||||||
return TxResponse{}
|
return TxResponse{}
|
||||||
|
@ -73,6 +74,7 @@ func NewResponseResultTx(res *ctypes.ResultTx, tx Tx) TxResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewResponseFormatBroadcastTxCommit returns a TxResponse given a ResultBroadcastTxCommit from tendermint
|
||||||
func NewResponseFormatBroadcastTxCommit(res *ctypes.ResultBroadcastTxCommit) TxResponse {
|
func NewResponseFormatBroadcastTxCommit(res *ctypes.ResultBroadcastTxCommit) TxResponse {
|
||||||
if res == nil {
|
if res == nil {
|
||||||
return TxResponse{}
|
return TxResponse{}
|
||||||
|
@ -95,8 +97,10 @@ func NewResponseFormatBroadcastTxCommit(res *ctypes.ResultBroadcastTxCommit) TxR
|
||||||
Tags: TagsToStringTags(res.DeliverTx.Tags),
|
Tags: TagsToStringTags(res.DeliverTx.Tags),
|
||||||
Codespace: res.DeliverTx.Codespace,
|
Codespace: res.DeliverTx.Codespace,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewResponseFormatBroadcastTx returns a TxResponse given a ResultBroadcastTx from tendermint
|
||||||
func NewResponseFormatBroadcastTx(res *ctypes.ResultBroadcastTx) TxResponse {
|
func NewResponseFormatBroadcastTx(res *ctypes.ResultBroadcastTx) TxResponse {
|
||||||
if res == nil {
|
if res == nil {
|
||||||
return TxResponse{}
|
return TxResponse{}
|
||||||
|
@ -156,3 +160,8 @@ func (r TxResponse) String() string {
|
||||||
|
|
||||||
return strings.TrimSpace(sb.String())
|
return strings.TrimSpace(sb.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Empty returns true if the response is empty
|
||||||
|
func (r TxResponse) Empty() bool {
|
||||||
|
return r.TxHash == "" && r.Log == ""
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue