diff --git a/.circleci/config.yml b/.circleci/config.yml index 0b910d44b6..a5668784c1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -391,6 +391,24 @@ jobs: - store_artifacts: path: /go/src/github.com/cosmos/gaia/gaia-windows-res.yml + contract_tests: + <<: *linux_defaults + steps: + - attach_workspace: + at: /tmp/workspace + - checkout + - setup_remote_docker: + docker_layer_caching: true + - run: + name: Get Node.js and test REST implementation against swagger documentation at https://cosmos.network/rpc/ + command: | + go get github.com/snikch/goodman/cmd/goodman + make build + make build-contract-tests-hooks + make setup-contract-tests-data + export PATH=~/.local/bin:$PATH + ./contrib/get_node.sh && make contract-tests + workflows: version: 2 test-suite: @@ -469,4 +487,7 @@ workflows: - master requires: - setup_dependencies + - contract_tests: + requires: + - setup_dependencies diff --git a/.gitignore b/.gitignore index d09b381271..96722f977c 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ dependency-graph.png *.aux *.out *.synctex.gz +contract_tests/* diff --git a/Makefile b/Makefile index ce294bf82b..830765424b 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ PACKAGES_SIMTEST=$(shell go list ./... | grep '/simulation') VERSION := $(shell echo $(shell git describe --tags) | sed 's/^v//') COMMIT := $(shell git log -1 --format='%H') LEDGER_ENABLED ?= true +SDK_PACK := $(shell go list -m github.com/cosmos/cosmos-sdk | sed 's/ /\@/g') export GO111MODULE = on @@ -78,6 +79,13 @@ endif build-linux: go.sum LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build +build-contract-tests-hooks: +ifeq ($(OS),Windows_NT) + go build -mod=readonly $(BUILD_FLAGS) -o build/contract_tests.exe ./cmd/contract_tests +else + go build -mod=readonly $(BUILD_FLAGS) -o build/contract_tests ./cmd/contract_tests +endif + install: go.sum check-ledger go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaiad go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaiacli @@ -86,6 +94,7 @@ install-debug: go.sum go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaiadebug + ######################################## ### Tools & dependencies @@ -158,10 +167,34 @@ localnet-start: localnet-stop localnet-stop: docker-compose down +setup-contract-tests-data: + echo 'Prepare data for the contract tests' + rm -rf /tmp/contract_tests ; \ + mkdir /tmp/contract_tests ; \ + cp "${GOPATH}/pkg/mod/${SDK_PACK}/client/lcd/swagger-ui/swagger.yaml" /tmp/contract_tests/swagger.yaml ; \ + ./build/gaiad init --home /tmp/contract_tests/.gaiad --chain-id lcd contract-tests ; \ + tar -xzf lcd_test/testdata/state.tar.gz -C /tmp/contract_tests/ + +start-gaia: setup-contract-tests-data + ./build/gaiad --home /tmp/contract_tests/.gaiad start & + @sleep 2s + +setup-transactions: start-gaia + @bash ./lcd_test/testdata/setup.sh + +run-lcd-contract-tests: + @echo "Running Gaia LCD for contract tests" + ./build/gaiacli rest-server --laddr tcp://0.0.0.0:8080 --home /tmp/contract_tests/.gaiacli --node http://localhost:26657 --chain-id lcd --trust-node true + +contract-tests: setup-transactions + @echo "Running Gaia LCD for contract tests" + dredd && pkill gaiad + # include simulations include sims.mk .PHONY: all build-linux install install-debug \ - go-mod-cache draw-deps clean \ + go-mod-cache draw-deps clean build \ + setup-transactions setup-contract-tests-data start-gaia run-lcd-contract-tests contract-tests \ check check-all check-build check-cover check-ledger check-unit check-race diff --git a/cmd/contract_tests/main.go b/cmd/contract_tests/main.go new file mode 100644 index 0000000000..740c771f34 --- /dev/null +++ b/cmd/contract_tests/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "fmt" + "github.com/snikch/goodman/hooks" + "github.com/snikch/goodman/transaction" +) + +func main() { + // This must be compiled beforehand and given to dredd as parameter, in the meantime the server should be running + h := hooks.NewHooks() + server := hooks.NewServer(hooks.NewHooksRunner(h)) + h.BeforeAll(func(t []*transaction.Transaction) { + fmt.Println("Sleep 5 seconds before all modification") + }) + h.BeforeEach(func(t *transaction.Transaction) { + fmt.Println("before each modification") + }) + h.Before("/version > GET", func(t *transaction.Transaction) { + fmt.Println("before version TEST") + }) + h.Before("/node_version > GET", func(t *transaction.Transaction) { + fmt.Println("before node_version TEST") + }) + h.BeforeEachValidation(func(t *transaction.Transaction) { + fmt.Println("before each validation modification") + }) + h.BeforeValidation("/node_version > GET", func(t *transaction.Transaction) { + fmt.Println("before validation node_version TEST") + }) + h.After("/node_version > GET", func(t *transaction.Transaction) { + fmt.Println("after node_version TEST") + }) + h.AfterEach(func(t *transaction.Transaction) { + fmt.Println("after each modification") + }) + h.AfterAll(func(t []*transaction.Transaction) { + fmt.Println("after all modification") + }) + server.Serve() + defer server.Listener.Close() + fmt.Print(h) +} diff --git a/contrib/get_node.sh b/contrib/get_node.sh new file mode 100755 index 0000000000..7f0dd6e38d --- /dev/null +++ b/contrib/get_node.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +VERSION=v11.15.0 +NODE_FULL=node-${VERSION}-linux-x64 + +mkdir -p ~/.local/bin +mkdir -p ~/.local/node +wget http://nodejs.org/dist/${VERSION}/${NODE_FULL}.tar.gz -O ~/.local/node/${NODE_FULL}.tar.gz +tar -xzf ~/.local/node/${NODE_FULL}.tar.gz -C ~/.local/node/ +ln -s ~/.local/node/${NODE_FULL}/bin/node ~/.local/bin/node +ln -s ~/.local/node/${NODE_FULL}/bin/npm ~/.local/bin/npm +export PATH=~/.local/bin:$PATH +npm i -g dredd@11.0.1 +ln -s ~/.local/node/${NODE_FULL}/bin/dredd ~/.local/bin/dredd diff --git a/dredd.yml b/dredd.yml new file mode 100644 index 0000000000..3c7e68e2ca --- /dev/null +++ b/dredd.yml @@ -0,0 +1,33 @@ +color: true +dry-run: null +hookfiles: build/contract_tests +language: go +require: null +server: make run-lcd-contract-tests +server-wait: 5 +init: false +custom: {} +names: false +only: [] +reporter: [] +output: [] +header: [] +sorted: false +user: null +inline-errors: false +details: false +method: [GET] +loglevel: warning +path: [] +hooks-worker-timeout: 5000 +hooks-worker-connect-timeout: 1500 +hooks-worker-connect-retry: 500 +hooks-worker-after-connect-wait: 100 +hooks-worker-term-timeout: 5000 +hooks-worker-term-retry: 500 +hooks-worker-handler-host: 127.0.0.1 +hooks-worker-handler-port: 61321 +config: ./dredd.yml +# This path accepts no variables +blueprint: /tmp/contract_tests/swagger.yaml +endpoint: 'http://127.0.0.1:8080' diff --git a/go.mod b/go.mod index eb2dbbcf91..7bf3b98df3 100644 --- a/go.mod +++ b/go.mod @@ -15,10 +15,12 @@ require ( github.com/otiai10/copy v1.0.1 github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776 // indirect github.com/pelletier/go-toml v1.4.0 // indirect + github.com/pkg/errors v0.8.1 github.com/prometheus/common v0.4.1 // indirect github.com/prometheus/procfs v0.0.0-20190523193104-a7aeb8df3389 // indirect - github.com/rakyll/statik v0.1.6 // indirect + github.com/rakyll/statik v0.1.6 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect + github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa github.com/spf13/afero v1.2.2 // indirect github.com/spf13/cobra v0.0.4 github.com/spf13/viper v1.4.0 diff --git a/go.sum b/go.sum index dc27c36d81..7233933289 100644 --- a/go.sum +++ b/go.sum @@ -182,6 +182,8 @@ github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa h1:YJfZp12Z3AFhSBeXOlv4BO55RMwPn2NoQeDsrdWnBtY= +github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= diff --git a/lcd_test/helpers.go b/lcd_test/helpers.go new file mode 100644 index 0000000000..0487051a43 --- /dev/null +++ b/lcd_test/helpers.go @@ -0,0 +1,478 @@ +package lcdtest + +import ( + "bytes" + "fmt" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/lcd" + "github.com/cosmos/cosmos-sdk/codec" + crkeys "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/server" + "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/auth/genaccounts" + "github.com/cosmos/cosmos-sdk/x/crisis" + distr "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/cosmos/cosmos-sdk/x/genutil" + "github.com/cosmos/cosmos-sdk/x/mint" + "github.com/cosmos/cosmos-sdk/x/staking" + gapp "github.com/cosmos/gaia/app" + "github.com/pkg/errors" + "github.com/spf13/viper" + "github.com/tendermint/go-amino" + tmcfg "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/libs/cli" + ctypes "github.com/tendermint/tendermint/rpc/core/types" + "io/ioutil" + "net" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/secp256k1" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" + nm "github.com/tendermint/tendermint/node" + "github.com/tendermint/tendermint/p2p" + 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" +) + +// TODO: Make InitializeTestLCD safe to call in multiple tests at the same time +// InitializeLCD starts Tendermint and the LCD in process, listening on +// their respective sockets where nValidators is the total number of validators +// and initAddrs are the accounts to initialize with some stake tokens. It +// returns a cleanup function, a set of validator public keys, and a port. +func InitializeLCD(nValidators int, initAddrs []sdk.AccAddress, minting bool, portExt ...string) ( + cleanup func(), valConsPubKeys []crypto.PubKey, valOperAddrs []sdk.ValAddress, port string, err error) { + + config, err := GetConfig() + if err != nil { + return + } + config.Consensus.TimeoutCommit = 100 + config.Consensus.SkipTimeoutCommit = false + config.TxIndex.IndexAllTags = true + + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + logger = log.NewFilter(logger, log.AllowError()) + + db := dbm.NewMemDB() + app := gapp.NewGaiaApp(logger, db, nil, true, 0) + cdc = gapp.MakeCodec() + + genDoc, valConsPubKeys, valOperAddrs, privVal, err := defaultGenesis(config, nValidators, initAddrs, minting) + if err != nil { + return + } + + var listenAddr string + + if len(portExt) == 0 { + listenAddr, port, err = server.FreeTCPAddr() + if err != nil { + return + } + } else { + listenAddr = fmt.Sprintf("tcp://0.0.0.0:%s", portExt[0]) + port = portExt[0] + } + + // 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) + // TODO Set to false once the upstream Tendermint proof verification issue is fixed. + viper.Set(client.FlagTrustNode, true) + + node, err := startTM(config, logger, genDoc, privVal, app) + if err != nil { + return + } + + tests.WaitForNextHeightTM(tests.ExtractPortFromAddress(config.RPC.ListenAddress)) + lcdInstance, err := startLCD(logger, listenAddr, cdc) + if err != nil { + return + } + + tests.WaitForLCDStart(port) + tests.WaitForHeight(1, port) + + cleanup = func() { + logger.Debug("cleaning up LCD initialization") + err = node.Stop() + if err != nil { + logger.Error(err.Error()) + } + + node.Wait() + err = lcdInstance.Close() + if err != nil { + logger.Error(err.Error()) + } + } + + return cleanup, valConsPubKeys, valOperAddrs, port, err +} + +func defaultGenesis(config *tmcfg.Config, nValidators int, initAddrs []sdk.AccAddress, minting bool) ( + genDoc *tmtypes.GenesisDoc, valConsPubKeys []crypto.PubKey, valOperAddrs []sdk.ValAddress, privVal *pvm.FilePV, err error) { + privVal = pvm.LoadOrGenFilePV(config.PrivValidatorKeyFile(), + config.PrivValidatorStateFile()) + privVal.Reset() + + if nValidators < 1 { + err = errors.New("InitializeLCD must use at least one validator") + return + } + + genesisFile := config.GenesisFile() + genDoc, err = tmtypes.GenesisDocFromFile(genesisFile) + if err != nil { + return + } + genDoc.Validators = nil + err = genDoc.SaveAs(genesisFile) + if err != nil { + return + } + + // append any additional (non-proposing) validators + var genTxs []auth.StdTx + var accs []genaccounts.GenesisAccount + + for i := 0; i < nValidators; i++ { + operPrivKey := secp256k1.GenPrivKey() + operAddr := operPrivKey.PubKey().Address() + pubKey := privVal.GetPubKey() + + power := int64(100) + if i > 0 { + pubKey = ed25519.GenPrivKey().PubKey() + power = 1 + } + startTokens := sdk.TokensFromTendermintPower(power) + + msg := staking.NewMsgCreateValidator( + sdk.ValAddress(operAddr), + pubKey, + sdk.NewCoin(sdk.DefaultBondDenom, startTokens), + staking.NewDescription(fmt.Sprintf("validator-%d", i+1), "", "", ""), + staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), + sdk.OneInt(), + ) + stdSignMsg := auth.StdSignMsg{ + ChainID: genDoc.ChainID, + Msgs: []sdk.Msg{msg}, + } + var sig []byte + sig, err = operPrivKey.Sign(stdSignMsg.Bytes()) + if err != nil { + return + } + transaction := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{{Signature: sig, PubKey: operPrivKey.PubKey()}}, "") + genTxs = append(genTxs, transaction) + valConsPubKeys = append(valConsPubKeys, pubKey) + valOperAddrs = append(valOperAddrs, sdk.ValAddress(operAddr)) + + accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(operAddr)) + accTokens := sdk.TokensFromTendermintPower(150) + accAuth.Coins = sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, accTokens)} + accs = append(accs, genaccounts.NewGenesisAccount(&accAuth)) + } + + genesisState := gapp.NewDefaultGenesisState() + genDoc.AppState, err = cdc.MarshalJSON(genesisState) + if err != nil { + return + } + + genesisState, err = genutil.SetGenTxsInAppGenesisState(cdc, genesisState, genTxs) + if err != nil { + return + } + + // add some tokens to init accounts + stakingDataBz := genesisState[staking.ModuleName] + var stakingData staking.GenesisState + cdc.MustUnmarshalJSON(stakingDataBz, &stakingData) + + // add some tokens to init accounts + for _, addr := range initAddrs { + accAuth := auth.NewBaseAccountWithAddress(addr) + accTokens := sdk.TokensFromTendermintPower(100) + accAuth.Coins = sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, accTokens)} + acc := genaccounts.NewGenesisAccount(&accAuth) + accs = append(accs, acc) + } + + // distr data + distrDataBz := genesisState[distr.ModuleName] + var distrData distr.GenesisState + cdc.MustUnmarshalJSON(distrDataBz, &distrData) + distrData.FeePool.CommunityPool = sdk.DecCoins{sdk.DecCoin{Denom: "test", Amount: sdk.NewDecFromInt(sdk.NewInt(10))}} + distrDataBz = cdc.MustMarshalJSON(distrData) + genesisState[distr.ModuleName] = distrDataBz + + // now add the account tokens to the non-bonded pool + for _, acc := range accs { + accTokens := acc.Coins.AmountOf(sdk.DefaultBondDenom) + stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens.Add(accTokens) + } + genesisState[staking.ModuleName] = cdc.MustMarshalJSON(stakingData) + genesisState[genaccounts.ModuleName] = cdc.MustMarshalJSON(accs) + + // mint genesis (none set within genesisState) + mintData := mint.DefaultGenesisState() + inflationMin := sdk.ZeroDec() + if minting { + inflationMin = sdk.MustNewDecFromStr("10000.0") + mintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0") + } else { + mintData.Params.InflationMax = inflationMin + } + mintData.Minter.Inflation = inflationMin + mintData.Params.InflationMin = inflationMin + mintDataBz := cdc.MustMarshalJSON(mintData) + genesisState[mint.ModuleName] = mintDataBz + + // initialize crisis data + crisisDataBz := genesisState[crisis.ModuleName] + var crisisData crisis.GenesisState + cdc.MustUnmarshalJSON(crisisDataBz, &crisisData) + crisisData.ConstantFee = sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000) + crisisDataBz = cdc.MustMarshalJSON(crisisData) + genesisState[crisis.ModuleName] = crisisDataBz + + //// double check inflation is set according to the minting boolean flag + if minting { + if !(mintData.Params.InflationMax.Equal(sdk.MustNewDecFromStr("15000.0")) && + mintData.Minter.Inflation.Equal(sdk.MustNewDecFromStr("10000.0")) && + mintData.Params.InflationMin.Equal(sdk.MustNewDecFromStr("10000.0"))) { + err = errors.New("Mint parameters does not correspond to their defaults") + return + } + } else { + if !(mintData.Params.InflationMax.Equal(sdk.ZeroDec()) && + mintData.Minter.Inflation.Equal(sdk.ZeroDec()) && + mintData.Params.InflationMin.Equal(sdk.ZeroDec())) { + err = errors.New("Mint parameters not equal to decimal 0") + return + } + } + + appState, err := codec.MarshalJSONIndent(cdc, genesisState) + if err != nil { + return + } + genDoc.AppState = appState + return +} + +// startTM creates and starts an in-process Tendermint node with memDB and +// in-process ABCI application. It returns the new node or any error that +// occurred. +// +// TODO: 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 *gapp.GaiaApp, +) (*nm.Node, error) { + + genDocProvider := func() (*tmtypes.GenesisDoc, error) { return genDoc, nil } + dbProvider := func(*nm.DBContext) (dbm.DB, error) { return dbm.NewMemDB(), nil } + nodeKey, err := p2p.LoadOrGenNodeKey(tmcfg.NodeKeyFile()) + if err != nil { + return nil, err + } + node, err := nm.NewNode( + tmcfg, + privVal, + nodeKey, + proxy.NewLocalClientCreator(app), + genDocProvider, + dbProvider, + nm.DefaultMetricsProvider(tmcfg.Instrumentation), + logger.With("module", "node"), + ) + if err != nil { + return nil, err + } + + err = node.Start() + if err != nil { + return nil, err + } + + tests.WaitForRPC(tmcfg.RPC.ListenAddress) + logger.Info("Tendermint running!") + + return node, err +} + +// startLCD starts the LCD. +func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec) (net.Listener, error) { + rs := lcd.NewRestServer(cdc) + registerRoutes(rs) + listener, err := tmrpc.Listen(listenAddr, tmrpc.DefaultConfig()) + if err != nil { + return nil, err + } + go tmrpc.StartHTTPServer(listener, rs.Mux, logger, tmrpc.DefaultConfig()) //nolint:errcheck + return listener, nil +} + +// NOTE: If making updates here also update cmd/gaia/cmd/gaiacli/main.go +func registerRoutes(rs *lcd.RestServer) { + client.RegisterRoutes(rs.CliCtx, rs.Mux) + gapp.ModuleBasics.RegisterRESTRoutes(rs.CliCtx, rs.Mux) +} + +var cdc = amino.NewCodec() + +func init() { + ctypes.RegisterAmino(cdc) +} + +// CreateAddr adds an address to the key store and returns an address and seed. +// It also requires that the key could be created. +func CreateAddr(name, password string, kb crkeys.Keybase) (sdk.AccAddress, string, error) { + var ( + err error + info crkeys.Info + seed string + ) + info, seed, err = kb.CreateMnemonic(name, crkeys.English, password, crkeys.Secp256k1) + return sdk.AccAddress(info.GetPubKey().Address()), seed, err +} + +// CreateAddr adds multiple address to the key store and returns the addresses and associated seeds in lexographical order by address. +// It also requires that the keys could be created. +func CreateAddrs(kb crkeys.Keybase, numAddrs int) (addrs []sdk.AccAddress, seeds, names, passwords []string, errs []error) { + var ( + err error + info crkeys.Info + seed string + ) + + addrSeeds := AddrSeedSlice{} + + for i := 0; i < numAddrs; i++ { + name := fmt.Sprintf("test%d", i) + password := "1234567890" + info, seed, err = kb.CreateMnemonic(name, crkeys.English, password, crkeys.Secp256k1) + if err != nil { + errs = append(errs, err) + } + addrSeeds = append(addrSeeds, AddrSeed{Address: sdk.AccAddress(info.GetPubKey().Address()), Seed: seed, Name: name, Password: password}) + } + if len(errs) > 0 { + return + } + + sort.Sort(addrSeeds) + + for i := range addrSeeds { + addrs = append(addrs, addrSeeds[i].Address) + seeds = append(seeds, addrSeeds[i].Seed) + names = append(names, addrSeeds[i].Name) + passwords = append(passwords, addrSeeds[i].Password) + } + + return +} + +// AddrSeed combines an Address with the mnemonic of the private key to that address +type AddrSeed struct { + Address sdk.AccAddress + Seed string + Name string + Password string +} + +// AddrSeedSlice implements `Interface` in sort package. +type AddrSeedSlice []AddrSeed + +func (b AddrSeedSlice) Len() int { + return len(b) +} + +// Less sorts lexicographically by Address +func (b AddrSeedSlice) Less(i, j int) bool { + // bytes package already implements Comparable for []byte. + switch bytes.Compare(b[i].Address.Bytes(), b[j].Address.Bytes()) { + case -1: + return true + case 0, 1: + return false + default: + panic("not fail-able with `bytes.Comparable` bounded [-1, 1].") + } +} + +func (b AddrSeedSlice) Swap(i, j int) { + b[j], b[i] = b[i], b[j] +} + +// InitClientHome initialises client home dir. +func InitClientHome(dir string) string { + var err error + if dir == "" { + dir, err = ioutil.TempDir("", "lcd_test") + if err != nil { + panic(err) + } + } + // TODO: this should be set in NewRestServer + // and pass down the CLIContext to achieve + // parallelism. + viper.Set(cli.HomeFlag, dir) + return dir +} + +// makePathname creates a unique pathname for each test. +func makePathname() (string, error) { + p, err := os.Getwd() + if err != nil { + return "", err + } + + sep := string(filepath.Separator) + return strings.Replace(p, sep, "_", -1), nil +} + +// GetConfig returns a Tendermint config for the test cases. +func GetConfig() (*tmcfg.Config, error) { + pathname, err := makePathname() + if err != nil { + return nil, err + } + config := tmcfg.ResetTestRoot(pathname) + + tmAddr, _, err := server.FreeTCPAddr() + if err != nil { + return nil, err + } + + rcpAddr, _, err := server.FreeTCPAddr() + if err != nil { + return nil, err + } + + grpcAddr, _, err := server.FreeTCPAddr() + if err != nil { + return nil, err + } + + config.P2P.ListenAddress = tmAddr + config.RPC.ListenAddress = rcpAddr + config.RPC.GRPCListenAddress = grpcAddr + + return config, nil +} diff --git a/lcd_test/helpers_test.go b/lcd_test/helpers_test.go index e33195ffce..ea3f4cfb8b 100644 --- a/lcd_test/helpers_test.go +++ b/lcd_test/helpers_test.go @@ -1,442 +1,43 @@ -package lcd_test +package lcdtest import ( "bytes" "fmt" "io/ioutil" - "net" "net/http" - "os" - "path/filepath" "regexp" - "sort" "strings" "testing" "github.com/spf13/viper" "github.com/stretchr/testify/require" - gapp "github.com/cosmos/gaia/app" - "github.com/cosmos/cosmos-sdk/client" clientkeys "github.com/cosmos/cosmos-sdk/client/keys" - "github.com/cosmos/cosmos-sdk/client/lcd" "github.com/cosmos/cosmos-sdk/client/rpc" clienttx "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/client/utils" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/keys" crkeys "github.com/cosmos/cosmos-sdk/crypto/keys" - "github.com/cosmos/cosmos-sdk/server" - "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/genaccounts" bankrest "github.com/cosmos/cosmos-sdk/x/bank/client/rest" - "github.com/cosmos/cosmos-sdk/x/crisis" - distr "github.com/cosmos/cosmos-sdk/x/distribution" distrrest "github.com/cosmos/cosmos-sdk/x/distribution/client/rest" - "github.com/cosmos/cosmos-sdk/x/genutil" "github.com/cosmos/cosmos-sdk/x/gov" govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" - "github.com/cosmos/cosmos-sdk/x/mint" paramscutils "github.com/cosmos/cosmos-sdk/x/params/client/utils" "github.com/cosmos/cosmos-sdk/x/slashing" slashingrest "github.com/cosmos/cosmos-sdk/x/slashing/client/rest" "github.com/cosmos/cosmos-sdk/x/staking" stakingrest "github.com/cosmos/cosmos-sdk/x/staking/client/rest" - abci "github.com/tendermint/tendermint/abci/types" - tmcfg "github.com/tendermint/tendermint/config" - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/crypto/secp256k1" - "github.com/tendermint/tendermint/libs/cli" - dbm "github.com/tendermint/tendermint/libs/db" - "github.com/tendermint/tendermint/libs/log" - nm "github.com/tendermint/tendermint/node" "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" ) -var cdc = codec.New() - -func init() { - codec.RegisterCrypto(cdc) -} - -// makePathname creates a unique pathname for each test. It will panic if it -// cannot get the current working directory. -func makePathname() string { - p, err := os.Getwd() - if err != nil { - panic(err) - } - - sep := string(filepath.Separator) - return strings.Replace(p, sep, "_", -1) -} - -// GetConfig returns a Tendermint config for the test cases. -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) - } - - grpcAddr, _, err := server.FreeTCPAddr() - if err != nil { - panic(err) - } - - config.P2P.ListenAddress = tmAddr - config.RPC.ListenAddress = rcpAddr - config.RPC.GRPCListenAddress = grpcAddr - - return config -} - -// CreateAddr adds an address to the key store and returns an address and seed. -// It also requires that the key could be created. -func CreateAddr(t *testing.T, name, password string, kb crkeys.Keybase) (sdk.AccAddress, string) { - var ( - err error - info crkeys.Info - seed string - ) - - info, seed, err = kb.CreateMnemonic(name, crkeys.English, password, crkeys.Secp256k1) - require.NoError(t, err) - - return sdk.AccAddress(info.GetPubKey().Address()), seed -} - -// CreateAddr adds multiple address to the key store and returns the addresses and associated seeds in lexographical order by address. -// It also requires that the keys could be created. -func CreateAddrs(t *testing.T, kb crkeys.Keybase, numAddrs int) (addrs []sdk.AccAddress, seeds, names, passwords []string) { - var ( - err error - info crkeys.Info - seed string - ) - - addrSeeds := AddrSeedSlice{} - - for i := 0; i < numAddrs; i++ { - name := fmt.Sprintf("test%d", i) - password := "1234567890" - info, seed, err = kb.CreateMnemonic(name, crkeys.English, password, crkeys.Secp256k1) - require.NoError(t, err) - addrSeeds = append(addrSeeds, AddrSeed{Address: sdk.AccAddress(info.GetPubKey().Address()), Seed: seed, Name: name, Password: password}) - } - - sort.Sort(addrSeeds) - - for i := range addrSeeds { - addrs = append(addrs, addrSeeds[i].Address) - seeds = append(seeds, addrSeeds[i].Seed) - names = append(names, addrSeeds[i].Name) - passwords = append(passwords, addrSeeds[i].Password) - } - - return addrs, seeds, names, passwords -} - -// AddrSeed combines an Address with the mnemonic of the private key to that address -type AddrSeed struct { - Address sdk.AccAddress - Seed string - Name string - Password string -} - -// AddrSeedSlice implements `Interface` in sort package. -type AddrSeedSlice []AddrSeed - -func (b AddrSeedSlice) Len() int { - return len(b) -} - -// Less sorts lexicographically by Address -func (b AddrSeedSlice) Less(i, j int) bool { - // bytes package already implements Comparable for []byte. - switch bytes.Compare(b[i].Address.Bytes(), b[j].Address.Bytes()) { - case -1: - return true - case 0, 1: - return false - default: - panic("not fail-able with `bytes.Comparable` bounded [-1, 1].") - } -} - -func (b AddrSeedSlice) Swap(i, j int) { - b[j], b[i] = b[i], b[j] -} - -// InitClientHome initialises client home dir. -func InitClientHome(t *testing.T, dir string) string { - var err error - if dir == "" { - dir, err = ioutil.TempDir("", "lcd_test") - require.NoError(t, err) - } - // TODO: this should be set in NewRestServer - // and pass down the CLIContext to achieve - // parallelism. - viper.Set(cli.HomeFlag, dir) - return dir -} - -// TODO: Make InitializeTestLCD safe to call in multiple tests at the same time -// InitializeTestLCD starts Tendermint and the LCD in process, listening on -// their respective sockets where nValidators is the total number of validators -// and initAddrs are the accounts to initialize with some stake tokens. It -// returns a cleanup function, a set of validator public keys, and a port. -func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress, minting bool) ( - cleanup func(), valConsPubKeys []crypto.PubKey, valOperAddrs []sdk.ValAddress, port string) { - - if nValidators < 1 { - panic("InitializeTestLCD must use at least one validator") - } - - config := GetConfig() - config.Consensus.TimeoutCommit = 100 - config.Consensus.SkipTimeoutCommit = false - config.TxIndex.IndexAllTags = true - - logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - logger = log.NewFilter(logger, log.AllowError()) - - privVal := pvm.LoadOrGenFilePV(config.PrivValidatorKeyFile(), - config.PrivValidatorStateFile()) - privVal.Reset() - - db := dbm.NewMemDB() - app := gapp.NewGaiaApp(logger, db, nil, true, 0) - cdc = gapp.MakeCodec() - - genesisFile := config.GenesisFile() - genDoc, err := tmtypes.GenesisDocFromFile(genesisFile) - require.Nil(t, err) - genDoc.Validators = nil - require.NoError(t, genDoc.SaveAs(genesisFile)) - - // append any additional (non-proposing) validators - var genTxs []auth.StdTx - var accs []genaccounts.GenesisAccount - for i := 0; i < nValidators; i++ { - operPrivKey := secp256k1.GenPrivKey() - operAddr := operPrivKey.PubKey().Address() - pubKey := privVal.GetPubKey() - - power := int64(100) - if i > 0 { - pubKey = ed25519.GenPrivKey().PubKey() - power = 1 - } - startTokens := sdk.TokensFromTendermintPower(power) - - msg := staking.NewMsgCreateValidator( - sdk.ValAddress(operAddr), - pubKey, - sdk.NewCoin(sdk.DefaultBondDenom, startTokens), - staking.NewDescription(fmt.Sprintf("validator-%d", i+1), "", "", ""), - staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), - sdk.OneInt(), - ) - stdSignMsg := auth.StdSignMsg{ - ChainID: genDoc.ChainID, - Msgs: []sdk.Msg{msg}, - } - sig, err := operPrivKey.Sign(stdSignMsg.Bytes()) - require.Nil(t, err) - - tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{{Signature: sig, PubKey: operPrivKey.PubKey()}}, "") - genTxs = append(genTxs, tx) - - valConsPubKeys = append(valConsPubKeys, pubKey) - valOperAddrs = append(valOperAddrs, sdk.ValAddress(operAddr)) - - accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(operAddr)) - accTokens := sdk.TokensFromTendermintPower(150) - accAuth.Coins = sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, accTokens)} - accs = append(accs, genaccounts.NewGenesisAccount(&accAuth)) - } - - genesisState := gapp.NewDefaultGenesisState() - genDoc.AppState, err = cdc.MarshalJSON(genesisState) - require.NoError(t, err) - genesisState, err = genutil.SetGenTxsInAppGenesisState(cdc, genesisState, genTxs) - require.NoError(t, err) - - // add some tokens to init accounts - stakingDataBz := genesisState[staking.ModuleName] - var stakingData staking.GenesisState - cdc.MustUnmarshalJSON(stakingDataBz, &stakingData) - for _, addr := range initAddrs { - accAuth := auth.NewBaseAccountWithAddress(addr) - accTokens := sdk.TokensFromTendermintPower(100) - accAuth.Coins = sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, accTokens)} - acc := genaccounts.NewGenesisAccount(&accAuth) - accs = append(accs, acc) - } - - // distr data - distrDataBz := genesisState[distr.ModuleName] - var distrData distr.GenesisState - cdc.MustUnmarshalJSON(distrDataBz, &distrData) - distrData.FeePool.CommunityPool = sdk.DecCoins{sdk.DecCoin{"test", sdk.NewDecFromInt(sdk.NewInt(10))}} - distrDataBz = cdc.MustMarshalJSON(distrData) - genesisState[distr.ModuleName] = distrDataBz - - // now add the account tokens to the non-bonded pool - for _, acc := range accs { - accTokens := acc.Coins.AmountOf(sdk.DefaultBondDenom) - stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens.Add(accTokens) - } - stakingDataBz = cdc.MustMarshalJSON(stakingData) - genesisState[staking.ModuleName] = stakingDataBz - - genaccountsData := genaccounts.GenesisState(accs) - genaccountsDataBz := cdc.MustMarshalJSON(genaccountsData) - genesisState[genaccounts.ModuleName] = genaccountsDataBz - - // mint genesis (none set within genesisState) - mintData := mint.DefaultGenesisState() - inflationMin := sdk.ZeroDec() - if minting { - inflationMin = sdk.MustNewDecFromStr("10000.0") - mintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0") - } else { - mintData.Params.InflationMax = inflationMin - } - mintData.Minter.Inflation = inflationMin - mintData.Params.InflationMin = inflationMin - mintDataBz := cdc.MustMarshalJSON(mintData) - genesisState[mint.ModuleName] = mintDataBz - - // initialize crisis data - crisisDataBz := genesisState[crisis.ModuleName] - var crisisData crisis.GenesisState - cdc.MustUnmarshalJSON(crisisDataBz, &crisisData) - crisisData.ConstantFee = sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000) - crisisDataBz = cdc.MustMarshalJSON(crisisData) - genesisState[crisis.ModuleName] = crisisDataBz - - // double check inflation is set according to the minting boolean flag - if minting { - require.Equal(t, sdk.MustNewDecFromStr("15000.0"), mintData.Params.InflationMax) - require.Equal(t, sdk.MustNewDecFromStr("10000.0"), mintData.Minter.Inflation) - require.Equal(t, sdk.MustNewDecFromStr("10000.0"), mintData.Params.InflationMin) - } else { - require.Equal(t, sdk.ZeroDec(), mintData.Params.InflationMax) - require.Equal(t, sdk.ZeroDec(), mintData.Minter.Inflation) - require.Equal(t, sdk.ZeroDec(), mintData.Params.InflationMin) - } - - appState, err := codec.MarshalJSONIndent(cdc, genesisState) - require.NoError(t, err) - genDoc.AppState = appState - - listenAddr, port, err := server.FreeTCPAddr() - require.NoError(t, err) - - // NOTE: Need to set this so LCD knows the tendermint node address! - viper.Set(client.FlagNode, config.RPC.ListenAddress) - viper.Set(client.FlagChainID, genDoc.ChainID) - // TODO Set to false once the upstream Tendermint proof verification issue is fixed. - viper.Set(client.FlagTrustNode, true) - - node := startTM(t, config, logger, genDoc, privVal, app) - require.NoError(t, err) - - tests.WaitForNextHeightTM(tests.ExtractPortFromAddress(config.RPC.ListenAddress)) - lcd, err := startLCD(logger, listenAddr, cdc, t) - require.NoError(t, err) - - tests.WaitForLCDStart(port) - tests.WaitForHeight(1, port) - - cleanup = func() { - logger.Debug("cleaning up LCD initialization") - node.Stop() //nolint:errcheck - node.Wait() - lcd.Close() - os.RemoveAll(config.RootDir) - } - - return cleanup, valConsPubKeys, valOperAddrs, port -} - -// startTM creates and starts an in-process Tendermint node with memDB and -// in-process ABCI application. It returns the new node or any error that -// occurred. -// -// TODO: Clean up the WAL dir or enable it to be not persistent! -func startTM( - t *testing.T, tmcfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, - privVal tmtypes.PrivValidator, app abci.Application, -) *nm.Node { - - genDocProvider := func() (*tmtypes.GenesisDoc, error) { return genDoc, nil } - dbProvider := func(*nm.DBContext) (dbm.DB, error) { return dbm.NewMemDB(), nil } - nodeKey, err := p2p.LoadOrGenNodeKey(tmcfg.NodeKeyFile()) - require.NoError(t, err) - - node, err := nm.NewNode( - tmcfg, - privVal, - nodeKey, - proxy.NewLocalClientCreator(app), - genDocProvider, - dbProvider, - nm.DefaultMetricsProvider(tmcfg.Instrumentation), - logger.With("module", "node"), - ) - require.NoError(t, err) - - err = node.Start() - require.NoError(t, err) - - tests.WaitForRPC(tmcfg.RPC.ListenAddress) - logger.Info("Tendermint running!") - - return node -} - -// startLCD starts the LCD. -func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec, t *testing.T) (net.Listener, error) { - rs := lcd.NewRestServer(cdc) - registerRoutes(rs) - listener, err := tmrpc.Listen(listenAddr, tmrpc.DefaultConfig()) - if err != nil { - return nil, err - } - go tmrpc.StartHTTPServer(listener, rs.Mux, logger, tmrpc.DefaultConfig()) //nolint:errcheck - return listener, nil -} - -// NOTE: If making updates here also update cmd/gaia/cmd/gaiacli/main.go -func registerRoutes(rs *lcd.RestServer) { - client.RegisterRoutes(rs.CliCtx, rs.Mux) - gapp.ModuleBasics.RegisterRESTRoutes(rs.CliCtx, rs.Mux) -} - // Request makes a test LCD test request. It returns a response object and a // stringified response body. func Request(t *testing.T, port, method, path string, payload []byte) (*http.Response, string) { diff --git a/lcd_test/lcd_test.go b/lcd_test/lcd_test.go index af5105b633..252fa48950 100644 --- a/lcd_test/lcd_test.go +++ b/lcd_test/lcd_test.go @@ -1,4 +1,4 @@ -package lcd_test +package lcdtest import ( "encoding/base64" @@ -52,7 +52,8 @@ func TestVersion(t *testing.T) { t.SkipNow() } - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}, true) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{}, true) + require.NoError(t, err) defer cleanup() // node info @@ -75,14 +76,16 @@ func TestVersion(t *testing.T) { } func TestNodeStatus(t *testing.T) { - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}, true) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{}, true) + require.NoError(t, err) defer cleanup() getNodeInfo(t, port) getSyncStatus(t, port, false) } func TestBlock(t *testing.T) { - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}, true) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{}, true) + require.NoError(t, err) defer cleanup() getBlock(t, port, -1, false) getBlock(t, port, 2, false) @@ -90,7 +93,8 @@ func TestBlock(t *testing.T) { } func TestValidators(t *testing.T) { - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}, true) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{}, true) + require.NoError(t, err) defer cleanup() resultVals := getValidatorSets(t, port, -1, false) require.Contains(t, resultVals.Validators[0].Address.String(), "cosmosvalcons") @@ -100,10 +104,12 @@ func TestValidators(t *testing.T) { } func TestCoinSend(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, seed, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, seed := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() bz, err := hex.DecodeString("8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6") @@ -191,10 +197,12 @@ func TestCoinSend(t *testing.T) { } func TestCoinSendAccAuto(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, seed, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, seed := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() acc := getAccount(t, port, addr) @@ -216,10 +224,12 @@ func TestCoinSendAccAuto(t *testing.T) { } func TestCoinMultiSendGenerateOnly(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, seed, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, seed := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() // generate only @@ -239,11 +249,12 @@ func TestCoinMultiSendGenerateOnly(t *testing.T) { } func TestCoinSendGenerateSignAndBroadcast(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, seed, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, seed := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) - defer cleanup() acc := getAccount(t, port, addr) @@ -282,10 +293,12 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) { } func TestEncodeTx(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, seed, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, seed := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() res, body, _ := doTransferWithGas(t, port, seed, name1, memo, "", addr, "2", 1, false, false, fees) @@ -315,10 +328,12 @@ func TestEncodeTx(t *testing.T) { } func TestTxs(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, seed, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, seed := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() var emptyTxs []sdk.TxResponse @@ -367,10 +382,12 @@ func TestTxs(t *testing.T) { } func TestPoolParamsQuery(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, _, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, _ := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() defaultParams := staking.DefaultParams() @@ -395,7 +412,8 @@ func TestPoolParamsQuery(t *testing.T) { } func TestValidatorsQuery(t *testing.T) { - cleanup, valPubKeys, operAddrs, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}, true) + cleanup, valPubKeys, operAddrs, port, err := InitializeLCD(1, []sdk.AccAddress{}, true) + require.NoError(t, err) defer cleanup() require.Equal(t, 1, len(valPubKeys)) @@ -415,7 +433,8 @@ func TestValidatorsQuery(t *testing.T) { } func TestValidatorQuery(t *testing.T) { - cleanup, valPubKeys, operAddrs, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}, true) + cleanup, valPubKeys, operAddrs, port, err := InitializeLCD(1, []sdk.AccAddress{}, true) + require.NoError(t, err) defer cleanup() require.Equal(t, 1, len(valPubKeys)) require.Equal(t, 1, len(operAddrs)) @@ -425,11 +444,13 @@ func TestValidatorQuery(t *testing.T) { } func TestBonding(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, _, err := CreateAddr(name1, pw, kb) require.NoError(t, err) - addr, _ := CreateAddr(t, name1, pw, kb) - cleanup, valPubKeys, operAddrs, port := InitializeTestLCD(t, 2, []sdk.AccAddress{addr}, false) + cleanup, valPubKeys, operAddrs, port, err := InitializeLCD(2, []sdk.AccAddress{addr}, false) + require.NoError(t, err) tests.WaitForHeight(1, port) defer cleanup() @@ -589,10 +610,12 @@ func TestBonding(t *testing.T) { } func TestSubmitProposal(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, seed, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, seed := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() acc := getAccount(t, port, addr) @@ -626,10 +649,12 @@ func TestSubmitProposal(t *testing.T) { } func TestSubmitCommunityPoolSpendProposal(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, seed, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, seed := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() acc := getAccount(t, port, addr) @@ -663,10 +688,12 @@ func TestSubmitCommunityPoolSpendProposal(t *testing.T) { } func TestSubmitParamChangeProposal(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, seed, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, seed := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() acc := getAccount(t, port, addr) @@ -700,10 +727,12 @@ func TestSubmitParamChangeProposal(t *testing.T) { } func TestDeposit(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, seed, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, seed := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() acc := getAccount(t, port, addr) @@ -759,10 +788,12 @@ func TestDeposit(t *testing.T) { } func TestVote(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, seed, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, operAddrs, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, seed := CreateAddr(t, name1, pw, kb) - cleanup, _, operAddrs, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() acc := getAccount(t, port, addr) @@ -846,10 +877,12 @@ func TestVote(t *testing.T) { } func TestUnjail(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, _, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, valPubKeys, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, _ := CreateAddr(t, name1, pw, kb) - cleanup, valPubKeys, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() // NOTE: any less than this and it fails @@ -865,11 +898,13 @@ func TestUnjail(t *testing.T) { } func TestProposalsQuery(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) require.NoError(t, err) - addrs, seeds, names, passwords := CreateAddrs(t, kb, 2) + addrs, seeds, names, passwords, errors := CreateAddrs(kb, 2) + require.Empty(t, errors) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addrs[0], addrs[1]}, true) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addrs[0], addrs[1]}, true) + require.NoError(t, err) defer cleanup() depositParam := getDepositParam(t, port) @@ -995,19 +1030,21 @@ func TestProposalsQuery(t *testing.T) { } func TestSlashingGetParams(t *testing.T) { - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}, true) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{}, true) + require.NoError(t, err) defer cleanup() res, body := Request(t, port, "GET", "/slashing/parameters", nil) require.Equal(t, http.StatusOK, res.StatusCode, body) var params slashing.Params - err := cdc.UnmarshalJSON([]byte(body), ¶ms) + err = cdc.UnmarshalJSON([]byte(body), ¶ms) require.NoError(t, err) } func TestDistributionGetParams(t *testing.T) { - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}, true) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{}, true) + require.NoError(t, err) defer cleanup() res, body := Request(t, port, "GET", "/distribution/parameters", nil) @@ -1016,10 +1053,12 @@ func TestDistributionGetParams(t *testing.T) { } func TestDistributionFlow(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, seed, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, valAddrs, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, seed := CreateAddr(t, name1, pw, kb) - cleanup, _, valAddrs, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() valAddr := valAddrs[0] @@ -1092,10 +1131,12 @@ func TestDistributionFlow(t *testing.T) { } func TestMintingQueries(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, _, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, _ := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() res, body := Request(t, port, "GET", "/minting/parameters", nil) @@ -1118,10 +1159,12 @@ func TestMintingQueries(t *testing.T) { } func TestAccountBalanceQuery(t *testing.T) { - kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + kb, err := keys.NewKeyBaseFromDir(InitClientHome("")) + require.NoError(t, err) + addr, _, err := CreateAddr(name1, pw, kb) + require.NoError(t, err) + cleanup, _, _, port, err := InitializeLCD(1, []sdk.AccAddress{addr}, true) require.NoError(t, err) - addr, _ := CreateAddr(t, name1, pw, kb) - cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() bz, err := hex.DecodeString("8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6") diff --git a/lcd_test/testdata/setup.sh b/lcd_test/testdata/setup.sh new file mode 100755 index 0000000000..05ee799976 --- /dev/null +++ b/lcd_test/testdata/setup.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +PASSWORD="1234567890" +ADDR="cosmos16xyempempp92x9hyzz9wrgf94r6j9h5f06pxxv" +RECEIVER="cosmos17gx5vwpm0y2k59tw0x00ccug234n56cgltx2w2" +VALIDATOR="cosmosvaloper16xyempempp92x9hyzz9wrgf94r6j9h5f2w4n2l" +AMOUNT="1000000stake" +CHAIN="lcd" +PROPOSALID="2" +HOME="/tmp/contract_tests/.gaiacli" +SWAGGER='/tmp/contract_tests/swagger.yaml' + +# sleeping a whole second between each step is a conservative precaution +# check lcd_test/testdata/state.tar.gz -> .gaiad/config/config.toml precommit_timeout = 500ms +sleep 1s +echo ${PASSWORD} | ./build/gaiacli tx gov submit-proposal --home ${HOME} --from ${ADDR} --chain-id ${CHAIN} --type text --title test --description test_description --deposit 10000stake --yes +sleep 1s +echo ${PASSWORD} | ./build/gaiacli tx gov deposit --home ${HOME} --from ${ADDR} --chain-id ${CHAIN} ${PROPOSALID} 1000000000stake --yes +sleep 1s +echo ${PASSWORD} | ./build/gaiacli tx gov vote --home ${HOME} --from ${ADDR} --yes --chain-id ${CHAIN} ${PROPOSALID} Yes +sleep 1s +HASH=$(echo ${PASSWORD} | ./build/gaiacli tx send --home ${HOME} ${ADDR} ${RECEIVER} ${AMOUNT} --yes --chain-id ${CHAIN} | awk '/txhash.*/{print $2}') +sed -i.bak -e "s/BCBE20E8D46758B96AE5883B792858296AC06E51435490FBDCAE25A72B3CC76B/${HASH}/g" "${SWAGGER}" +echo "Replaced dummy with actual transaction hash ${HASH}" +sleep 1s +echo ${PASSWORD} | ./build/gaiacli tx staking unbond --home ${HOME} --from ${ADDR} ${VALIDATOR} 100stake --yes --chain-id ${CHAIN} + diff --git a/lcd_test/testdata/state.tar.gz b/lcd_test/testdata/state.tar.gz new file mode 100644 index 0000000000..30f0942309 Binary files /dev/null and b/lcd_test/testdata/state.tar.gz differ