Merge PR #3523: Add tx/encode endpoint and CLI command

This commit is contained in:
Ducem Barr 2019-02-08 16:17:25 -05:00 committed by Jack Zampolin
parent d759bef4d1
commit 9348750eb4
16 changed files with 318 additions and 56 deletions

View File

@ -25,7 +25,7 @@ BREAKING CHANGES
* Reintroduce OR semantics for tx fees
* SDK
* \#2513 Tendermint updates are adjusted by 10^-6 relative to staking tokens,
* \#2513 Tendermint updates are adjusted by 10^-6 relative to staking tokens,
* [\#3487](https://github.com/cosmos/cosmos-sdk/pull/3487) Move HTTP/REST utilities out of client/utils into a new dedicated client/rest package.
* [\#3490](https://github.com/cosmos/cosmos-sdk/issues/3490) ReadRESTReq() returns bool to avoid callers to write error responses twice.
* [\#3502](https://github.com/cosmos/cosmos-sdk/pull/3502) Fixes issue when comparing genesis states
@ -73,6 +73,7 @@ IMPROVEMENTS
* [\#3423](https://github.com/cosmos/cosmos-sdk/issues/3423) Allow simulation
(auto gas) to work with generate only.
* [\#3514](https://github.com/cosmos/cosmos-sdk/pull/3514) REST server calls to keybase does not lock the underlying storage anymore.
* [\#3523](https://github.com/cosmos/cosmos-sdk/pull/3523) Added `/tx/encode` endpoint to serialize a JSON tx to base64-encoded Amino.
* Gaia CLI (`gaiacli`)
* [\#3476](https://github.com/cosmos/cosmos-sdk/issues/3476) New `withdraw-all-rewards` command to withdraw all delegations rewards for delegators.
@ -80,6 +81,7 @@ IMPROVEMENTS
* [\#3518](https://github.com/cosmos/cosmos-sdk/issues/3518) Fix flow in
`keys add` to show the mnemonic by default.
* [\#3517](https://github.com/cosmos/cosmos-sdk/pull/3517) Increased test coverage
* [\#3523](https://github.com/cosmos/cosmos-sdk/pull/3523) Added `tx encode` command to serialize a JSON tx to base64-encoded Amino.
* Gaia
* [\#3418](https://github.com/cosmos/cosmos-sdk/issues/3418) Add vesting account

View File

@ -1,6 +1,7 @@
package lcd
import (
"encoding/base64"
"encoding/hex"
"fmt"
"net/http"
@ -423,6 +424,46 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
require.Equal(t, gasEstimate, resultTx.GasWanted)
}
func TestEncodeTx(t *testing.T) {
// Setup
kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, ""))
require.NoError(t, err)
addr, seed := CreateAddr(t, name1, pw, kb)
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true)
defer cleanup()
// Make a transaction to test with
res, body, _ := doTransferWithGas(t, port, seed, name1, memo, "", addr, "2", 1, false, true, fees)
var tx auth.StdTx
cdc.UnmarshalJSON([]byte(body), &tx)
// Build the request
encodeReq := struct {
Tx auth.StdTx `json:"tx"`
}{Tx: tx}
encodedJSON, _ := cdc.MarshalJSON(encodeReq)
res, body = Request(t, port, "POST", "/tx/encode", encodedJSON)
// Make sure it came back ok, and that we can decode it back to the transaction
// 200 response
require.Equal(t, http.StatusOK, res.StatusCode, body)
encodeResp := struct {
Tx string `json:"tx"`
}{}
// No error decoding the JSON
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &encodeResp))
// Check that the base64 decodes
decodedBytes, err := base64.StdEncoding.DecodeString(encodeResp.Tx)
require.Nil(t, err)
// Check that the transaction decodes as expected
var decodedTx auth.StdTx
require.Nil(t, cdc.UnmarshalBinaryLengthPrefixed(decodedBytes, &decodedTx))
require.Equal(t, memo, decodedTx.Memo)
}
func TestTxs(t *testing.T) {
kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, ""))
require.NoError(t, err)

View File

@ -334,6 +334,39 @@ paths:
description: The Tx was malformated
500:
description: Server internal error
/tx/encode:
post:
tags:
- ICS20
summary: Encode a transaction to wire format
description: Encode a transaction (signed or not) from JSON to base64-encoded Amino serialized bytes
consumes:
- application/json
produces:
- application/json
parameters:
- in: body
name: tx
description: The transaction to encode
required: true
schema:
type: object
properties:
tx:
$ref: "#/definitions/StdTx"
responses:
200:
description: Transaction was successfully decoded and re-encoded
schema:
type: object
properties:
tx:
type: string
example: The base64-encoded Amino-serialized bytes for the transaction
400:
description: The Tx was malformated
500:
description: Server internal error
/bank/balances/{address}:
get:
summary: Get the account balances

View File

@ -1,12 +1,14 @@
package clitest
import (
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"testing"
"time"
@ -18,6 +20,7 @@ import (
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/staking"
)
@ -587,7 +590,7 @@ func TestGaiaCLIValidateSignatures(t *testing.T) {
require.Empty(t, stderr)
// write unsigned tx to file
unsignedTxFile := writeToNewTempFile(t, stdout)
unsignedTxFile := WriteToNewTempFile(t, stdout)
defer os.Remove(unsignedTxFile.Name())
// validate we can successfully sign
@ -600,7 +603,7 @@ func TestGaiaCLIValidateSignatures(t *testing.T) {
require.Equal(t, fooAddr.String(), stdTx.GetSigners()[0].String())
// write signed tx to file
signedTxFile := writeToNewTempFile(t, stdout)
signedTxFile := WriteToNewTempFile(t, stdout)
defer os.Remove(signedTxFile.Name())
// validate signatures
@ -610,7 +613,7 @@ func TestGaiaCLIValidateSignatures(t *testing.T) {
// modify the transaction
stdTx.Memo = "MODIFIED-ORIGINAL-TX-BAD"
bz := marshalStdTx(t, stdTx)
modSignedTxFile := writeToNewTempFile(t, string(bz))
modSignedTxFile := WriteToNewTempFile(t, string(bz))
defer os.Remove(modSignedTxFile.Name())
// validate signature validation failure due to different transaction sig bytes
@ -659,7 +662,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
require.Equal(t, len(msg.Msgs), 1)
// Write the output to disk
unsignedTxFile := writeToNewTempFile(t, stdout)
unsignedTxFile := WriteToNewTempFile(t, stdout)
defer os.Remove(unsignedTxFile.Name())
// Test sign --validate-signatures
@ -676,7 +679,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
require.Equal(t, fooAddr.String(), msg.GetSigners()[0].String())
// Write the output to disk
signedTxFile := writeToNewTempFile(t, stdout)
signedTxFile := WriteToNewTempFile(t, stdout)
defer os.Remove(signedTxFile.Name())
// Test sign --validate-signatures
@ -732,7 +735,7 @@ func TestGaiaCLIMultisignInsufficientCosigners(t *testing.T) {
require.True(t, success)
// Write the output to disk
unsignedTxFile := writeToNewTempFile(t, stdout)
unsignedTxFile := WriteToNewTempFile(t, stdout)
defer os.Remove(unsignedTxFile.Name())
// Sign with foo's key
@ -740,7 +743,7 @@ func TestGaiaCLIMultisignInsufficientCosigners(t *testing.T) {
require.True(t, success)
// Write the output to disk
fooSignatureFile := writeToNewTempFile(t, stdout)
fooSignatureFile := WriteToNewTempFile(t, stdout)
defer os.Remove(fooSignatureFile.Name())
// Multisign, not enough signatures
@ -748,7 +751,7 @@ func TestGaiaCLIMultisignInsufficientCosigners(t *testing.T) {
require.True(t, success)
// Write the output to disk
signedTxFile := writeToNewTempFile(t, stdout)
signedTxFile := WriteToNewTempFile(t, stdout)
defer os.Remove(signedTxFile.Name())
// Validate the multisignature
@ -760,6 +763,42 @@ func TestGaiaCLIMultisignInsufficientCosigners(t *testing.T) {
require.False(t, success)
}
func TestGaiaCLIEncode(t *testing.T) {
t.Parallel()
f := InitFixtures(t)
// start gaiad server
proc := f.GDStart()
defer proc.Stop(false)
cdc := app.MakeCodec()
// Build a testing transaction and write it to disk
barAddr := f.KeyAddress(keyBar)
sendTokens := staking.TokensFromTendermintPower(10)
success, stdout, stderr := f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--generate-only", "--memo", "deadbeef")
require.True(t, success)
require.Empty(t, stderr)
// Write it to disk
jsonTxFile := WriteToNewTempFile(t, stdout)
defer os.Remove(jsonTxFile.Name())
// Run the encode command, and trim the extras from the stdout capture
success, base64Encoded, _ := f.TxEncode(jsonTxFile.Name())
require.True(t, success)
trimmedBase64 := strings.Trim(base64Encoded, "\"\n")
// Decode the base64
decodedBytes, err := base64.StdEncoding.DecodeString(trimmedBase64)
require.Nil(t, err)
// Check that the transaction decodes as epxceted
var decodedTx auth.StdTx
require.Nil(t, cdc.UnmarshalBinaryLengthPrefixed(decodedBytes, &decodedTx))
require.Equal(t, "deadbeef", decodedTx.Memo)
}
func TestGaiaCLIMultisignSortSignatures(t *testing.T) {
t.Parallel()
f := InitFixtures(t)
@ -785,7 +824,7 @@ func TestGaiaCLIMultisignSortSignatures(t *testing.T) {
require.True(t, success)
// Write the output to disk
unsignedTxFile := writeToNewTempFile(t, stdout)
unsignedTxFile := WriteToNewTempFile(t, stdout)
defer os.Remove(unsignedTxFile.Name())
// Sign with foo's key
@ -793,7 +832,7 @@ func TestGaiaCLIMultisignSortSignatures(t *testing.T) {
require.True(t, success)
// Write the output to disk
fooSignatureFile := writeToNewTempFile(t, stdout)
fooSignatureFile := WriteToNewTempFile(t, stdout)
defer os.Remove(fooSignatureFile.Name())
// Sign with baz's key
@ -801,7 +840,7 @@ func TestGaiaCLIMultisignSortSignatures(t *testing.T) {
require.True(t, success)
// Write the output to disk
bazSignatureFile := writeToNewTempFile(t, stdout)
bazSignatureFile := WriteToNewTempFile(t, stdout)
defer os.Remove(bazSignatureFile.Name())
// Multisign, keys in different order
@ -810,7 +849,7 @@ func TestGaiaCLIMultisignSortSignatures(t *testing.T) {
require.True(t, success)
// Write the output to disk
signedTxFile := writeToNewTempFile(t, stdout)
signedTxFile := WriteToNewTempFile(t, stdout)
defer os.Remove(signedTxFile.Name())
// Validate the multisignature
@ -848,7 +887,7 @@ func TestGaiaCLIMultisign(t *testing.T) {
require.Empty(t, stderr)
// Write the output to disk
unsignedTxFile := writeToNewTempFile(t, stdout)
unsignedTxFile := WriteToNewTempFile(t, stdout)
defer os.Remove(unsignedTxFile.Name())
// Sign with foo's key
@ -856,7 +895,7 @@ func TestGaiaCLIMultisign(t *testing.T) {
require.True(t, success)
// Write the output to disk
fooSignatureFile := writeToNewTempFile(t, stdout)
fooSignatureFile := WriteToNewTempFile(t, stdout)
defer os.Remove(fooSignatureFile.Name())
// Sign with bar's key
@ -864,7 +903,7 @@ func TestGaiaCLIMultisign(t *testing.T) {
require.True(t, success)
// Write the output to disk
barSignatureFile := writeToNewTempFile(t, stdout)
barSignatureFile := WriteToNewTempFile(t, stdout)
defer os.Remove(barSignatureFile.Name())
// Multisign
@ -873,7 +912,7 @@ func TestGaiaCLIMultisign(t *testing.T) {
require.True(t, success)
// Write the output to disk
signedTxFile := writeToNewTempFile(t, stdout)
signedTxFile := WriteToNewTempFile(t, stdout)
defer os.Remove(signedTxFile.Name())
// Validate the multisignature

View File

@ -294,12 +294,18 @@ func (f *Fixtures) TxSign(signer, fileName string, flags ...string) (bool, strin
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxBroadcast is gaiacli tx sign
// TxBroadcast is gaiacli tx broadcast
func (f *Fixtures) TxBroadcast(fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx broadcast %v %v", f.Flags(), fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxEncode is gaiacli tx encode
func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx encode %v %v", f.Flags(), fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxMultisign is gaiacli tx multisign
func (f *Fixtures) TxMultisign(fileName, name string, signaturesFiles []string,
flags ...string) (bool, string, string) {
@ -640,7 +646,8 @@ func queryTags(tags []string) (out string) {
return strings.TrimSuffix(out, "&")
}
func writeToNewTempFile(t *testing.T, s string) *os.File {
// Write the given string to a new temporary file
func WriteToNewTempFile(t *testing.T, s string) *os.File {
fp, err := ioutil.TempFile(os.TempDir(), "cosmos_cli_test_")
require.Nil(t, err)
_, err = fp.WriteString(s)

View File

@ -141,7 +141,8 @@ func txCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
client.LineBreak,
authcmd.GetSignCommand(cdc),
authcmd.GetMultiSignCommand(cdc),
bankcmd.GetBroadcastCommand(cdc),
authcmd.GetBroadcastCommand(cdc),
authcmd.GetEncodeCommand(cdc),
client.LineBreak,
)

View File

@ -1,8 +1,6 @@
package cli
import (
"io/ioutil"
"os"
"strings"
"github.com/spf13/cobra"
@ -10,7 +8,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/x/auth"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
)
// GetSignCommand returns the sign command
@ -27,7 +25,7 @@ $ gaiacli tx broadcast ./mytxn.json
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) (err error) {
cliCtx := context.NewCLIContext().WithCodec(codec)
stdTx, err := readAndUnmarshalStdTx(cliCtx.Codec, args[0])
stdTx, err := authclient.ReadStdTxFromFile(cliCtx.Codec, args[0])
if err != nil {
return
}
@ -45,19 +43,3 @@ $ gaiacli tx broadcast ./mytxn.json
return client.PostCommands(cmd)[0]
}
func readAndUnmarshalStdTx(cdc *amino.Codec, filename string) (stdTx auth.StdTx, err error) {
var bytes []byte
if filename == "-" {
bytes, err = ioutil.ReadAll(os.Stdin)
} else {
bytes, err = ioutil.ReadFile(filename)
}
if err != nil {
return
}
if err = cdc.UnmarshalJSON(bytes, &stdTx); err != nil {
return
}
return
}

View File

@ -0,0 +1,55 @@
package cli
import (
"encoding/base64"
"github.com/spf13/cobra"
amino "github.com/tendermint/go-amino"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
)
// PrintOutput requires a Stringer, so we wrap string
type encodeResp string
func (e encodeResp) String() string {
return string(e)
}
// GetEncodeCommand returns the encode command to take a JSONified transaction and turn it into
// Amino-serialized bytes
func GetEncodeCommand(codec *amino.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "encode [file]",
Short: "encode transactions generated offline",
Long: `Encode transactions created with the --generate-only flag and signed with the sign command.
Read a transaction from <file>, serialize it to the Amino wire protocol, and output it as base64.
If you supply a dash (-) argument in place of an input filename, the command reads from standard input.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) (err error) {
cliCtx := context.NewCLIContext().WithCodec(codec)
stdTx, err := authclient.ReadStdTxFromFile(cliCtx.Codec, args[0])
if err != nil {
return
}
txBytes, err := cliCtx.Codec.MarshalBinaryLengthPrefixed(stdTx)
if err != nil {
return err
}
// Encode the bytes to base64
txBytesBase64 := base64.StdEncoding.EncodeToString(txBytes)
// Write it back
response := encodeResp(txBytesBase64)
cliCtx.PrintOutput(response)
return nil
},
}
return client.PostCommands(cmd)[0]
}

View File

@ -16,6 +16,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/keys"
crkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/x/auth"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
)
@ -51,7 +52,7 @@ recommended to set such parameters manually.
func makeMultiSignCmd(cdc *amino.Codec) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) (err error) {
stdTx, err := readAndUnmarshalStdTx(cdc, args[0])
stdTx, err := authclient.ReadStdTxFromFile(cdc, args[0])
if err != nil {
return
}

View File

@ -3,7 +3,6 @@ package cli
import (
"errors"
"fmt"
"io/ioutil"
"os"
"github.com/spf13/cobra"
@ -15,6 +14,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/utils"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
)
@ -75,7 +75,7 @@ be generated via the 'multisign' command.
func makeSignCmd(cdc *amino.Codec) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) (err error) {
stdTx, err := readAndUnmarshalStdTx(cdc, args[0])
stdTx, err := authclient.ReadStdTxFromFile(cdc, args[0])
if err != nil {
return
}
@ -222,14 +222,3 @@ func printAndValidateSigs(
fmt.Println("")
return success
}
func readAndUnmarshalStdTx(cdc *amino.Codec, filename string) (stdTx auth.StdTx, err error) {
var bytes []byte
if bytes, err = ioutil.ReadFile(filename); err != nil {
return
}
if err = cdc.UnmarshalJSON(bytes, &stdTx); err != nil {
return
}
return
}

View File

@ -38,7 +38,7 @@ func BroadcastTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) ht
}
}
func unmarshalBodyOrReturnBadRequest(cliCtx context.CLIContext, w http.ResponseWriter, r *http.Request, m *broadcastBody) bool {
func unmarshalBodyOrReturnBadRequest(cliCtx context.CLIContext, w http.ResponseWriter, r *http.Request, m interface{}) bool {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())

View File

@ -0,0 +1,46 @@
package rest
import (
"encoding/base64"
"net/http"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/rest"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/auth"
)
type encodeReq struct {
Tx auth.StdTx `json:"tx"`
}
type encodeResp struct {
Tx string `json:"tx"`
}
// EncodeTxRequestHandlerFn returns the encode tx REST handler. In particular, it takes a
// json-formatted transaction, encodes it to the Amino wire protocol, and responds with
// base64-encoded bytes
func EncodeTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var m encodeReq
// Decode the transaction from JSON
if ok := unmarshalBodyOrReturnBadRequest(cliCtx, w, r, &m); !ok {
return
}
// Re-encode it to the wire protocol
txBytes, err := cliCtx.Codec.MarshalBinaryLengthPrefixed(m.Tx)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
// Encode the bytes to base64
txBytesBase64 := base64.StdEncoding.EncodeToString(txBytes)
// Write it back
response := encodeResp{Tx: txBytesBase64}
rest.PostProcessResponse(w, cdc, response, cliCtx.Indent)
}
}

View File

@ -22,6 +22,14 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec,
"/bank/balances/{address}",
QueryBalancesRequestHandlerFn(storeName, cdc, context.GetAccountDecoder(cdc), cliCtx),
).Methods("GET")
r.HandleFunc(
"/tx/broadcast",
BroadcastTxRequestHandlerFn(cdc, cliCtx),
).Methods("POST")
r.HandleFunc(
"/tx/encode",
EncodeTxRequestHandlerFn(cdc, cliCtx),
).Methods("POST")
r.HandleFunc(
"/tx/sign",
SignTxRequestHandlerFn(cdc, cliCtx),

27
x/auth/client/util.go Normal file
View File

@ -0,0 +1,27 @@
package client
import (
"io/ioutil"
"os"
"github.com/tendermint/go-amino"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// Read and decode a StdTx from the given filename. Can pass "-" to read from stdin.
func ReadStdTxFromFile(cdc *amino.Codec, filename string) (stdTx auth.StdTx, err error) {
var bytes []byte
if filename == "-" {
bytes, err = ioutil.ReadAll(os.Stdin)
} else {
bytes, err = ioutil.ReadFile(filename)
}
if err != nil {
return
}
if err = cdc.UnmarshalJSON(bytes, &stdTx); err != nil {
return
}
return
}

View File

@ -0,0 +1,32 @@
package client
import (
"os"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
func TestReadStdTxFromFile(t *testing.T) {
cdc := codec.New()
sdk.RegisterCodec(cdc)
// Build a test transaction
fee := auth.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)})
stdTx := auth.NewStdTx([]sdk.Msg{}, fee, []auth.StdSignature{}, "foomemo")
// Write it to the file
encodedTx, _ := cdc.MarshalJSON(stdTx)
jsonTxFile := clitest.WriteToNewTempFile(t, string(encodedTx))
defer os.Remove(jsonTxFile.Name())
// Read it back
decodedTx, err := ReadStdTxFromFile(cdc, jsonTxFile.Name())
require.Nil(t, err)
require.Equal(t, decodedTx.Memo, "foomemo")
}

View File

@ -17,7 +17,6 @@ import (
// RegisterRoutes - Central function to define routes that get registered by the main application
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec, kb keys.Keybase) {
r.HandleFunc("/bank/accounts/{address}/transfers", SendRequestHandlerFn(cdc, kb, cliCtx)).Methods("POST")
r.HandleFunc("/tx/broadcast", BroadcastTxRequestHandlerFn(cdc, cliCtx)).Methods("POST")
}
type sendReq struct {