Merge PR #1191: LCD cleanup / add LCD gas field

* remove global variables from lcd
* added make race, fix lcd race condition
* cleanup
* Five-character changelog update
This commit is contained in:
Rigel 2018-06-11 18:12:37 -07:00 committed by Christopher Goes
parent 8ece807301
commit 1b20adcd22
13 changed files with 464 additions and 430 deletions

3
.gitignore vendored
View File

@ -14,6 +14,7 @@ docs/_build
# Data - ideally these don't exist
examples/basecoin/app/data
baseapp/data/*
client/lcd/keys/*
# Testing
coverage.txt
@ -26,4 +27,4 @@ profile.out
vagrant
# Graphviz
dependency-graph.png
dependency-graph.png

View File

@ -2,6 +2,7 @@
BREAKING CHANGES
* msg.GetSignBytes() now returns bech32-encoded addresses in all cases
* [lcd] REST end-points now include gas
FEATURES
@ -9,10 +10,11 @@ IMPROVEMENTS
* export command now writes current validator set for Tendermint
* [tests] Application module tests now use a mock application
* [gaiacli] Fix error message when account isn't found when running gaiacli account
* [lcd] refactored to eliminate use of global variables, and interdependent tests
FIXES
* [lcd] Switch to bech32 for addresses on all human readable inputs and outputs
* fixed tx indexing/querying
* [lcd] fixed tx indexing/querying
* [cli] Added `--gas` flag to specify transaction gas limit
## 0.18.0

View File

@ -92,6 +92,9 @@ test_cli:
test_unit:
@go test $(PACKAGES_NOCLITEST)
test_race:
@go test -race $(PACKAGES_NOCLITEST)
test_cover:
@bash tests/test_cover.sh

View File

@ -21,6 +21,8 @@ const KeyDBName = "keys"
// keybase is used to make GetKeyBase a singleton
var keybase keys.Keybase
// TODO make keybase take a database not load from the directory
// initialize a keybase based on the configuration
func GetKeyBase() (keys.Keybase, error) {
rootDir := viper.GetString(cli.HomeFlag)

View File

@ -1,53 +0,0 @@
package lcd
// NOTE: COPIED VERBATIM FROM tendermint/tendermint/rpc/test/helpers.go
import (
"fmt"
"os"
"path/filepath"
"strings"
cmn "github.com/tendermint/tmlibs/common"
cfg "github.com/tendermint/tendermint/config"
)
var globalConfig *cfg.Config
// f**ing long, but unique for each test
func makePathname() string {
// get path
p, err := os.Getwd()
if err != nil {
panic(err)
}
// fmt.Println(p)
sep := string(filepath.Separator)
return strings.Replace(p, sep, "_", -1)
}
func randPort() int {
return int(cmn.RandUint16()/2 + 10000)
}
func makeAddrs() (string, string, string) {
start := randPort()
return fmt.Sprintf("tcp://0.0.0.0:%d", start),
fmt.Sprintf("tcp://0.0.0.0:%d", start+1),
fmt.Sprintf("tcp://0.0.0.0:%d", start+2)
}
// GetConfig returns a config for the test cases as a singleton
func GetConfig() *cfg.Config {
if globalConfig == nil {
pathname := makePathname()
globalConfig = cfg.ResetTestRoot(pathname)
// and we use random ports to run in parallel
tm, rpc, _ := makeAddrs()
globalConfig.P2P.ListenAddress = tm
globalConfig.RPC.ListenAddress = rpc
}
return globalConfig
}

View File

@ -1,146 +1,115 @@
package lcd
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"regexp"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
cryptoKeys "github.com/tendermint/go-crypto/keys"
tmcfg "github.com/tendermint/tendermint/config"
nm "github.com/tendermint/tendermint/node"
p2p "github.com/tendermint/tendermint/p2p"
pvm "github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
tmrpc "github.com/tendermint/tendermint/rpc/lib/server"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
client "github.com/cosmos/cosmos-sdk/client"
keys "github.com/cosmos/cosmos-sdk/client/keys"
rpc "github.com/cosmos/cosmos-sdk/client/rpc"
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
tests "github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/stake"
stakerest "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
)
var (
coinDenom = "steak"
coinAmount = int64(10000000)
validatorAddr1Hx = ""
validatorAddr2Hx = ""
validatorAddr1 = ""
validatorAddr2 = ""
// XXX bad globals
name = "test"
password = "0123456789"
port string
seed string
sendAddr string
)
func TestKeys(t *testing.T) {
// empty keys
// XXX: the test comes with a key setup
/*
res, body := request(t, port, "GET", "/keys", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
assert.Equal(t, "[]", body, "Expected an empty array")
*/
name, password := "test", "1234567890"
addr, seed := CreateAddr(t, "test", password, GetKB(t))
cleanup, _, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
defer cleanup()
// get seed
res, body := request(t, port, "GET", "/keys/seed", nil)
res, body := Request(t, port, "GET", "/keys/seed", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
newSeed := body
reg, err := regexp.Compile(`([a-z]+ ){12}`)
require.Nil(t, err)
match := reg.MatchString(seed)
assert.True(t, match, "Returned seed has wrong foramt", seed)
assert.True(t, match, "Returned seed has wrong format", seed)
newName := "test_newname"
newPassword := "0987654321"
// add key
var jsonStr = []byte(fmt.Sprintf(`{"name":"test_fail", "password":"%s"}`, password))
res, body = request(t, port, "POST", "/keys", jsonStr)
res, body = Request(t, port, "POST", "/keys", jsonStr)
assert.Equal(t, http.StatusBadRequest, res.StatusCode, "Account creation should require a seed")
jsonStr = []byte(fmt.Sprintf(`{"name":"%s", "password":"%s", "seed": "%s"}`, newName, newPassword, newSeed))
res, body = request(t, port, "POST", "/keys", jsonStr)
res, body = Request(t, port, "POST", "/keys", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
addr := body
assert.Len(t, addr, 40, "Returned address has wrong format", addr)
addr2 := body
assert.Len(t, addr2, 40, "Returned address has wrong format", addr2)
// existing keys
res, body = request(t, port, "GET", "/keys", nil)
res, body = Request(t, port, "GET", "/keys", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var m [2]keys.KeyOutput
err = cdc.UnmarshalJSON([]byte(body), &m)
require.Nil(t, err)
addrAcc, _ := sdk.GetAccAddressHex(addr)
addrBech32, _ := sdk.Bech32ifyAcc(addrAcc)
addr2Acc, err := sdk.GetAccAddressHex(addr2)
require.Nil(t, err)
addr2Bech32 := sdk.MustBech32ifyAcc(addr2Acc)
addrBech32 := sdk.MustBech32ifyAcc(addr)
assert.Equal(t, name, m[0].Name, "Did not serve keys name correctly")
assert.Equal(t, sendAddr, m[0].Address, "Did not serve keys Address correctly")
assert.Equal(t, addrBech32, m[0].Address, "Did not serve keys Address correctly")
assert.Equal(t, newName, m[1].Name, "Did not serve keys name correctly")
assert.Equal(t, addrBech32, m[1].Address, "Did not serve keys Address correctly")
assert.Equal(t, addr2Bech32, m[1].Address, "Did not serve keys Address correctly")
// select key
keyEndpoint := fmt.Sprintf("/keys/%s", newName)
res, body = request(t, port, "GET", keyEndpoint, nil)
res, body = Request(t, port, "GET", keyEndpoint, nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var m2 keys.KeyOutput
err = cdc.UnmarshalJSON([]byte(body), &m2)
require.Nil(t, err)
assert.Equal(t, newName, m2.Name, "Did not serve keys name correctly")
assert.Equal(t, addrBech32, m2.Address, "Did not serve keys Address correctly")
assert.Equal(t, addr2Bech32, m2.Address, "Did not serve keys Address correctly")
// update key
jsonStr = []byte(fmt.Sprintf(`{"old_password":"%s", "new_password":"12345678901"}`, newPassword))
res, body = request(t, port, "PUT", keyEndpoint, jsonStr)
jsonStr = []byte(fmt.Sprintf(`{
"old_password":"%s",
"new_password":"12345678901"
}`, newPassword))
res, body = Request(t, port, "PUT", keyEndpoint, jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
// here it should say unauthorized as we changed the password before
res, body = request(t, port, "PUT", keyEndpoint, jsonStr)
res, body = Request(t, port, "PUT", keyEndpoint, jsonStr)
require.Equal(t, http.StatusUnauthorized, res.StatusCode, body)
// delete key
jsonStr = []byte(`{"password":"12345678901"}`)
res, body = request(t, port, "DELETE", keyEndpoint, jsonStr)
res, body = Request(t, port, "DELETE", keyEndpoint, jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
}
func TestVersion(t *testing.T) {
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{})
defer cleanup()
// node info
res, body := request(t, port, "GET", "/version", nil)
res, body := Request(t, port, "GET", "/version", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
reg, err := regexp.Compile(`\d+\.\d+\.\d+(-dev)?`)
@ -150,9 +119,11 @@ func TestVersion(t *testing.T) {
}
func TestNodeStatus(t *testing.T) {
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{})
defer cleanup()
// node info
res, body := request(t, port, "GET", "/node_info", nil)
res, body := Request(t, port, "GET", "/node_info", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var nodeInfo p2p.NodeInfo
@ -162,21 +133,20 @@ func TestNodeStatus(t *testing.T) {
assert.NotEqual(t, p2p.NodeInfo{}, nodeInfo, "res: %v", res)
// syncing
res, body = request(t, port, "GET", "/syncing", nil)
res, body = Request(t, port, "GET", "/syncing", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
// we expect that there is no other node running so the syncing state is "false"
// we c
assert.Equal(t, "false", body)
}
func TestBlock(t *testing.T) {
tests.WaitForHeight(2, port)
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{})
defer cleanup()
var resultBlock ctypes.ResultBlock
res, body := request(t, port, "GET", "/blocks/latest", nil)
res, body := Request(t, port, "GET", "/blocks/latest", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err := cdc.UnmarshalJSON([]byte(body), &resultBlock)
@ -186,7 +156,7 @@ func TestBlock(t *testing.T) {
// --
res, body = request(t, port, "GET", "/blocks/1", nil)
res, body = Request(t, port, "GET", "/blocks/1", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = json.Unmarshal([]byte(body), &resultBlock)
@ -196,15 +166,17 @@ func TestBlock(t *testing.T) {
// --
res, body = request(t, port, "GET", "/blocks/1000000000", nil)
res, body = Request(t, port, "GET", "/blocks/1000000000", nil)
require.Equal(t, http.StatusNotFound, res.StatusCode, body)
}
func TestValidators(t *testing.T) {
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{})
defer cleanup()
var resultVals rpc.ResultValidatorsOutput
res, body := request(t, port, "GET", "/validatorsets/latest", nil)
res, body := Request(t, port, "GET", "/validatorsets/latest", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err := cdc.UnmarshalJSON([]byte(body), &resultVals)
@ -217,7 +189,7 @@ func TestValidators(t *testing.T) {
// --
res, body = request(t, port, "GET", "/validatorsets/1", nil)
res, body = Request(t, port, "GET", "/validatorsets/1", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = cdc.UnmarshalJSON([]byte(body), &resultVals)
@ -227,23 +199,29 @@ func TestValidators(t *testing.T) {
// --
res, body = request(t, port, "GET", "/validatorsets/1000000000", nil)
res, body = Request(t, port, "GET", "/validatorsets/1000000000", nil)
require.Equal(t, http.StatusNotFound, res.StatusCode)
}
func TestCoinSend(t *testing.T) {
bz, _ := hex.DecodeString("8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6")
someFakeAddr, _ := sdk.Bech32ifyAcc(bz)
name, password := "test", "1234567890"
addr, seed := CreateAddr(t, "test", password, GetKB(t))
cleanup, _, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
defer cleanup()
bz, err := hex.DecodeString("8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6")
require.NoError(t, err)
someFakeAddr := sdk.MustBech32ifyAcc(bz)
// query empty
res, body := request(t, port, "GET", "/accounts/"+someFakeAddr, nil)
res, body := Request(t, port, "GET", "/accounts/"+someFakeAddr, nil)
require.Equal(t, http.StatusNoContent, res.StatusCode, body)
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, addr)
initialBalance := acc.GetCoins()
// create TX
receiveAddr, resultTx := doSend(t, port)
receiveAddr, resultTx := doSend(t, port, seed, name, password, addr)
tests.WaitForHeight(resultTx.Height+1, port)
// check if tx was commited
@ -251,27 +229,31 @@ func TestCoinSend(t *testing.T) {
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
// query sender
acc = getAccount(t, sendAddr)
acc = getAccount(t, port, addr)
coins := acc.GetCoins()
mycoins := coins[0]
assert.Equal(t, coinDenom, mycoins.Denom)
assert.Equal(t, "steak", mycoins.Denom)
assert.Equal(t, initialBalance[0].Amount-1, mycoins.Amount)
// query receiver
acc = getAccount(t, receiveAddr)
acc = getAccount(t, port, receiveAddr)
coins = acc.GetCoins()
mycoins = coins[0]
assert.Equal(t, coinDenom, mycoins.Denom)
assert.Equal(t, "steak", mycoins.Denom)
assert.Equal(t, int64(1), mycoins.Amount)
}
func TestIBCTransfer(t *testing.T) {
name, password := "test", "1234567890"
addr, seed := CreateAddr(t, "test", password, GetKB(t))
cleanup, _, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
defer cleanup()
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, addr)
initialBalance := acc.GetCoins()
// create TX
resultTx := doIBCTransfer(t, port, seed)
resultTx := doIBCTransfer(t, port, seed, name, password, addr)
tests.WaitForHeight(resultTx.Height+1, port)
@ -280,32 +262,37 @@ func TestIBCTransfer(t *testing.T) {
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
// query sender
acc = getAccount(t, sendAddr)
acc = getAccount(t, port, addr)
coins := acc.GetCoins()
mycoins := coins[0]
assert.Equal(t, coinDenom, mycoins.Denom)
assert.Equal(t, "steak", mycoins.Denom)
assert.Equal(t, initialBalance[0].Amount-1, mycoins.Amount)
// TODO: query ibc egress packet state
}
func TestTxs(t *testing.T) {
name, password := "test", "1234567890"
addr, seed := CreateAddr(t, "test", password, GetKB(t))
cleanup, _, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
defer cleanup()
// query wrong
res, body := request(t, port, "GET", "/txs", nil)
res, body := Request(t, port, "GET", "/txs", nil)
require.Equal(t, http.StatusBadRequest, res.StatusCode, body)
// query empty
res, body = request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", "cosmosaccaddr1jawd35d9aq4u76sr3fjalmcqc8hqygs9gtnmv3"), nil)
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", "cosmosaccaddr1jawd35d9aq4u76sr3fjalmcqc8hqygs9gtnmv3"), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
assert.Equal(t, "[]", body)
// create TX
receiveAddr, resultTx := doSend(t, port)
receiveAddr, resultTx := doSend(t, port, seed, name, password, addr)
tests.WaitForHeight(resultTx.Height+1, port)
// check if tx is findable
res, body = request(t, port, "GET", fmt.Sprintf("/txs/%s", resultTx.Hash), nil)
res, body = Request(t, port, "GET", fmt.Sprintf("/txs/%s", resultTx.Hash), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
type txInfo struct {
@ -316,53 +303,67 @@ func TestTxs(t *testing.T) {
var indexedTxs []txInfo
// check if tx is queryable
res, body = request(t, port, "GET", fmt.Sprintf("/txs?tag=tx.hash='%s'", resultTx.Hash), nil)
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=tx.hash='%s'", resultTx.Hash), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
assert.NotEqual(t, "[]", body)
err := cdc.UnmarshalJSON([]byte(body), &indexedTxs)
require.NoError(t, err)
assert.Equal(t, len(indexedTxs), 1)
assert.Equal(t, 1, len(indexedTxs))
// query sender
res, body = request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", sendAddr), nil)
addrBech := sdk.MustBech32ifyAcc(addr)
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", addrBech), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = cdc.UnmarshalJSON([]byte(body), &indexedTxs)
require.NoError(t, err)
assert.Equal(t, 2, len(indexedTxs)) // there are 2 txs created with doSend
assert.Equal(t, resultTx.Height, indexedTxs[1].Height)
require.Equal(t, 1, len(indexedTxs), "%v", indexedTxs) // there are 2 txs created with doSend
assert.Equal(t, resultTx.Height, indexedTxs[0].Height)
// query recipient
res, body = request(t, port, "GET", fmt.Sprintf("/txs?tag=recipient_bech32='%s'", receiveAddr), nil)
receiveAddrBech := sdk.MustBech32ifyAcc(receiveAddr)
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=recipient_bech32='%s'", receiveAddrBech), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = cdc.UnmarshalJSON([]byte(body), &indexedTxs)
require.NoError(t, err)
assert.Equal(t, 1, len(indexedTxs))
require.Equal(t, 1, len(indexedTxs))
assert.Equal(t, resultTx.Height, indexedTxs[0].Height)
}
func TestValidatorsQuery(t *testing.T) {
validators := getValidators(t)
cleanup, pks, port := InitializeTestLCD(t, 2, []sdk.Address{})
require.Equal(t, 2, len(pks))
defer cleanup()
validators := getValidators(t, port)
assert.Equal(t, len(validators), 2)
// make sure all the validators were found (order unknown because sorted by owner addr)
foundVal1, foundVal2 := false, false
if validators[0].Owner == validatorAddr1 || validators[1].Owner == validatorAddr1 {
pk1Bech := sdk.MustBech32ifyValPub(pks[0])
pk2Bech := sdk.MustBech32ifyValPub(pks[1])
if validators[0].PubKey == pk1Bech || validators[1].PubKey == pk1Bech {
foundVal1 = true
}
if validators[0].Owner == validatorAddr2 || validators[1].Owner == validatorAddr2 {
if validators[0].PubKey == pk2Bech || validators[1].PubKey == pk2Bech {
foundVal2 = true
}
assert.True(t, foundVal1, "validatorAddr1 %v, owner1 %v, owner2 %v", validatorAddr1, validators[0].Owner, validators[1].Owner)
assert.True(t, foundVal2, "validatorAddr2 %v, owner1 %v, owner2 %v", validatorAddr2, validators[0].Owner, validators[1].Owner)
assert.True(t, foundVal1, "pk1Bech %v, owner1 %v, owner2 %v", pk1Bech, validators[0].Owner, validators[1].Owner)
assert.True(t, foundVal2, "pk2Bech %v, owner1 %v, owner2 %v", pk2Bech, validators[0].Owner, validators[1].Owner)
}
func TestBond(t *testing.T) {
func TestBonding(t *testing.T) {
name, password, denom := "test", "1234567890", "steak"
addr, seed := CreateAddr(t, "test", password, GetKB(t))
cleanup, pks, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
defer cleanup()
validator1Owner := pks[0].Address()
// create bond TX
resultTx := doBond(t, port, seed)
resultTx := doBond(t, port, seed, name, password, addr, validator1Owner)
tests.WaitForHeight(resultTx.Height+1, port)
// check if tx was commited
@ -370,201 +371,41 @@ func TestBond(t *testing.T) {
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
// query sender
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, addr)
coins := acc.GetCoins()
assert.Equal(t, int64(87), coins.AmountOf(coinDenom))
assert.Equal(t, int64(40), coins.AmountOf(denom))
// query candidate
bond := getDelegation(t, sendAddr, validatorAddr1)
assert.Equal(t, "10/1", bond.Shares.String())
}
// query validator
bond := getDelegation(t, port, addr, validator1Owner)
assert.Equal(t, "60/1", bond.Shares.String())
func TestUnbond(t *testing.T) {
//////////////////////
// testing unbonding
// create unbond TX
resultTx := doUnbond(t, port, seed)
resultTx = doUnbond(t, port, seed, name, password, addr, validator1Owner)
tests.WaitForHeight(resultTx.Height+1, port)
// query validator
bond = getDelegation(t, port, addr, validator1Owner)
assert.Equal(t, "30/1", bond.Shares.String())
// check if tx was commited
assert.Equal(t, uint32(0), resultTx.CheckTx.Code)
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
// TODO fix shares fn in staking
// query sender
acc := getAccount(t, sendAddr)
coins := acc.GetCoins()
assert.Equal(t, int64(98), coins.AmountOf(coinDenom))
// query candidate
bond := getDelegation(t, sendAddr, validatorAddr1)
assert.Equal(t, "9/1", bond.Shares.String())
//acc = getAccount(t, port, addr)
//coins = acc.GetCoins()
//assert.Equal(t, int64(70), coins.AmountOf(denom))
}
//__________________________________________________________
// helpers
// strt TM and the LCD in process, listening on their respective sockets
func startTMAndLCD() (*nm.Node, net.Listener, error) {
dir, err := ioutil.TempDir("", "lcd_test")
if err != nil {
return nil, nil, err
}
viper.Set(cli.HomeFlag, dir)
viper.Set(client.FlagGas, 200000)
kb, err := keys.GetKeyBase() // dbm.NewMemDB()) // :(
if err != nil {
return nil, nil, err
}
config := GetConfig()
config.Consensus.TimeoutCommit = 1000
config.Consensus.SkipTimeoutCommit = false
config.TxIndex.IndexAllTags = true
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger = log.NewFilter(logger, log.AllowError())
privValidatorFile := config.PrivValidatorFile()
privVal := pvm.LoadOrGenFilePV(privValidatorFile)
db := dbm.NewMemDB()
app := gapp.NewGaiaApp(logger, db)
cdc = gapp.MakeCodec() // XXX
genesisFile := config.GenesisFile()
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
if err != nil {
return nil, nil, err
}
genDoc.Validators = append(genDoc.Validators,
tmtypes.GenesisValidator{
PubKey: crypto.GenPrivKeyEd25519().PubKey(),
Power: 1,
Name: "val",
},
)
pk1 := genDoc.Validators[0].PubKey
pk2 := genDoc.Validators[1].PubKey
validatorAddr1Hx = hex.EncodeToString(pk1.Address())
validatorAddr2Hx = hex.EncodeToString(pk2.Address())
validatorAddr1, _ = sdk.Bech32ifyVal(pk1.Address())
validatorAddr2, _ = sdk.Bech32ifyVal(pk2.Address())
// NOTE it's bad practice to reuse pk address for the owner address but doing in the
// test for simplicity
var appGenTxs [2]json.RawMessage
appGenTxs[0], _, _, err = gapp.GaiaAppGenTxNF(cdc, pk1, pk1.Address(), "test_val1", true)
if err != nil {
return nil, nil, err
}
appGenTxs[1], _, _, err = gapp.GaiaAppGenTxNF(cdc, pk2, pk2.Address(), "test_val2", true)
if err != nil {
return nil, nil, err
}
genesisState, err := gapp.GaiaAppGenState(cdc, appGenTxs[:])
if err != nil {
return nil, nil, err
}
// add the sendAddr to genesis
var info cryptoKeys.Info
info, seed, err = kb.Create(name, password, cryptoKeys.AlgoEd25519) // XXX global seed
if err != nil {
return nil, nil, err
}
sendAddrHex, _ := sdk.GetAccAddressHex(info.PubKey.Address().String())
sendAddr, _ = sdk.Bech32ifyAcc(sendAddrHex) // XXX global
accAuth := auth.NewBaseAccountWithAddress(info.PubKey.Address())
accAuth.Coins = sdk.Coins{{"steak", 100}}
acc := gapp.NewGenesisAccount(&accAuth)
genesisState.Accounts = append(genesisState.Accounts, acc)
appState, err := wire.MarshalJSONIndent(cdc, genesisState)
if err != nil {
return nil, nil, err
}
genDoc.AppStateJSON = appState
// LCD listen address
var listenAddr string
listenAddr, port, err = server.FreeTCPAddr()
if err != nil {
return nil, nil, err
}
// XXX: need to set this so LCD knows the tendermint node address!
viper.Set(client.FlagNode, config.RPC.ListenAddress)
viper.Set(client.FlagChainID, genDoc.ChainID)
node, err := startTM(config, logger, genDoc, privVal, app)
if err != nil {
return nil, nil, err
}
lcd, err := startLCD(logger, listenAddr, cdc)
if err != nil {
return nil, nil, err
}
tests.WaitForStart(port)
return node, lcd, nil
}
// Create & start in-process tendermint node with memdb
// and in-process abci application.
// TODO: need to clean up the WAL dir or enable it to be not persistent
func startTM(cfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, privVal tmtypes.PrivValidator, app abci.Application) (*nm.Node, error) {
genDocProvider := func() (*tmtypes.GenesisDoc, error) { return genDoc, nil }
dbProvider := func(*nm.DBContext) (dbm.DB, error) { return dbm.NewMemDB(), nil }
n, err := nm.NewNode(cfg,
privVal,
proxy.NewLocalClientCreator(app),
genDocProvider,
dbProvider,
logger.With("module", "node"))
if err != nil {
return nil, err
}
err = n.Start()
if err != nil {
return nil, err
}
// wait for rpc
tests.WaitForRPC(GetConfig().RPC.ListenAddress)
logger.Info("Tendermint running!")
return n, err
}
// start the LCD. note this blocks!
func startLCD(logger log.Logger, listenAddr string, cdc *wire.Codec) (net.Listener, error) {
handler := createHandler(cdc)
return tmrpc.StartHTTPServer(listenAddr, handler, logger)
}
func request(t *testing.T, port, method, path string, payload []byte) (*http.Response, string) {
var res *http.Response
var err error
url := fmt.Sprintf("http://localhost:%v%v", port, path)
req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
require.Nil(t, err)
res, err = http.DefaultClient.Do(req)
// res, err = http.Post(url, "application/json", bytes.NewBuffer(payload))
require.Nil(t, err)
output, err := ioutil.ReadAll(res.Body)
res.Body.Close()
require.Nil(t, err)
return res, string(output)
}
func getAccount(t *testing.T, sendAddr string) auth.Account {
// get the account to get the sequence
res, body := request(t, port, "GET", "/accounts/"+sendAddr, nil)
//_____________________________________________________________________________
// get the account to get the sequence
func getAccount(t *testing.T, port string, addr sdk.Address) auth.Account {
addrBech32 := sdk.MustBech32ifyAcc(addr)
res, body := Request(t, port, "GET", "/accounts/"+addrBech32, nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var acc auth.Account
err := cdc.UnmarshalJSON([]byte(body), &acc)
@ -572,20 +413,32 @@ func getAccount(t *testing.T, sendAddr string) auth.Account {
return acc
}
func doSend(t *testing.T, port string) (receiveAddr string, resultTx ctypes.ResultBroadcastTxCommit) {
func doSend(t *testing.T, port, seed, name, password string, addr sdk.Address) (receiveAddr sdk.Address, resultTx ctypes.ResultBroadcastTxCommit) {
// create receive address
kb := client.MockKeyBase()
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
require.Nil(t, err)
receiveAddr, _ = sdk.Bech32ifyAcc(receiveInfo.PubKey.Address())
receiveAddr = receiveInfo.PubKey.Address()
receiveAddrBech := sdk.MustBech32ifyAcc(receiveAddr)
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, addr)
sequence := acc.GetSequence()
// send
jsonStr := []byte(fmt.Sprintf(`{ "name":"%s", "password":"%s", "sequence":%d, "amount":[{ "denom": "%s", "amount": 1 }] }`, name, password, sequence, coinDenom))
res, body := request(t, port, "POST", "/accounts/"+receiveAddr+"/send", jsonStr)
jsonStr := []byte(fmt.Sprintf(`{
"name":"%s",
"password":"%s",
"sequence":%d,
"gas": 10000,
"amount":[
{
"denom": "%s",
"amount": 1
}
]
}`, name, password, sequence, "steak"))
res, body := Request(t, port, "POST", "/accounts/"+receiveAddrBech+"/send", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = cdc.UnmarshalJSON([]byte(body), &resultTx)
@ -594,20 +447,32 @@ func doSend(t *testing.T, port string) (receiveAddr string, resultTx ctypes.Resu
return receiveAddr, resultTx
}
func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Address) (resultTx ctypes.ResultBroadcastTxCommit) {
// create receive address
kb := client.MockKeyBase()
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
require.Nil(t, err)
receiveAddr, _ := sdk.Bech32ifyAcc(receiveInfo.PubKey.Address())
receiveAddr := receiveInfo.PubKey.Address()
receiveAddrBech := sdk.MustBech32ifyAcc(receiveAddr)
// get the account to get the sequence
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, addr)
sequence := acc.GetSequence()
// send
jsonStr := []byte(fmt.Sprintf(`{ "name":"%s", "password":"%s", "sequence":%d, "amount":[{ "denom": "%s", "amount": 1 }] }`, name, password, sequence, coinDenom))
res, body := request(t, port, "POST", "/ibc/testchain/"+receiveAddr+"/send", jsonStr)
jsonStr := []byte(fmt.Sprintf(`{
"name":"%s",
"password": "%s",
"sequence": %d,
"gas": 100000,
"amount":[
{
"denom": "%s",
"amount": 1
}
]
}`, name, password, sequence, "steak"))
res, body := Request(t, port, "POST", "/ibc/testchain/"+receiveAddrBech+"/send", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = cdc.UnmarshalJSON([]byte(body), &resultTx)
@ -616,9 +481,13 @@ func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroad
return resultTx
}
func getDelegation(t *testing.T, delegatorAddr, candidateAddr string) stake.Delegation {
func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.Address) stake.Delegation {
delegatorAddrBech := sdk.MustBech32ifyAcc(delegatorAddr)
validatorAddrBech := sdk.MustBech32ifyVal(validatorAddr)
// get the account to get the sequence
res, body := request(t, port, "GET", "/stake/"+delegatorAddr+"/bonding_status/"+candidateAddr, nil)
res, body := Request(t, port, "GET", "/stake/"+delegatorAddrBech+"/bonding_status/"+validatorAddrBech, nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var bond stake.Delegation
err := cdc.UnmarshalJSON([]byte(body), &bond)
@ -626,26 +495,30 @@ func getDelegation(t *testing.T, delegatorAddr, candidateAddr string) stake.Dele
return bond
}
func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
func doBond(t *testing.T, port, seed, name, password string, delegatorAddr, validatorAddr sdk.Address) (resultTx ctypes.ResultBroadcastTxCommit) {
// get the account to get the sequence
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, delegatorAddr)
sequence := acc.GetSequence()
delegatorAddrBech := sdk.MustBech32ifyAcc(delegatorAddr)
validatorAddrBech := sdk.MustBech32ifyVal(validatorAddr)
// send
jsonStr := []byte(fmt.Sprintf(`{
"name": "%s",
"password": "%s",
"sequence": %d,
"gas": 10000,
"delegate": [
{
"delegator_addr": "%s",
"validator_addr": "%s",
"bond": { "denom": "%s", "amount": 10 }
"bond": { "denom": "%s", "amount": 60 }
}
],
"unbond": []
}`, name, password, sequence, sendAddr, validatorAddr1, coinDenom))
res, body := request(t, port, "POST", "/stake/delegations", jsonStr)
}`, name, password, sequence, delegatorAddrBech, validatorAddrBech, "steak"))
res, body := Request(t, port, "POST", "/stake/delegations", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results []ctypes.ResultBroadcastTxCommit
@ -655,26 +528,30 @@ func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxC
return results[0]
}
func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
func doUnbond(t *testing.T, port, seed, name, password string, delegatorAddr, validatorAddr sdk.Address) (resultTx ctypes.ResultBroadcastTxCommit) {
// get the account to get the sequence
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, delegatorAddr)
sequence := acc.GetSequence()
delegatorAddrBech := sdk.MustBech32ifyAcc(delegatorAddr)
validatorAddrBech := sdk.MustBech32ifyVal(validatorAddr)
// send
jsonStr := []byte(fmt.Sprintf(`{
"name": "%s",
"password": "%s",
"sequence": %d,
"bond": [],
"gas": 10000,
"delegate": [],
"unbond": [
{
"delegator_addr": "%s",
"validator_addr": "%s",
"shares": "1"
"shares": "30"
}
]
}`, name, password, sequence, sendAddr, validatorAddr1))
res, body := request(t, port, "POST", "/stake/delegations", jsonStr)
}`, name, password, sequence, delegatorAddrBech, validatorAddrBech))
res, body := Request(t, port, "POST", "/stake/delegations", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results []ctypes.ResultBroadcastTxCommit
@ -684,9 +561,9 @@ func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastT
return results[0]
}
func getValidators(t *testing.T) []stakerest.StakeValidatorOutput {
func getValidators(t *testing.T, port string) []stakerest.StakeValidatorOutput {
// get the account to get the sequence
res, body := request(t, port, "GET", "/stake/validators", nil)
res, body := Request(t, port, "GET", "/stake/validators", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var validators []stakerest.StakeValidatorOutput
err := cdc.UnmarshalJSON([]byte(body), &validators)

View File

@ -1,38 +0,0 @@
package lcd
import (
"fmt"
"os"
"testing"
nm "github.com/tendermint/tendermint/node"
)
var node *nm.Node
// See https://golang.org/pkg/testing/#hdr-Main
// for more details
func TestMain(m *testing.M) {
// start a basecoind node and LCD server in the background to test against
// run all the tests against a single server instance
node, lcd, err := startTMAndLCD()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
code := m.Run()
// tear down
// TODO: cleanup
// TODO: it would be great if TM could run without
// persiting anything in the first place
node.Stop()
node.Wait()
// just a listener ...
lcd.Close()
os.Exit(code)
}

View File

@ -25,19 +25,34 @@ import (
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
)
const (
flagListenAddr = "laddr"
flagCORS = "cors"
)
// ServeCommand will generate a long-running rest server
// (aka Light Client Daemon) that exposes functionality similar
// to the cli, but over rest
func ServeCommand(cdc *wire.Codec) *cobra.Command {
flagListenAddr := "laddr"
flagCORS := "cors"
cmd := &cobra.Command{
Use: "rest-server",
Short: "Start LCD (light-client daemon), a local REST server",
RunE: startRESTServerFn(cdc),
RunE: func(cmd *cobra.Command, args []string) error {
listenAddr := viper.GetString(flagListenAddr)
handler := createHandler(cdc)
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).
With("module", "rest-server")
listener, err := tmserver.StartHTTPServer(listenAddr, handler, logger)
if err != nil {
return err
}
logger.Info("REST server started")
// Wait forever and cleanup
cmn.TrapSignal(func() {
err := listener.Close()
logger.Error("Error closing listener", "err", err)
})
return nil
},
}
cmd.Flags().StringP(flagListenAddr, "a", "tcp://localhost:1317", "Address for server to listen on")
cmd.Flags().String(flagCORS, "", "Set to domains that can make CORS requests (* for all)")
@ -46,27 +61,6 @@ func ServeCommand(cdc *wire.Codec) *cobra.Command {
return cmd
}
func startRESTServerFn(cdc *wire.Codec) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
listenAddr := viper.GetString(flagListenAddr)
handler := createHandler(cdc)
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).
With("module", "rest-server")
listener, err := tmserver.StartHTTPServer(listenAddr, handler, logger)
if err != nil {
return err
}
logger.Info("REST server started")
// Wait forever and cleanup
cmn.TrapSignal(func() {
err := listener.Close()
logger.Error("Error closing listener", "err", err)
})
return nil
}
}
func createHandler(cdc *wire.Codec) http.Handler {
r := mux.NewRouter()
r.HandleFunc("/version", version.RequestHandler).Methods("GET")

234
client/lcd/test_helpers.go Normal file
View File

@ -0,0 +1,234 @@
package lcd
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"path/filepath"
"strings"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
crkeys "github.com/tendermint/go-crypto/keys"
tmcfg "github.com/tendermint/tendermint/config"
nm "github.com/tendermint/tendermint/node"
pvm "github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
tmrpc "github.com/tendermint/tendermint/rpc/lib/server"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
"github.com/cosmos/cosmos-sdk/client"
keys "github.com/cosmos/cosmos-sdk/client/keys"
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// f**ing long, but unique for each test
func makePathname() string {
// get path
p, err := os.Getwd()
if err != nil {
panic(err)
}
sep := string(filepath.Separator)
return strings.Replace(p, sep, "_", -1)
}
// GetConfig returns a config for the test cases as a singleton
func GetConfig() *tmcfg.Config {
pathname := makePathname()
config := tmcfg.ResetTestRoot(pathname)
tmAddr, _, err := server.FreeTCPAddr()
if err != nil {
panic(err)
}
rcpAddr, _, err := server.FreeTCPAddr()
if err != nil {
panic(err)
}
config.P2P.ListenAddress = tmAddr
config.RPC.ListenAddress = rcpAddr
return config
}
// get the lcd test keybase
// note can't use a memdb because the request is expecting to interact with the default location
func GetKB(t *testing.T) crkeys.Keybase {
dir, err := ioutil.TempDir("", "lcd_test")
require.NoError(t, err)
viper.Set(cli.HomeFlag, dir)
keybase, err := keys.GetKeyBase() // dbm.NewMemDB()) // :(
require.NoError(t, err)
return keybase
}
// add an address to the store return name and password
func CreateAddr(t *testing.T, name, password string, kb crkeys.Keybase) (addr sdk.Address, seed string) {
var info crkeys.Info
var err error
info, seed, err = kb.Create(name, password, crkeys.AlgoEd25519)
require.NoError(t, err)
addr = info.PubKey.Address()
return
}
// strt TM and the LCD in process, listening on their respective sockets
// nValidators = number of validators
// initAddrs = accounts to initialize with some steaks
func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.Address) (cleanup func(), validatorsPKs []crypto.PubKey, port string) {
config := GetConfig()
config.Consensus.TimeoutCommit = 1000
config.Consensus.SkipTimeoutCommit = false
config.TxIndex.IndexAllTags = true
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger = log.NewFilter(logger, log.AllowError())
privValidatorFile := config.PrivValidatorFile()
privVal := pvm.LoadOrGenFilePV(privValidatorFile)
privVal.Reset()
db := dbm.NewMemDB()
app := gapp.NewGaiaApp(logger, db)
cdc = gapp.MakeCodec() // XXX
genesisFile := config.GenesisFile()
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
require.NoError(t, err)
// add more validators
if nValidators < 1 {
panic("InitializeTestLCD must use at least one validator")
}
for i := 1; i < nValidators; i++ {
genDoc.Validators = append(genDoc.Validators,
tmtypes.GenesisValidator{
PubKey: crypto.GenPrivKeyEd25519().PubKey(),
Power: 1,
Name: "val",
},
)
}
// NOTE it's bad practice to reuse pk address for the owner address but doing in the
// test for simplicity
var appGenTxs []json.RawMessage
for _, gdValidator := range genDoc.Validators {
pk := gdValidator.PubKey
validatorsPKs = append(validatorsPKs, pk) // append keys for output
appGenTx, _, _, err := gapp.GaiaAppGenTxNF(cdc, pk, pk.Address(), "test_val1", true)
require.NoError(t, err)
appGenTxs = append(appGenTxs, appGenTx)
}
genesisState, err := gapp.GaiaAppGenState(cdc, appGenTxs[:])
require.NoError(t, err)
// add some tokens to init accounts
for _, addr := range initAddrs {
accAuth := auth.NewBaseAccountWithAddress(addr)
accAuth.Coins = sdk.Coins{{"steak", 100}}
acc := gapp.NewGenesisAccount(&accAuth)
genesisState.Accounts = append(genesisState.Accounts, acc)
}
appState, err := wire.MarshalJSONIndent(cdc, genesisState)
require.NoError(t, err)
genDoc.AppStateJSON = appState
// LCD listen address
var listenAddr string
listenAddr, port, err = server.FreeTCPAddr()
require.NoError(t, err)
// XXX: need to set this so LCD knows the tendermint node address!
viper.Set(client.FlagNode, config.RPC.ListenAddress)
viper.Set(client.FlagChainID, genDoc.ChainID)
node, err := startTM(config, logger, genDoc, privVal, app)
require.NoError(t, err)
lcd, err := startLCD(logger, listenAddr, cdc)
require.NoError(t, err)
//time.Sleep(time.Second)
//tests.WaitForHeight(2, port)
tests.WaitForStart(port)
tests.WaitForHeight(1, port)
// for use in defer
cleanup = func() {
node.Stop()
node.Wait()
lcd.Close()
}
return
}
// Create & start in-process tendermint node with memdb
// and in-process abci application.
// TODO: need to clean up the WAL dir or enable it to be not persistent
func startTM(tmcfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, privVal tmtypes.PrivValidator, app abci.Application) (*nm.Node, error) {
genDocProvider := func() (*tmtypes.GenesisDoc, error) { return genDoc, nil }
dbProvider := func(*nm.DBContext) (dbm.DB, error) { return dbm.NewMemDB(), nil }
n, err := nm.NewNode(tmcfg,
privVal,
proxy.NewLocalClientCreator(app),
genDocProvider,
dbProvider,
logger.With("module", "node"))
if err != nil {
return nil, err
}
err = n.Start()
if err != nil {
return nil, err
}
// wait for rpc
tests.WaitForRPC(tmcfg.RPC.ListenAddress)
logger.Info("Tendermint running!")
return n, err
}
// start the LCD. note this blocks!
func startLCD(logger log.Logger, listenAddr string, cdc *wire.Codec) (net.Listener, error) {
handler := createHandler(cdc)
return tmrpc.StartHTTPServer(listenAddr, handler, logger)
}
// make a test lcd test request
func Request(t *testing.T, port, method, path string, payload []byte) (*http.Response, string) {
var res *http.Response
var err error
url := fmt.Sprintf("http://localhost:%v%v", port, path)
req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
require.Nil(t, err)
res, err = http.DefaultClient.Do(req)
// res, err = http.Post(url, "application/json", bytes.NewBuffer(payload))
require.Nil(t, err)
output, err := ioutil.ReadAll(res.Body)
res.Body.Close()
require.Nil(t, err)
return res, string(output)
}

View File

@ -28,6 +28,7 @@ type sendBody struct {
Password string `json:"password"`
ChainID string `json:"chain_id"`
Sequence int64 `json:"sequence"`
Gas int64 `json:"gas"`
}
var msgCdc = wire.NewCodec()
@ -86,6 +87,9 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont
return
}
// add gas to context
ctx = ctx.WithGas(m.Gas)
// sign
ctx = ctx.WithSequence(m.Sequence)
txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, msg, cdc)

View File

@ -26,6 +26,7 @@ type transferBody struct {
Password string `json:"password"`
SrcChainID string `json:"src_chain_id"`
Sequence int64 `json:"sequence"`
Gas int64 `json:"gas"`
}
// TransferRequestHandler - http request handler to transfer coins to a address
@ -77,6 +78,9 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core
packet := ibc.NewIBCPacket(info.PubKey.Address(), to, m.Amount, m.SrcChainID, destChainID)
msg := ibc.IBCTransferMsg{packet}
// add gas to context
ctx = ctx.WithGas(m.Gas)
// sign
ctx = ctx.WithSequence(m.Sequence)
txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, msg, cdc)

View File

@ -80,7 +80,7 @@ func bondingStatusHandlerFn(ctx context.CoreContext, storeName string, cdc *wire
}
}
// TODO inherit from Validator
// TODO move exist next to validator struct for maintainability
type StakeValidatorOutput struct {
Owner string `json:"owner"` // in bech32
PubKey string `json:"pub_key"` // in bech32

View File

@ -40,6 +40,7 @@ type editDelegationsBody struct {
Password string `json:"password"`
ChainID string `json:"chain_id"`
Sequence int64 `json:"sequence"`
Gas int64 `json:"gas"`
Delegate []msgDelegateInput `json:"delegate"`
Unbond []msgUnbondInput `json:"unbond"`
}
@ -121,6 +122,9 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte
i++
}
// add gas to context
ctx = ctx.WithGas(m.Gas)
// sign messages
signedTxs := make([][]byte, len(messages[:]))
for i, msg := range messages {