The command processes list of transactions from file (one StdTx each line), generate signed transactions or signatures and print their JSON encoding, delimited by '\n'. As the signatures are generated, the command increments the sequence number automatically. Author: @jgimeno Reviewed-by: @alessio
216 lines
6.0 KiB
Go
216 lines
6.0 KiB
Go
package client
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"io/ioutil"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
)
|
|
|
|
var (
|
|
priv = ed25519.GenPrivKey()
|
|
addr = sdk.AccAddress(priv.PubKey().Address())
|
|
)
|
|
|
|
func TestParseQueryResponse(t *testing.T) {
|
|
simRes := &sdk.SimulationResponse{
|
|
GasInfo: sdk.GasInfo{GasUsed: 10, GasWanted: 20},
|
|
Result: &sdk.Result{Data: []byte("tx data"), Log: "log"},
|
|
}
|
|
|
|
bz, err := codec.ProtoMarshalJSON(simRes)
|
|
require.NoError(t, err)
|
|
|
|
res, err := parseQueryResponse(bz)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 10, int(res.GasInfo.GasUsed))
|
|
require.NotNil(t, res.Result)
|
|
|
|
res, err = parseQueryResponse([]byte("fuzzy"))
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestCalculateGas(t *testing.T) {
|
|
cdc := makeCodec()
|
|
makeQueryFunc := func(gasUsed uint64, wantErr bool) func(string, []byte) ([]byte, int64, error) {
|
|
return func(string, []byte) ([]byte, int64, error) {
|
|
if wantErr {
|
|
return nil, 0, errors.New("query failed")
|
|
}
|
|
simRes := &sdk.SimulationResponse{
|
|
GasInfo: sdk.GasInfo{GasUsed: gasUsed, GasWanted: gasUsed},
|
|
Result: &sdk.Result{Data: []byte("tx data"), Log: "log"},
|
|
}
|
|
|
|
bz, _ := codec.ProtoMarshalJSON(simRes)
|
|
return bz, 0, nil
|
|
}
|
|
}
|
|
|
|
type args struct {
|
|
queryFuncGasUsed uint64
|
|
queryFuncWantErr bool
|
|
adjustment float64
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
wantEstimate uint64
|
|
wantAdjusted uint64
|
|
expPass bool
|
|
}{
|
|
{"error", args{0, true, 1.2}, 0, 0, false},
|
|
{"adjusted gas", args{10, false, 1.2}, 10, 12, true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
queryFunc := makeQueryFunc(tt.args.queryFuncGasUsed, tt.args.queryFuncWantErr)
|
|
simRes, gotAdjusted, err := CalculateGas(queryFunc, cdc, []byte(""), tt.args.adjustment)
|
|
if tt.expPass {
|
|
require.NoError(t, err)
|
|
require.Equal(t, simRes.GasInfo.GasUsed, tt.wantEstimate)
|
|
require.Equal(t, gotAdjusted, tt.wantAdjusted)
|
|
require.NotNil(t, simRes.Result)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.Nil(t, simRes.Result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDefaultTxEncoder(t *testing.T) {
|
|
cdc := makeCodec()
|
|
|
|
defaultEncoder := authtypes.DefaultTxEncoder(cdc)
|
|
encoder := GetTxEncoder(cdc)
|
|
|
|
compareEncoders(t, defaultEncoder, encoder)
|
|
}
|
|
|
|
func TestConfiguredTxEncoder(t *testing.T) {
|
|
cdc := makeCodec()
|
|
|
|
customEncoder := func(tx sdk.Tx) ([]byte, error) {
|
|
return json.Marshal(tx)
|
|
}
|
|
|
|
config := sdk.GetConfig()
|
|
config.SetTxEncoder(customEncoder)
|
|
|
|
encoder := GetTxEncoder(cdc)
|
|
|
|
compareEncoders(t, customEncoder, encoder)
|
|
}
|
|
|
|
func TestReadStdTxFromFile(t *testing.T) {
|
|
t.Parallel()
|
|
cdc := codec.New()
|
|
sdk.RegisterCodec(cdc)
|
|
|
|
// Build a test transaction
|
|
fee := authtypes.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)})
|
|
stdTx := authtypes.NewStdTx([]sdk.Msg{}, fee, []authtypes.StdSignature{}, "foomemo")
|
|
|
|
// Write it to the file
|
|
encodedTx, _ := cdc.MarshalJSON(stdTx)
|
|
jsonTxFile := writeToNewTempFile(t, string(encodedTx))
|
|
defer os.Remove(jsonTxFile.Name())
|
|
|
|
// Read it back
|
|
decodedTx, err := ReadStdTxFromFile(cdc, jsonTxFile.Name())
|
|
require.NoError(t, err)
|
|
require.Equal(t, decodedTx.Memo, "foomemo")
|
|
}
|
|
|
|
func TestBatchScanner_Scan(t *testing.T) {
|
|
t.Parallel()
|
|
cdc := codec.New()
|
|
sdk.RegisterCodec(cdc)
|
|
|
|
batch1 := `{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"150"}],"gas":"50000"},"signatures":[],"memo":"foomemo"}
|
|
{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"150"}],"gas":"10000"},"signatures":[],"memo":"foomemo"}
|
|
{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"1"}],"gas":"10000"},"signatures":[],"memo":"foomemo"}
|
|
`
|
|
batch2 := `{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"150"}],"gas":"50000"},"signatures":[],"memo":"foomemo"}
|
|
malformed
|
|
{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"1"}],"gas":"10000"},"signatures":[],"memo":"foomemo"}
|
|
`
|
|
batch3 := `{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"150"}],"gas":"50000"},"signatures":[],"memo":"foomemo"}
|
|
{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"1"}],"gas":"10000"},"signatures":[],"memo":"foomemo"}`
|
|
batch4 := `{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"150"}],"gas":"50000"},"signatures":[],"memo":"foomemo"}
|
|
|
|
{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"1"}],"gas":"10000"},"signatures":[],"memo":"foomemo"}
|
|
`
|
|
tests := []struct {
|
|
name string
|
|
batch string
|
|
wantScannerError bool
|
|
wantUnmarshalError bool
|
|
numTxs int
|
|
}{
|
|
{"good batch", batch1, false, false, 3},
|
|
{"malformed", batch2, false, true, 1},
|
|
{"missing trailing newline", batch3, false, false, 2},
|
|
{"empty line", batch4, false, true, 1},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
scanner, i := NewBatchScanner(cdc, strings.NewReader(tt.batch)), 0
|
|
for scanner.Scan() {
|
|
_ = scanner.StdTx()
|
|
i++
|
|
}
|
|
|
|
require.Equal(t, tt.wantScannerError, scanner.Err() != nil)
|
|
require.Equal(t, tt.wantUnmarshalError, scanner.UnmarshalErr() != nil)
|
|
require.Equal(t, tt.numTxs, i)
|
|
})
|
|
}
|
|
}
|
|
|
|
func compareEncoders(t *testing.T, expected sdk.TxEncoder, actual sdk.TxEncoder) {
|
|
msgs := []sdk.Msg{sdk.NewTestMsg(addr)}
|
|
tx := authtypes.NewStdTx(msgs, authtypes.StdFee{}, []authtypes.StdSignature{}, "")
|
|
|
|
defaultEncoderBytes, err := expected(tx)
|
|
require.NoError(t, err)
|
|
encoderBytes, err := actual(tx)
|
|
require.NoError(t, err)
|
|
require.Equal(t, defaultEncoderBytes, encoderBytes)
|
|
}
|
|
|
|
func writeToNewTempFile(t *testing.T, data string) *os.File {
|
|
fp, err := ioutil.TempFile(os.TempDir(), "client_tx_test")
|
|
require.NoError(t, err)
|
|
|
|
_, err = fp.WriteString(data)
|
|
require.NoError(t, err)
|
|
|
|
return fp
|
|
}
|
|
|
|
func makeCodec() *codec.Codec {
|
|
var cdc = codec.New()
|
|
sdk.RegisterCodec(cdc)
|
|
cryptocodec.RegisterCrypto(cdc)
|
|
authtypes.RegisterCodec(cdc)
|
|
cdc.RegisterConcrete(sdk.TestMsg{}, "cosmos-sdk/Test", nil)
|
|
return cdc
|
|
}
|