diff --git a/app/app.go b/app/app.go index 71a82b7c..46b0ccab 100644 --- a/app/app.go +++ b/app/app.go @@ -220,6 +220,12 @@ func MakeCodec() *codec.Codec { return cdc } +func SetBech32AddressPrefixes(config *sdk.Config) { + config.SetBech32PrefixForAccount(Bech32MainPrefix, Bech32MainPrefix+sdk.PrefixPublic) + config.SetBech32PrefixForValidator(Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixOperator, Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixOperator+sdk.PrefixPublic) + config.SetBech32PrefixForConsensusNode(Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixConsensus, Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixConsensus+sdk.PrefixPublic) +} + // application updates every end block func (app *App) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { // mint new tokens for the previous block diff --git a/cli_test/README.md b/cli_test/README.md new file mode 100644 index 00000000..8dacad3a --- /dev/null +++ b/cli_test/README.md @@ -0,0 +1,13 @@ +# CLI Integration tests + +Run the full suite: + +```bash +go test -v -p 4 ./cli_test -tags cli_test +``` + +`-v` for verbose, `-p 4` to use 4 cores, `-tags cli_test` a build tag (specified in `cli_test.go`) to tell go not to ignore the package + +> NOTE: While the full suite runs in parallel, some of the tests can take up to a minute to complete + +> NOTE: The tests will use the `kvd` or `kvcli` binaries in your `$GOPATH/bin`. Or in `$BUILDDIR` if that env var is set. \ No newline at end of file diff --git a/cli_test/cli_test.go b/cli_test/cli_test.go new file mode 100644 index 00000000..0b9ab572 --- /dev/null +++ b/cli_test/cli_test.go @@ -0,0 +1,1094 @@ +// +build cli_test + +package clitest + +import ( + "encoding/base64" + "errors" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/tendermint/tendermint/crypto/ed25519" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/tests" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/gov" + + "github.com/kava-labs/kava/app" +) + +func TestGaiaCLIKeysAddMultisig(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // key names order does not matter + f.KeysAdd("msig1", "--multisig-threshold=2", + fmt.Sprintf("--multisig=%s,%s", keyBar, keyBaz)) + f.KeysAdd("msig2", "--multisig-threshold=2", + fmt.Sprintf("--multisig=%s,%s", keyBaz, keyBar)) + require.Equal(t, f.KeysShow("msig1").Address, f.KeysShow("msig2").Address) + + f.KeysAdd("msig3", "--multisig-threshold=2", + fmt.Sprintf("--multisig=%s,%s", keyBar, keyBaz), + "--nosort") + f.KeysAdd("msig4", "--multisig-threshold=2", + fmt.Sprintf("--multisig=%s,%s", keyBaz, keyBar), + "--nosort") + require.NotEqual(t, f.KeysShow("msig3").Address, f.KeysShow("msig4").Address) +} + +func TestGaiaCLIKeysAddRecover(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + exitSuccess, _, _ := f.KeysAddRecover("empty-mnemonic", "") + require.False(t, exitSuccess) + + exitSuccess, _, _ = f.KeysAddRecover("test-recover", "dentist task convince chimney quality leave banana trade firm crawl eternal easily") + require.True(t, exitSuccess) + require.Equal(t, "k1qcfdf69js922qrdr4yaww3ax7gjml6pd3fmkx7", f.KeyAddress("test-recover").String()) +} + +func TestGaiaCLIKeysAddRecoverHDPath(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + f.KeysAddRecoverHDPath("test-recoverHD1", "dentist task convince chimney quality leave banana trade firm crawl eternal easily", 0, 0) + require.Equal(t, "k1qcfdf69js922qrdr4yaww3ax7gjml6pd3fmkx7", f.KeyAddress("test-recoverHD1").String()) + + f.KeysAddRecoverHDPath("test-recoverH2", "dentist task convince chimney quality leave banana trade firm crawl eternal easily", 1, 5) + require.Equal(t, "k1pdfav2cjhry9k79nu6r8kgknnjtq6a7rc043x0", f.KeyAddress("test-recoverH2").String()) + + f.KeysAddRecoverHDPath("test-recoverH3", "dentist task convince chimney quality leave banana trade firm crawl eternal easily", 1, 17) + require.Equal(t, "k1909k354n6wl8ujzu6kmh49w4d02ax7qvr0zelc", f.KeyAddress("test-recoverH3").String()) + + f.KeysAddRecoverHDPath("test-recoverH4", "dentist task convince chimney quality leave banana trade firm crawl eternal easily", 2, 17) + require.Equal(t, "k1v9plmhvyhgxk3th9ydacm7j4z357s3nhhh77jq", f.KeyAddress("test-recoverH4").String()) +} + +func TestGaiaCLIMinimumFees(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server with minimum fees + minGasPrice, _ := sdk.NewDecFromStr("0.000006") + fees := fmt.Sprintf( + "--minimum-gas-prices=%s,%s", + sdk.NewDecCoinFromDec(feeDenom, minGasPrice), + sdk.NewDecCoinFromDec(fee2Denom, minGasPrice), + ) + proc := f.GDStart(fees) + defer proc.Stop(false) + + barAddr := f.KeyAddress(keyBar) + + // Send a transaction that will get rejected + success, _, _ := f.TxSend(keyFoo, barAddr, sdk.NewInt64Coin(fee2Denom, 10), "-y") + require.False(f.T, success) + tests.WaitForNextNBlocksTM(1, f.Port) + + // Ensure tx w/ correct fees pass + txFees := fmt.Sprintf("--fees=%s", sdk.NewInt64Coin(feeDenom, 2)) + success, _, _ = f.TxSend(keyFoo, barAddr, sdk.NewInt64Coin(fee2Denom, 10), txFees, "-y") + require.True(f.T, success) + tests.WaitForNextNBlocksTM(1, f.Port) + + // Ensure tx w/ improper fees fails + txFees = fmt.Sprintf("--fees=%s", sdk.NewInt64Coin(feeDenom, 1)) + success, _, _ = f.TxSend(keyFoo, barAddr, sdk.NewInt64Coin(fooDenom, 10), txFees, "-y") + require.False(f.T, success) + + // Cleanup testing directories + f.Cleanup() +} + +func TestGaiaCLIGasPrices(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server with minimum fees + minGasPrice, _ := sdk.NewDecFromStr("0.000006") + proc := f.GDStart(fmt.Sprintf("--minimum-gas-prices=%s", sdk.NewDecCoinFromDec(feeDenom, minGasPrice))) + defer proc.Stop(false) + + barAddr := f.KeyAddress(keyBar) + + // insufficient gas prices (tx fails) + badGasPrice, _ := sdk.NewDecFromStr("0.000003") + success, _, _ := f.TxSend( + keyFoo, barAddr, sdk.NewInt64Coin(fooDenom, 50), + fmt.Sprintf("--gas-prices=%s", sdk.NewDecCoinFromDec(feeDenom, badGasPrice)), "-y") + require.False(t, success) + + // wait for a block confirmation + tests.WaitForNextNBlocksTM(1, f.Port) + + // sufficient gas prices (tx passes) + success, _, _ = f.TxSend( + keyFoo, barAddr, sdk.NewInt64Coin(fooDenom, 50), + fmt.Sprintf("--gas-prices=%s", sdk.NewDecCoinFromDec(feeDenom, minGasPrice)), "-y") + require.True(t, success) + + // wait for a block confirmation + tests.WaitForNextNBlocksTM(1, f.Port) + + f.Cleanup() +} + +func TestGaiaCLIFeesDeduction(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server with minimum fees + minGasPrice, _ := sdk.NewDecFromStr("0.000006") + proc := f.GDStart(fmt.Sprintf("--minimum-gas-prices=%s", sdk.NewDecCoinFromDec(feeDenom, minGasPrice))) + defer proc.Stop(false) + + // Save key addresses for later use + fooAddr := f.KeyAddress(keyFoo) + barAddr := f.KeyAddress(keyBar) + + fooAcc := f.QueryAccount(fooAddr) + fooAmt := fooAcc.GetCoins().AmountOf(fooDenom) + + // test simulation + success, _, _ := f.TxSend( + keyFoo, barAddr, sdk.NewInt64Coin(fooDenom, 1000), + fmt.Sprintf("--fees=%s", sdk.NewInt64Coin(feeDenom, 2)), "--dry-run") + require.True(t, success) + + // Wait for a block + tests.WaitForNextNBlocksTM(1, f.Port) + + // ensure state didn't change + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, fooAmt.Int64(), fooAcc.GetCoins().AmountOf(fooDenom).Int64()) + + // insufficient funds (coins + fees) tx fails + largeCoins := sdk.TokensFromTendermintPower(10000000) + success, _, _ = f.TxSend( + keyFoo, barAddr, sdk.NewCoin(fooDenom, largeCoins), + fmt.Sprintf("--fees=%s", sdk.NewInt64Coin(feeDenom, 2)), "-y") + require.False(t, success) + + // Wait for a block + tests.WaitForNextNBlocksTM(1, f.Port) + + // ensure state didn't change + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, fooAmt.Int64(), fooAcc.GetCoins().AmountOf(fooDenom).Int64()) + + // test success (transfer = coins + fees) + success, _, _ = f.TxSend( + keyFoo, barAddr, sdk.NewInt64Coin(fooDenom, 500), + fmt.Sprintf("--fees=%s", sdk.NewInt64Coin(feeDenom, 2)), "-y") + require.True(t, success) + + f.Cleanup() +} + +func TestGaiaCLISend(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server + proc := f.GDStart() + defer proc.Stop(false) + + // Save key addresses for later use + fooAddr := f.KeyAddress(keyFoo) + barAddr := f.KeyAddress(keyBar) + + fooAcc := f.QueryAccount(fooAddr) + startTokens := sdk.TokensFromTendermintPower(50) + require.Equal(t, startTokens, fooAcc.GetCoins().AmountOf(denom)) + + // Send some tokens from one account to the other + sendTokens := sdk.TokensFromTendermintPower(10) + f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "-y") + tests.WaitForNextNBlocksTM(1, f.Port) + + // Ensure account balances match expected + barAcc := f.QueryAccount(barAddr) + require.Equal(t, sendTokens, barAcc.GetCoins().AmountOf(denom)) + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, startTokens.Sub(sendTokens), fooAcc.GetCoins().AmountOf(denom)) + + // Test --dry-run + success, _, _ := f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--dry-run") + require.True(t, success) + + // Check state didn't change + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, startTokens.Sub(sendTokens), fooAcc.GetCoins().AmountOf(denom)) + + // test autosequencing + f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "-y") + tests.WaitForNextNBlocksTM(1, f.Port) + + // Ensure account balances match expected + barAcc = f.QueryAccount(barAddr) + require.Equal(t, sendTokens.MulRaw(2), barAcc.GetCoins().AmountOf(denom)) + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, startTokens.Sub(sendTokens.MulRaw(2)), fooAcc.GetCoins().AmountOf(denom)) + + // test memo + f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--memo='testmemo'", "-y") + tests.WaitForNextNBlocksTM(1, f.Port) + + // Ensure account balances match expected + barAcc = f.QueryAccount(barAddr) + require.Equal(t, sendTokens.MulRaw(3), barAcc.GetCoins().AmountOf(denom)) + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, startTokens.Sub(sendTokens.MulRaw(3)), fooAcc.GetCoins().AmountOf(denom)) + + f.Cleanup() +} + +func TestGaiaCLIConfirmTx(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server + proc := f.GDStart() + defer proc.Stop(false) + + // Save key addresses for later use + fooAddr := f.KeyAddress(keyFoo) + barAddr := f.KeyAddress(keyBar) + + fooAcc := f.QueryAccount(fooAddr) + startTokens := sdk.TokensFromTendermintPower(50) + require.Equal(t, startTokens, fooAcc.GetCoins().AmountOf(denom)) + + // send some tokens from one account to the other + sendTokens := sdk.TokensFromTendermintPower(10) + f.txSendWithConfirm(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "Y") + tests.WaitForNextNBlocksTM(1, f.Port) + + // ensure account balances match expected + barAcc := f.QueryAccount(barAddr) + require.Equal(t, sendTokens, barAcc.GetCoins().AmountOf(denom)) + + // send some tokens from one account to the other (cancelling confirmation) + f.txSendWithConfirm(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "n") + tests.WaitForNextNBlocksTM(1, f.Port) + + // ensure account balances match expected + barAcc = f.QueryAccount(barAddr) + require.Equal(t, sendTokens, barAcc.GetCoins().AmountOf(denom)) +} + +func TestGaiaCLIGasAuto(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server + proc := f.GDStart() + defer proc.Stop(false) + + fooAddr := f.KeyAddress(keyFoo) + barAddr := f.KeyAddress(keyBar) + + fooAcc := f.QueryAccount(fooAddr) + startTokens := sdk.TokensFromTendermintPower(50) + require.Equal(t, startTokens, fooAcc.GetCoins().AmountOf(denom)) + + // Test failure with auto gas disabled and very little gas set by hand + sendTokens := sdk.TokensFromTendermintPower(10) + success, _, _ := f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--gas=10", "-y") + require.False(t, success) + + // Check state didn't change + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, startTokens, fooAcc.GetCoins().AmountOf(denom)) + + // Test failure with negative gas + success, _, _ = f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--gas=-100", "-y") + require.False(t, success) + + // Check state didn't change + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, startTokens, fooAcc.GetCoins().AmountOf(denom)) + + // Test failure with 0 gas + success, _, _ = f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--gas=0", "-y") + require.False(t, success) + + // Check state didn't change + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, startTokens, fooAcc.GetCoins().AmountOf(denom)) + + // Enable auto gas + success, stdout, stderr := f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--gas=auto", "-y") + require.NotEmpty(t, stderr) + require.True(t, success) + cdc := app.MakeCodec() + sendResp := sdk.TxResponse{} + err := cdc.UnmarshalJSON([]byte(stdout), &sendResp) + require.Nil(t, err) + require.True(t, sendResp.GasWanted >= sendResp.GasUsed) + tests.WaitForNextNBlocksTM(1, f.Port) + + // Check state has changed accordingly + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, startTokens.Sub(sendTokens), fooAcc.GetCoins().AmountOf(denom)) + + f.Cleanup() +} + +func TestGaiaCLICreateValidator(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server + proc := f.GDStart() + defer proc.Stop(false) + + barAddr := f.KeyAddress(keyBar) + barVal := sdk.ValAddress(barAddr) + + consPubKey := sdk.MustBech32ifyConsPub(ed25519.GenPrivKey().PubKey()) + + sendTokens := sdk.TokensFromTendermintPower(10) + f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "-y") + tests.WaitForNextNBlocksTM(1, f.Port) + + barAcc := f.QueryAccount(barAddr) + require.Equal(t, sendTokens, barAcc.GetCoins().AmountOf(denom)) + + // Generate a create validator transaction and ensure correctness + success, stdout, stderr := f.TxStakingCreateValidator(barAddr.String(), consPubKey, sdk.NewInt64Coin(denom, 2), "--generate-only") + + require.True(f.T, success) + require.Empty(f.T, stderr) + msg := unmarshalStdTx(f.T, stdout) + require.NotZero(t, msg.Fee.Gas) + require.Equal(t, len(msg.Msgs), 1) + require.Equal(t, 0, len(msg.GetSignatures())) + + // Test --dry-run + newValTokens := sdk.TokensFromTendermintPower(2) + success, _, _ = f.TxStakingCreateValidator(keyBar, consPubKey, sdk.NewCoin(denom, newValTokens), "--dry-run") + require.True(t, success) + + // Create the validator + f.TxStakingCreateValidator(keyBar, consPubKey, sdk.NewCoin(denom, newValTokens), "-y") + tests.WaitForNextNBlocksTM(1, f.Port) + + // Ensure funds were deducted properly + barAcc = f.QueryAccount(barAddr) + require.Equal(t, sendTokens.Sub(newValTokens), barAcc.GetCoins().AmountOf(denom)) + + // Ensure that validator state is as expected + validator := f.QueryStakingValidator(barVal) + require.Equal(t, validator.OperatorAddress, barVal) + require.True(sdk.IntEq(t, newValTokens, validator.Tokens)) + + // Query delegations to the validator + validatorDelegations := f.QueryStakingDelegationsTo(barVal) + require.Len(t, validatorDelegations, 1) + require.NotZero(t, validatorDelegations[0].Shares) + + // unbond a single share + unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(1)) + success = f.TxStakingUnbond(keyBar, unbondAmt.String(), barVal, "-y") + require.True(t, success) + tests.WaitForNextNBlocksTM(1, f.Port) + + // Ensure bonded staking is correct + remainingTokens := newValTokens.Sub(unbondAmt.Amount) + validator = f.QueryStakingValidator(barVal) + require.Equal(t, remainingTokens, validator.Tokens) + + // Get unbonding delegations from the validator + validatorUbds := f.QueryStakingUnbondingDelegationsFrom(barVal) + require.Len(t, validatorUbds, 1) + require.Len(t, validatorUbds[0].Entries, 1) + require.Equal(t, remainingTokens.String(), validatorUbds[0].Entries[0].Balance.String()) + + f.Cleanup() +} + +func TestGaiaCLISubmitProposal(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server + proc := f.GDStart() + defer proc.Stop(false) + + f.QueryGovParamDeposit() + f.QueryGovParamVoting() + f.QueryGovParamTallying() + + fooAddr := f.KeyAddress(keyFoo) + + fooAcc := f.QueryAccount(fooAddr) + startTokens := sdk.TokensFromTendermintPower(50) + require.Equal(t, startTokens, fooAcc.GetCoins().AmountOf(sdk.DefaultBondDenom)) + + proposalsQuery := f.QueryGovProposals() + require.Empty(t, proposalsQuery) + + // Test submit generate only for submit proposal + proposalTokens := sdk.TokensFromTendermintPower(5) + success, stdout, stderr := f.TxGovSubmitProposal( + fooAddr.String(), "Text", "Test", "test", sdk.NewCoin(denom, proposalTokens), "--generate-only", "-y") + require.True(t, success) + require.Empty(t, stderr) + msg := unmarshalStdTx(t, stdout) + require.NotZero(t, msg.Fee.Gas) + require.Equal(t, len(msg.Msgs), 1) + require.Equal(t, 0, len(msg.GetSignatures())) + + // Test --dry-run + success, _, _ = f.TxGovSubmitProposal(keyFoo, "Text", "Test", "test", sdk.NewCoin(denom, proposalTokens), "--dry-run") + require.True(t, success) + + // Create the proposal + f.TxGovSubmitProposal(keyFoo, "Text", "Test", "test", sdk.NewCoin(denom, proposalTokens), "-y") + tests.WaitForNextNBlocksTM(1, f.Port) + + // Ensure transaction tags can be queried + txs := f.QueryTxs(1, 50, "action:submit_proposal", fmt.Sprintf("proposer:%s", fooAddr)) + require.Len(t, txs, 1) + + // Ensure deposit was deducted + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, startTokens.Sub(proposalTokens), fooAcc.GetCoins().AmountOf(denom)) + + // Ensure propsal is directly queryable + proposal1 := f.QueryGovProposal(1) + require.Equal(t, uint64(1), proposal1.ProposalID) + require.Equal(t, gov.StatusDepositPeriod, proposal1.Status) + + // Ensure query proposals returns properly + proposalsQuery = f.QueryGovProposals() + require.Equal(t, uint64(1), proposalsQuery[0].ProposalID) + + // Query the deposits on the proposal + deposit := f.QueryGovDeposit(1, fooAddr) + require.Equal(t, proposalTokens, deposit.Amount.AmountOf(denom)) + + // Test deposit generate only + depositTokens := sdk.TokensFromTendermintPower(10) + success, stdout, stderr = f.TxGovDeposit(1, fooAddr.String(), sdk.NewCoin(denom, depositTokens), "--generate-only") + require.True(t, success) + require.Empty(t, stderr) + msg = unmarshalStdTx(t, stdout) + require.NotZero(t, msg.Fee.Gas) + require.Equal(t, len(msg.Msgs), 1) + require.Equal(t, 0, len(msg.GetSignatures())) + + // Run the deposit transaction + f.TxGovDeposit(1, keyFoo, sdk.NewCoin(denom, depositTokens), "-y") + tests.WaitForNextNBlocksTM(1, f.Port) + + // test query deposit + deposits := f.QueryGovDeposits(1) + require.Len(t, deposits, 1) + require.Equal(t, proposalTokens.Add(depositTokens), deposits[0].Amount.AmountOf(denom)) + + // Ensure querying the deposit returns the proper amount + deposit = f.QueryGovDeposit(1, fooAddr) + require.Equal(t, proposalTokens.Add(depositTokens), deposit.Amount.AmountOf(denom)) + + // Ensure tags are set on the transaction + txs = f.QueryTxs(1, 50, "action:deposit", fmt.Sprintf("depositor:%s", fooAddr)) + require.Len(t, txs, 1) + + // Ensure account has expected amount of funds + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, startTokens.Sub(proposalTokens.Add(depositTokens)), fooAcc.GetCoins().AmountOf(denom)) + + // Fetch the proposal and ensure it is now in the voting period + proposal1 = f.QueryGovProposal(1) + require.Equal(t, uint64(1), proposal1.ProposalID) + require.Equal(t, gov.StatusVotingPeriod, proposal1.Status) + + // Test vote generate only + success, stdout, stderr = f.TxGovVote(1, gov.OptionYes, fooAddr.String(), "--generate-only") + require.True(t, success) + require.Empty(t, stderr) + msg = unmarshalStdTx(t, stdout) + require.NotZero(t, msg.Fee.Gas) + require.Equal(t, len(msg.Msgs), 1) + require.Equal(t, 0, len(msg.GetSignatures())) + + // Vote on the proposal + f.TxGovVote(1, gov.OptionYes, keyFoo, "-y") + tests.WaitForNextNBlocksTM(1, f.Port) + + // Query the vote + vote := f.QueryGovVote(1, fooAddr) + require.Equal(t, uint64(1), vote.ProposalID) + require.Equal(t, gov.OptionYes, vote.Option) + + // Query the votes + votes := f.QueryGovVotes(1) + require.Len(t, votes, 1) + require.Equal(t, uint64(1), votes[0].ProposalID) + require.Equal(t, gov.OptionYes, votes[0].Option) + + // Ensure tags are applied to voting transaction properly + txs = f.QueryTxs(1, 50, "action:vote", fmt.Sprintf("voter:%s", fooAddr)) + require.Len(t, txs, 1) + + // Ensure no proposals in deposit period + proposalsQuery = f.QueryGovProposals("--status=DepositPeriod") + require.Empty(t, proposalsQuery) + + // Ensure the proposal returns as in the voting period + proposalsQuery = f.QueryGovProposals("--status=VotingPeriod") + require.Equal(t, uint64(1), proposalsQuery[0].ProposalID) + + // submit a second test proposal + f.TxGovSubmitProposal(keyFoo, "Text", "Apples", "test", sdk.NewCoin(denom, proposalTokens), "-y") + tests.WaitForNextNBlocksTM(1, f.Port) + + // Test limit on proposals query + proposalsQuery = f.QueryGovProposals("--limit=1") + require.Equal(t, uint64(2), proposalsQuery[0].ProposalID) + + f.Cleanup() +} + +func TestGaiaCLIQueryTxPagination(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server + proc := f.GDStart() + defer proc.Stop(false) + + fooAddr := f.KeyAddress(keyFoo) + barAddr := f.KeyAddress(keyBar) + + accFoo := f.QueryAccount(fooAddr) + seq := accFoo.GetSequence() + + for i := 1; i <= 30; i++ { + success, _, _ := f.TxSend(keyFoo, barAddr, sdk.NewInt64Coin(fooDenom, int64(i)), fmt.Sprintf("--sequence=%d", seq), "-y") + require.True(t, success) + seq++ + } + + // perPage = 15, 2 pages + txsPage1 := f.QueryTxs(1, 15, fmt.Sprintf("sender:%s", fooAddr)) + require.Len(t, txsPage1, 15) + txsPage2 := f.QueryTxs(2, 15, fmt.Sprintf("sender:%s", fooAddr)) + require.Len(t, txsPage2, 15) + require.NotEqual(t, txsPage1, txsPage2) + txsPage3 := f.QueryTxs(3, 15, fmt.Sprintf("sender:%s", fooAddr)) + require.Len(t, txsPage3, 15) + require.Equal(t, txsPage2, txsPage3) + + // perPage = 16, 2 pages + txsPage1 = f.QueryTxs(1, 16, fmt.Sprintf("sender:%s", fooAddr)) + require.Len(t, txsPage1, 16) + txsPage2 = f.QueryTxs(2, 16, fmt.Sprintf("sender:%s", fooAddr)) + require.Len(t, txsPage2, 14) + require.NotEqual(t, txsPage1, txsPage2) + + // perPage = 50 + txsPageFull := f.QueryTxs(1, 50, fmt.Sprintf("sender:%s", fooAddr)) + require.Len(t, txsPageFull, 30) + require.Equal(t, txsPageFull, append(txsPage1, txsPage2...)) + + // perPage = 0 + f.QueryTxsInvalid(errors.New("ERROR: page must greater than 0"), 0, 50, fmt.Sprintf("sender:%s", fooAddr)) + + // limit = 0 + f.QueryTxsInvalid(errors.New("ERROR: limit must greater than 0"), 1, 0, fmt.Sprintf("sender:%s", fooAddr)) +} + +func TestGaiaCLIValidateSignatures(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server + proc := f.GDStart() + defer proc.Stop(false) + + fooAddr := f.KeyAddress(keyFoo) + barAddr := f.KeyAddress(keyBar) + + // generate sendTx with default gas + success, stdout, stderr := f.TxSend(fooAddr.String(), barAddr, sdk.NewInt64Coin(denom, 10), "--generate-only") + require.True(t, success) + require.Empty(t, stderr) + + // write unsigned tx to file + unsignedTxFile := WriteToNewTempFile(t, stdout) + defer os.Remove(unsignedTxFile.Name()) + + // validate we can successfully sign + success, stdout, stderr = f.TxSign(keyFoo, unsignedTxFile.Name()) + require.True(t, success) + require.Empty(t, stderr) + stdTx := unmarshalStdTx(t, stdout) + require.Equal(t, len(stdTx.Msgs), 1) + require.Equal(t, 1, len(stdTx.GetSignatures())) + require.Equal(t, fooAddr.String(), stdTx.GetSigners()[0].String()) + + // write signed tx to file + signedTxFile := WriteToNewTempFile(t, stdout) + defer os.Remove(signedTxFile.Name()) + + // validate signatures + success, _, _ = f.TxSign(keyFoo, signedTxFile.Name(), "--validate-signatures") + require.True(t, success) + + // modify the transaction + stdTx.Memo = "MODIFIED-ORIGINAL-TX-BAD" + bz := marshalStdTx(t, stdTx) + modSignedTxFile := WriteToNewTempFile(t, string(bz)) + defer os.Remove(modSignedTxFile.Name()) + + // validate signature validation failure due to different transaction sig bytes + success, _, _ = f.TxSign(keyFoo, modSignedTxFile.Name(), "--validate-signatures") + require.False(t, success) + + f.Cleanup() +} + +func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server + proc := f.GDStart() + defer proc.Stop(false) + + fooAddr := f.KeyAddress(keyFoo) + barAddr := f.KeyAddress(keyBar) + + // Test generate sendTx with default gas + sendTokens := sdk.TokensFromTendermintPower(10) + success, stdout, stderr := f.TxSend(fooAddr.String(), barAddr, sdk.NewCoin(denom, sendTokens), "--generate-only") + require.True(t, success) + require.Empty(t, stderr) + msg := unmarshalStdTx(t, stdout) + require.Equal(t, msg.Fee.Gas, uint64(client.DefaultGasLimit)) + require.Equal(t, len(msg.Msgs), 1) + require.Equal(t, 0, len(msg.GetSignatures())) + + // Test generate sendTx with --gas=$amount + success, stdout, stderr = f.TxSend(fooAddr.String(), barAddr, sdk.NewCoin(denom, sendTokens), "--gas=100", "--generate-only") + require.True(t, success) + require.Empty(t, stderr) + msg = unmarshalStdTx(t, stdout) + require.Equal(t, msg.Fee.Gas, uint64(100)) + require.Equal(t, len(msg.Msgs), 1) + require.Equal(t, 0, len(msg.GetSignatures())) + + // Test generate sendTx, estimate gas + success, stdout, stderr = f.TxSend(fooAddr.String(), barAddr, sdk.NewCoin(denom, sendTokens), "--gas=auto", "--generate-only") + require.True(t, success) + require.NotEmpty(t, stderr) + msg = unmarshalStdTx(t, stdout) + require.True(t, msg.Fee.Gas > 0) + require.Equal(t, len(msg.Msgs), 1) + + // Write the output to disk + unsignedTxFile := WriteToNewTempFile(t, stdout) + defer os.Remove(unsignedTxFile.Name()) + + // Test sign --validate-signatures + success, stdout, _ = f.TxSign(keyFoo, unsignedTxFile.Name(), "--validate-signatures") + require.False(t, success) + require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n\n", fooAddr.String()), stdout) + + // Test sign + success, stdout, _ = f.TxSign(keyFoo, unsignedTxFile.Name()) + require.True(t, success) + msg = unmarshalStdTx(t, stdout) + require.Equal(t, len(msg.Msgs), 1) + require.Equal(t, 1, len(msg.GetSignatures())) + require.Equal(t, fooAddr.String(), msg.GetSigners()[0].String()) + + // Write the output to disk + signedTxFile := WriteToNewTempFile(t, stdout) + defer os.Remove(signedTxFile.Name()) + + // Test sign --validate-signatures + success, stdout, _ = f.TxSign(keyFoo, signedTxFile.Name(), "--validate-signatures") + require.True(t, success) + require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n 0: %v\t\t\t[OK]\n\n", fooAddr.String(), + fooAddr.String()), stdout) + + // Ensure foo has right amount of funds + fooAcc := f.QueryAccount(fooAddr) + startTokens := sdk.TokensFromTendermintPower(50) + require.Equal(t, startTokens, fooAcc.GetCoins().AmountOf(denom)) + + // Test broadcast + success, stdout, _ = f.TxBroadcast(signedTxFile.Name()) + require.True(t, success) + + var result sdk.TxResponse + + // Unmarshal the response and ensure that gas was properly used + require.Nil(t, app.MakeCodec().UnmarshalJSON([]byte(stdout), &result)) + require.Equal(t, msg.Fee.Gas, uint64(result.GasUsed)) + require.Equal(t, msg.Fee.Gas, uint64(result.GasWanted)) + tests.WaitForNextNBlocksTM(1, f.Port) + + // Ensure account state + barAcc := f.QueryAccount(barAddr) + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, sendTokens, barAcc.GetCoins().AmountOf(denom)) + require.Equal(t, startTokens.Sub(sendTokens), fooAcc.GetCoins().AmountOf(denom)) + + f.Cleanup() +} + +func TestGaiaCLIMultisignInsufficientCosigners(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server with minimum fees + proc := f.GDStart() + defer proc.Stop(false) + + fooBarBazAddr := f.KeyAddress(keyFooBarBaz) + barAddr := f.KeyAddress(keyBar) + + // Send some tokens from one account to the other + success, _, _ := f.TxSend(keyFoo, fooBarBazAddr, sdk.NewInt64Coin(denom, 10), "-y") + require.True(t, success) + tests.WaitForNextNBlocksTM(1, f.Port) + + // Test generate sendTx with multisig + success, stdout, _ := f.TxSend(fooBarBazAddr.String(), barAddr, sdk.NewInt64Coin(denom, 5), "--generate-only") + require.True(t, success) + + // Write the output to disk + unsignedTxFile := WriteToNewTempFile(t, stdout) + defer os.Remove(unsignedTxFile.Name()) + + // Sign with foo's key + success, stdout, _ = f.TxSign(keyFoo, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String(), "-y") + require.True(t, success) + + // Write the output to disk + fooSignatureFile := WriteToNewTempFile(t, stdout) + defer os.Remove(fooSignatureFile.Name()) + + // Multisign, not enough signatures + success, stdout, _ = f.TxMultisign(unsignedTxFile.Name(), keyFooBarBaz, []string{fooSignatureFile.Name()}) + require.True(t, success) + + // Write the output to disk + signedTxFile := WriteToNewTempFile(t, stdout) + defer os.Remove(signedTxFile.Name()) + + // Validate the multisignature + success, _, _ = f.TxSign(keyFooBarBaz, signedTxFile.Name(), "--validate-signatures") + require.False(t, success) + + // Broadcast the transaction + success, _, _ = f.TxBroadcast(signedTxFile.Name()) + require.False(t, success) +} + +func TestGaiaCLIEncode(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server + proc := f.GDStart() + defer proc.Stop(false) + + cdc := app.MakeCodec() + + // Build a testing transaction and write it to disk + barAddr := f.KeyAddress(keyBar) + keyAddr := f.KeyAddress(keyFoo) + + sendTokens := sdk.TokensFromTendermintPower(10) + success, stdout, stderr := f.TxSend(keyAddr.String(), barAddr, sdk.NewCoin(denom, sendTokens), "--generate-only", "--memo", "deadbeef") + require.True(t, success) + require.Empty(t, stderr) + + // Write it to disk + jsonTxFile := WriteToNewTempFile(t, stdout) + defer os.Remove(jsonTxFile.Name()) + + // Run the encode command, and trim the extras from the stdout capture + success, base64Encoded, _ := f.TxEncode(jsonTxFile.Name()) + require.True(t, success) + trimmedBase64 := strings.Trim(base64Encoded, "\"\n") + + // Decode the base64 + decodedBytes, err := base64.StdEncoding.DecodeString(trimmedBase64) + require.Nil(t, err) + + // Check that the transaction decodes as epxceted + var decodedTx auth.StdTx + require.Nil(t, cdc.UnmarshalBinaryLengthPrefixed(decodedBytes, &decodedTx)) + require.Equal(t, "deadbeef", decodedTx.Memo) +} + +func TestGaiaCLIMultisignSortSignatures(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server with minimum fees + proc := f.GDStart() + defer proc.Stop(false) + + fooBarBazAddr := f.KeyAddress(keyFooBarBaz) + barAddr := f.KeyAddress(keyBar) + + // Send some tokens from one account to the other + success, _, _ := f.TxSend(keyFoo, fooBarBazAddr, sdk.NewInt64Coin(denom, 10), "-y") + require.True(t, success) + tests.WaitForNextNBlocksTM(1, f.Port) + + // Ensure account balances match expected + fooBarBazAcc := f.QueryAccount(fooBarBazAddr) + require.Equal(t, int64(10), fooBarBazAcc.GetCoins().AmountOf(denom).Int64()) + + // Test generate sendTx with multisig + success, stdout, _ := f.TxSend(fooBarBazAddr.String(), barAddr, sdk.NewInt64Coin(denom, 5), "--generate-only") + require.True(t, success) + + // Write the output to disk + unsignedTxFile := WriteToNewTempFile(t, stdout) + defer os.Remove(unsignedTxFile.Name()) + + // Sign with foo's key + success, stdout, _ = f.TxSign(keyFoo, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String()) + require.True(t, success) + + // Write the output to disk + fooSignatureFile := WriteToNewTempFile(t, stdout) + defer os.Remove(fooSignatureFile.Name()) + + // Sign with baz's key + success, stdout, _ = f.TxSign(keyBaz, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String()) + require.True(t, success) + + // Write the output to disk + bazSignatureFile := WriteToNewTempFile(t, stdout) + defer os.Remove(bazSignatureFile.Name()) + + // Multisign, keys in different order + success, stdout, _ = f.TxMultisign(unsignedTxFile.Name(), keyFooBarBaz, []string{ + bazSignatureFile.Name(), fooSignatureFile.Name()}) + require.True(t, success) + + // Write the output to disk + signedTxFile := WriteToNewTempFile(t, stdout) + defer os.Remove(signedTxFile.Name()) + + // Validate the multisignature + success, _, _ = f.TxSign(keyFooBarBaz, signedTxFile.Name(), "--validate-signatures") + require.True(t, success) + + // Broadcast the transaction + success, _, _ = f.TxBroadcast(signedTxFile.Name()) + require.True(t, success) +} + +func TestGaiaCLIMultisign(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server with minimum fees + proc := f.GDStart() + defer proc.Stop(false) + + fooBarBazAddr := f.KeyAddress(keyFooBarBaz) + bazAddr := f.KeyAddress(keyBaz) + + // Send some tokens from one account to the other + success, _, _ := f.TxSend(keyFoo, fooBarBazAddr, sdk.NewInt64Coin(denom, 10), "-y") + require.True(t, success) + tests.WaitForNextNBlocksTM(1, f.Port) + + // Ensure account balances match expected + fooBarBazAcc := f.QueryAccount(fooBarBazAddr) + require.Equal(t, int64(10), fooBarBazAcc.GetCoins().AmountOf(denom).Int64()) + + // Test generate sendTx with multisig + success, stdout, stderr := f.TxSend(fooBarBazAddr.String(), bazAddr, sdk.NewInt64Coin(denom, 10), "--generate-only") + require.True(t, success) + require.Empty(t, stderr) + + // Write the output to disk + unsignedTxFile := WriteToNewTempFile(t, stdout) + defer os.Remove(unsignedTxFile.Name()) + + // Sign with foo's key + success, stdout, _ = f.TxSign(keyFoo, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String(), "-y") + require.True(t, success) + + // Write the output to disk + fooSignatureFile := WriteToNewTempFile(t, stdout) + defer os.Remove(fooSignatureFile.Name()) + + // Sign with bar's key + success, stdout, _ = f.TxSign(keyBar, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String(), "-y") + require.True(t, success) + + // Write the output to disk + barSignatureFile := WriteToNewTempFile(t, stdout) + defer os.Remove(barSignatureFile.Name()) + + // Multisign + success, stdout, _ = f.TxMultisign(unsignedTxFile.Name(), keyFooBarBaz, []string{ + fooSignatureFile.Name(), barSignatureFile.Name()}) + require.True(t, success) + + // Write the output to disk + signedTxFile := WriteToNewTempFile(t, stdout) + defer os.Remove(signedTxFile.Name()) + + // Validate the multisignature + success, _, _ = f.TxSign(keyFooBarBaz, signedTxFile.Name(), "--validate-signatures", "-y") + require.True(t, success) + + // Broadcast the transaction + success, _, _ = f.TxBroadcast(signedTxFile.Name()) + require.True(t, success) +} + +func TestGaiaCLIConfig(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + node := fmt.Sprintf("%s:%s", f.RPCAddr, f.Port) + + // Set available configuration options + f.CLIConfig("broadcast-mode", "block") + f.CLIConfig("node", node) + f.CLIConfig("output", "text") + f.CLIConfig("trust-node", "true") + f.CLIConfig("chain-id", f.ChainID) + f.CLIConfig("trace", "false") + f.CLIConfig("indent", "true") + + config, err := ioutil.ReadFile(path.Join(f.GCLIHome, "config", "config.toml")) + require.NoError(t, err) + expectedConfig := fmt.Sprintf(`broadcast-mode = "block" +chain-id = "%s" +indent = true +node = "%s" +output = "text" +trace = false +trust-node = true +`, f.ChainID, node) + require.Equal(t, expectedConfig, string(config)) + + f.Cleanup() +} + +func TestGaiadCollectGentxs(t *testing.T) { + t.Parallel() + f := NewFixtures(t) + + // Initialise temporary directories + gentxDir, err := ioutil.TempDir("", "") + gentxDoc := filepath.Join(gentxDir, "gentx.json") + require.NoError(t, err) + + // Reset testing path + f.UnsafeResetAll() + + // Initialize keys + f.KeysAdd(keyFoo) + + // Configure json output + f.CLIConfig("output", "json") + + // Run init + f.GDInit(keyFoo) + + // Add account to genesis.json + f.AddGenesisAccount(f.KeyAddress(keyFoo), startCoins) + + // Write gentx file + f.GenTx(keyFoo, fmt.Sprintf("--output-document=%s", gentxDoc)) + + // Collect gentxs from a custom directory + f.CollectGenTxs(fmt.Sprintf("--gentx-dir=%s", gentxDir)) + + f.Cleanup(gentxDir) +} + +func TestGaiadAddGenesisAccount(t *testing.T) { + t.Parallel() + f := NewFixtures(t) + + // Reset testing path + f.UnsafeResetAll() + + // Initialize keys + f.KeysDelete(keyFoo) + f.KeysDelete(keyBar) + f.KeysDelete(keyBaz) + f.KeysAdd(keyFoo) + f.KeysAdd(keyBar) + f.KeysAdd(keyBaz) + + // Configure json output + f.CLIConfig("output", "json") + + // Run init + f.GDInit(keyFoo) + + // Add account to genesis.json + bazCoins := sdk.Coins{ + sdk.NewInt64Coin("acoin", 1000000), + sdk.NewInt64Coin("bcoin", 1000000), + } + + f.AddGenesisAccount(f.KeyAddress(keyFoo), startCoins) + f.AddGenesisAccount(f.KeyAddress(keyBar), bazCoins) + genesisState := f.GenesisState() + require.Equal(t, genesisState.Accounts[0].Address, f.KeyAddress(keyFoo)) + require.Equal(t, genesisState.Accounts[1].Address, f.KeyAddress(keyBar)) + require.True(t, genesisState.Accounts[0].Coins.IsEqual(startCoins)) + require.True(t, genesisState.Accounts[1].Coins.IsEqual(bazCoins)) +} + +func TestSlashingGetParams(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server + proc := f.GDStart() + defer proc.Stop(false) + + params := f.QuerySlashingParams() + require.Equal(t, time.Duration(120000000000), params.MaxEvidenceAge) + require.Equal(t, int64(100), params.SignedBlocksWindow) + require.Equal(t, sdk.NewDecWithPrec(5, 1), params.MinSignedPerWindow) + + sinfo := f.QuerySigningInfo(f.GDTendermint("show-validator")) + require.Equal(t, int64(0), sinfo.StartHeight) + require.False(t, sinfo.Tombstoned) +} + +func TestValidateGenesis(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start gaiad server + proc := f.GDStart() + defer proc.Stop(false) + + f.ValidateGenesis() +} diff --git a/cli_test/doc.go b/cli_test/doc.go new file mode 100644 index 00000000..51ef2ad5 --- /dev/null +++ b/cli_test/doc.go @@ -0,0 +1,2 @@ +// Package clitest runs integration tests which make use of CLI commands. +package clitest diff --git a/cli_test/test_helpers.go b/cli_test/test_helpers.go new file mode 100644 index 00000000..6441f444 --- /dev/null +++ b/cli_test/test_helpers.go @@ -0,0 +1,704 @@ +package clitest + +import ( + "encoding/json" + "fmt" + "go/build" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/require" + + cmn "github.com/tendermint/tendermint/libs/common" + + clientkeys "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/codec" + "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/gov" + "github.com/cosmos/cosmos-sdk/x/slashing" + "github.com/cosmos/cosmos-sdk/x/staking" + + "github.com/kava-labs/kava/app" + appInit "github.com/kava-labs/kava/init" +) + +const ( + denom = "stake" + keyFoo = "foo" + keyBar = "bar" + fooDenom = "footoken" + feeDenom = "feetoken" + fee2Denom = "fee2token" + keyBaz = "baz" + keyVesting = "vesting" + keyFooBarBaz = "foobarbaz" +) + +var ( + startCoins = sdk.Coins{ + sdk.NewCoin(feeDenom, sdk.TokensFromTendermintPower(1000000)), + sdk.NewCoin(fee2Denom, sdk.TokensFromTendermintPower(1000000)), + sdk.NewCoin(fooDenom, sdk.TokensFromTendermintPower(1000)), + sdk.NewCoin(denom, sdk.TokensFromTendermintPower(150)), + } + + vestingCoins = sdk.Coins{ + sdk.NewCoin(feeDenom, sdk.TokensFromTendermintPower(500000)), + } +) + +func init() { + // set the address prefixes + config := sdk.GetConfig() + app.SetBech32AddressPrefixes(config) + config.Seal() +} + +//___________________________________________________________________________________ +// Fixtures + +// Fixtures is used to setup the testing environment +type Fixtures struct { + ChainID string + RPCAddr string + Port string + AppDaemonBinary string + AppCliBinary string + GDHome string + GCLIHome string + P2PAddr string + T *testing.T +} + +// NewFixtures creates a new instance of Fixtures with many vars set +func NewFixtures(t *testing.T) *Fixtures { + tmpDir, err := ioutil.TempDir("", "kava_integration_"+t.Name()+"_") + require.NoError(t, err) + + // set location of the app binaries + buildDir := os.Getenv("BUILDDIR") + if buildDir == "" { + buildDir = filepath.Join(build.Default.GOPATH, "bin") + } + + servAddr, port, err := server.FreeTCPAddr() + require.NoError(t, err) + + p2pAddr, _, err := server.FreeTCPAddr() + require.NoError(t, err) + + return &Fixtures{ + T: t, + AppDaemonBinary: filepath.Join(buildDir, "kvd"), + AppCliBinary: filepath.Join(buildDir, "kvcli"), + GDHome: filepath.Join(tmpDir, ".kvd"), + GCLIHome: filepath.Join(tmpDir, ".kvcli"), + RPCAddr: servAddr, + P2PAddr: p2pAddr, + Port: port, + } +} + +// GenesisFile returns the path of the genesis file +func (f Fixtures) GenesisFile() string { + return filepath.Join(f.GDHome, "config", "genesis.json") +} + +// GenesisFile returns the application's genesis state +func (f Fixtures) GenesisState() app.GenesisState { + cdc := codec.New() + genDoc, err := appInit.LoadGenesisDoc(cdc, f.GenesisFile()) + require.NoError(f.T, err) + + var appState app.GenesisState + require.NoError(f.T, cdc.UnmarshalJSON(genDoc.AppState, &appState)) + return appState +} + +// InitFixtures is called at the beginning of a test and initializes a chain +// with 1 validator. +func InitFixtures(t *testing.T) (f *Fixtures) { + f = NewFixtures(t) + + // reset test state + f.UnsafeResetAll() + + // ensure keystore has foo and bar keys + f.KeysDelete(keyFoo) + f.KeysDelete(keyBar) + f.KeysDelete(keyBar) + f.KeysDelete(keyFooBarBaz) + f.KeysAdd(keyFoo) + f.KeysAdd(keyBar) + f.KeysAdd(keyBaz) + f.KeysAdd(keyVesting) + f.KeysAdd(keyFooBarBaz, "--multisig-threshold=2", fmt.Sprintf( + "--multisig=%s,%s,%s", keyFoo, keyBar, keyBaz)) + + // ensure that CLI output is in JSON format + f.CLIConfig("output", "json") + + // NOTE: GDInit sets the ChainID + f.GDInit(keyFoo) + + f.CLIConfig("chain-id", f.ChainID) + f.CLIConfig("broadcast-mode", "block") + + // start an account with tokens + f.AddGenesisAccount(f.KeyAddress(keyFoo), startCoins) + f.AddGenesisAccount( + f.KeyAddress(keyVesting), startCoins, + fmt.Sprintf("--vesting-amount=%s", vestingCoins), + fmt.Sprintf("--vesting-start-time=%d", time.Now().UTC().UnixNano()), + fmt.Sprintf("--vesting-end-time=%d", time.Now().Add(60*time.Second).UTC().UnixNano()), + ) + + f.GenTx(keyFoo) + f.CollectGenTxs() + + return +} + +// Cleanup is meant to be run at the end of a test to clean up an remaining test state +func (f *Fixtures) Cleanup(dirs ...string) { + clean := append(dirs, f.GDHome, f.GCLIHome) + for _, d := range clean { + err := os.RemoveAll(d) + require.NoError(f.T, err) + } +} + +// Flags returns the flags necessary for making most CLI calls +func (f *Fixtures) Flags() string { + return fmt.Sprintf("--home=%s --node=%s", f.GCLIHome, f.RPCAddr) +} + +//___________________________________________________________________________________ +// gaiad + +// UnsafeResetAll is gaiad unsafe-reset-all +func (f *Fixtures) UnsafeResetAll(flags ...string) { + cmd := fmt.Sprintf("%s --home=%s unsafe-reset-all", f.AppDaemonBinary, f.GDHome) + executeWrite(f.T, addFlags(cmd, flags)) + err := os.RemoveAll(filepath.Join(f.GDHome, "config", "gentx")) + require.NoError(f.T, err) +} + +// GDInit is gaiad init +// NOTE: GDInit sets the ChainID for the Fixtures instance +func (f *Fixtures) GDInit(moniker string, flags ...string) { + cmd := fmt.Sprintf("%s init -o --home=%s %s", f.AppDaemonBinary, f.GDHome, moniker) + _, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), app.DefaultKeyPass) + + var chainID string + var initRes map[string]json.RawMessage + + err := json.Unmarshal([]byte(stderr), &initRes) + require.NoError(f.T, err) + + err = json.Unmarshal(initRes["chain_id"], &chainID) + require.NoError(f.T, err) + + f.ChainID = chainID +} + +// AddGenesisAccount is gaiad add-genesis-account +func (f *Fixtures) AddGenesisAccount(address sdk.AccAddress, coins sdk.Coins, flags ...string) { + cmd := fmt.Sprintf("%s add-genesis-account %s %s --home=%s", f.AppDaemonBinary, address, coins, f.GDHome) + executeWriteCheckErr(f.T, addFlags(cmd, flags)) +} + +// GenTx is gaiad gentx +func (f *Fixtures) GenTx(name string, flags ...string) { + cmd := fmt.Sprintf("%s gentx --name=%s --home=%s --home-client=%s", f.AppDaemonBinary, name, f.GDHome, f.GCLIHome) + executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass) +} + +// CollectGenTxs is gaiad collect-gentxs +func (f *Fixtures) CollectGenTxs(flags ...string) { + cmd := fmt.Sprintf("%s collect-gentxs --home=%s", f.AppDaemonBinary, f.GDHome) + executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass) +} + +// GDStart runs gaiad start with the appropriate flags and returns a process +func (f *Fixtures) GDStart(flags ...string) *tests.Process { + cmd := fmt.Sprintf("%s start --home=%s --rpc.laddr=%v --p2p.laddr=%v", f.AppDaemonBinary, f.GDHome, f.RPCAddr, f.P2PAddr) + proc := tests.GoExecuteTWithStdout(f.T, addFlags(cmd, flags)) + tests.WaitForTMStart(f.Port) + tests.WaitForNextNBlocksTM(1, f.Port) + return proc +} + +// GDTendermint returns the results of gaiad tendermint [query] +func (f *Fixtures) GDTendermint(query string) string { + cmd := fmt.Sprintf("%s tendermint %s --home=%s", f.AppDaemonBinary, query, f.GDHome) + success, stdout, stderr := executeWriteRetStdStreams(f.T, cmd) + require.Empty(f.T, stderr) + require.True(f.T, success) + return strings.TrimSpace(stdout) +} + +// ValidateGenesis runs gaiad validate-genesis +func (f *Fixtures) ValidateGenesis() { + cmd := fmt.Sprintf("%s validate-genesis --home=%s", f.AppDaemonBinary, f.GDHome) + executeWriteCheckErr(f.T, cmd) +} + +//___________________________________________________________________________________ +// gaiacli keys + +// KeysDelete is gaiacli keys delete +func (f *Fixtures) KeysDelete(name string, flags ...string) { + cmd := fmt.Sprintf("%s keys delete --home=%s %s", f.AppCliBinary, f.GCLIHome, name) + executeWrite(f.T, addFlags(cmd, append(append(flags, "-y"), "-f"))) +} + +// KeysAdd is gaiacli keys add +func (f *Fixtures) KeysAdd(name string, flags ...string) { + cmd := fmt.Sprintf("%s keys add --home=%s %s", f.AppCliBinary, f.GCLIHome, name) + executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass) +} + +// KeysAddRecover prepares gaiacli keys add --recover +func (f *Fixtures) KeysAddRecover(name, mnemonic string, flags ...string) (exitSuccess bool, stdout, stderr string) { + cmd := fmt.Sprintf("%s keys add --home=%s --recover %s", f.AppCliBinary, f.GCLIHome, name) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic) +} + +// KeysAddRecoverHDPath prepares gaiacli keys add --recover --account --index +func (f *Fixtures) KeysAddRecoverHDPath(name, mnemonic string, account uint32, index uint32, flags ...string) { + cmd := fmt.Sprintf("%s keys add --home=%s --recover %s --account %d --index %d", f.AppCliBinary, f.GCLIHome, name, account, index) + executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic) +} + +// KeysShow is gaiacli keys show +func (f *Fixtures) KeysShow(name string, flags ...string) keys.KeyOutput { + cmd := fmt.Sprintf("%s keys show --home=%s %s", f.AppCliBinary, f.GCLIHome, name) + out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + var ko keys.KeyOutput + err := clientkeys.UnmarshalJSON([]byte(out), &ko) + require.NoError(f.T, err) + return ko +} + +// KeyAddress returns the SDK account address from the key +func (f *Fixtures) KeyAddress(name string) sdk.AccAddress { + ko := f.KeysShow(name) + accAddr, err := sdk.AccAddressFromBech32(ko.Address) + require.NoError(f.T, err) + return accAddr +} + +//___________________________________________________________________________________ +// gaiacli config + +// CLIConfig is gaiacli config +func (f *Fixtures) CLIConfig(key, value string, flags ...string) { + cmd := fmt.Sprintf("%s config --home=%s %s %s", f.AppCliBinary, f.GCLIHome, key, value) + executeWriteCheckErr(f.T, addFlags(cmd, flags)) +} + +//___________________________________________________________________________________ +// gaiacli tx send/sign/broadcast + +// TxSend is gaiacli tx send +func (f *Fixtures) TxSend(from string, to sdk.AccAddress, amount sdk.Coin, flags ...string) (bool, string, string) { + cmd := fmt.Sprintf("%s tx send %s %s %v --from=%s", f.AppCliBinary, to, amount, f.Flags(), from) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass) +} + +func (f *Fixtures) txSendWithConfirm( + from string, to sdk.AccAddress, amount sdk.Coin, confirm string, flags ...string, +) (bool, string, string) { + + cmd := fmt.Sprintf("%s tx send %s %s %v --from=%s", f.AppCliBinary, to, amount, f.Flags(), from) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), confirm, app.DefaultKeyPass) +} + +// TxSign is gaiacli tx sign +func (f *Fixtures) TxSign(signer, fileName string, flags ...string) (bool, string, string) { + cmd := fmt.Sprintf("%s tx sign %v --from=%s %v", f.AppCliBinary, f.Flags(), signer, fileName) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass) +} + +// TxBroadcast is gaiacli tx broadcast +func (f *Fixtures) TxBroadcast(fileName string, flags ...string) (bool, string, string) { + cmd := fmt.Sprintf("%s tx broadcast %v %v", f.AppCliBinary, f.Flags(), fileName) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass) +} + +// TxEncode is gaiacli tx encode +func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, string) { + cmd := fmt.Sprintf("%s tx encode %v %v", f.AppCliBinary, f.Flags(), fileName) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass) +} + +// TxMultisign is gaiacli tx multisign +func (f *Fixtures) TxMultisign(fileName, name string, signaturesFiles []string, + flags ...string) (bool, string, string) { + + cmd := fmt.Sprintf("%s tx multisign %v %s %s %s", f.AppCliBinary, f.Flags(), + fileName, name, strings.Join(signaturesFiles, " "), + ) + return executeWriteRetStdStreams(f.T, cmd) +} + +//___________________________________________________________________________________ +// gaiacli tx staking + +// TxStakingCreateValidator is gaiacli tx staking create-validator +func (f *Fixtures) TxStakingCreateValidator(from, consPubKey string, amount sdk.Coin, flags ...string) (bool, string, string) { + cmd := fmt.Sprintf("%s tx staking create-validator %v --from=%s --pubkey=%s", f.AppCliBinary, f.Flags(), from, consPubKey) + cmd += fmt.Sprintf(" --amount=%v --moniker=%v --commission-rate=%v", amount, from, "0.05") + cmd += fmt.Sprintf(" --commission-max-rate=%v --commission-max-change-rate=%v", "0.20", "0.10") + cmd += fmt.Sprintf(" --min-self-delegation=%v", "1") + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass) +} + +// TxStakingUnbond is gaiacli tx staking unbond +func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress, flags ...string) bool { + cmd := fmt.Sprintf("%s tx staking unbond %s %v --from=%s %v", f.AppCliBinary, validator, shares, from, f.Flags()) + return executeWrite(f.T, addFlags(cmd, flags), app.DefaultKeyPass) +} + +//___________________________________________________________________________________ +// gaiacli tx gov + +// TxGovSubmitProposal is gaiacli tx gov submit-proposal +func (f *Fixtures) TxGovSubmitProposal(from, typ, title, description string, deposit sdk.Coin, flags ...string) (bool, string, string) { + cmd := fmt.Sprintf("%s tx gov submit-proposal %v --from=%s --type=%s", f.AppCliBinary, f.Flags(), from, typ) + cmd += fmt.Sprintf(" --title=%s --description=%s --deposit=%s", title, description, deposit) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass) +} + +// TxGovDeposit is gaiacli tx gov deposit +func (f *Fixtures) TxGovDeposit(proposalID int, from string, amount sdk.Coin, flags ...string) (bool, string, string) { + cmd := fmt.Sprintf("%s tx gov deposit %d %s --from=%s %v", f.AppCliBinary, proposalID, amount, from, f.Flags()) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass) +} + +// TxGovVote is gaiacli tx gov vote +func (f *Fixtures) TxGovVote(proposalID int, option gov.VoteOption, from string, flags ...string) (bool, string, string) { + cmd := fmt.Sprintf("%s tx gov vote %d %s --from=%s %v", f.AppCliBinary, proposalID, option, from, f.Flags()) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass) +} + +//___________________________________________________________________________________ +// gaiacli query account + +// QueryAccount is gaiacli query account +func (f *Fixtures) QueryAccount(address sdk.AccAddress, flags ...string) auth.BaseAccount { + cmd := fmt.Sprintf("%s query account %s %v", f.AppCliBinary, address, f.Flags()) + out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + var initRes map[string]json.RawMessage + err := json.Unmarshal([]byte(out), &initRes) + require.NoError(f.T, err, "out %v, err %v", out, err) + value := initRes["value"] + var acc auth.BaseAccount + cdc := codec.New() + codec.RegisterCrypto(cdc) + err = cdc.UnmarshalJSON(value, &acc) + require.NoError(f.T, err, "value %v, err %v", string(value), err) + return acc +} + +//___________________________________________________________________________________ +// gaiacli query txs + +// QueryTxs is gaiacli query txs +func (f *Fixtures) QueryTxs(page, limit int, tags ...string) []sdk.TxResponse { + cmd := fmt.Sprintf("%s query txs --page=%d --limit=%d --tags='%s' %v", f.AppCliBinary, page, limit, queryTags(tags), f.Flags()) + out, _ := tests.ExecuteT(f.T, cmd, "") + var txs []sdk.TxResponse + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &txs) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return txs +} + +// QueryTxsInvalid query txs with wrong parameters and compare expected error +func (f *Fixtures) QueryTxsInvalid(expectedErr error, page, limit int, tags ...string) { + cmd := fmt.Sprintf("%s query txs --page=%d --limit=%d --tags='%s' %v", f.AppCliBinary, page, limit, queryTags(tags), f.Flags()) + _, err := tests.ExecuteT(f.T, cmd, "") + require.EqualError(f.T, expectedErr, err) +} + +//___________________________________________________________________________________ +// gaiacli query staking + +// QueryStakingValidator is gaiacli query staking validator +func (f *Fixtures) QueryStakingValidator(valAddr sdk.ValAddress, flags ...string) staking.Validator { + cmd := fmt.Sprintf("%s query staking validator %s %v", f.AppCliBinary, valAddr, f.Flags()) + out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + var validator staking.Validator + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &validator) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return validator +} + +// QueryStakingUnbondingDelegationsFrom is gaiacli query staking unbonding-delegations-from +func (f *Fixtures) QueryStakingUnbondingDelegationsFrom(valAddr sdk.ValAddress, flags ...string) []staking.UnbondingDelegation { + cmd := fmt.Sprintf("%s query staking unbonding-delegations-from %s %v", f.AppCliBinary, valAddr, f.Flags()) + out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + var ubds []staking.UnbondingDelegation + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &ubds) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return ubds +} + +// QueryStakingDelegationsTo is gaiacli query staking delegations-to +func (f *Fixtures) QueryStakingDelegationsTo(valAddr sdk.ValAddress, flags ...string) []staking.Delegation { + cmd := fmt.Sprintf("%s query staking delegations-to %s %v", f.AppCliBinary, valAddr, f.Flags()) + out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + var delegations []staking.Delegation + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &delegations) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return delegations +} + +// QueryStakingPool is gaiacli query staking pool +func (f *Fixtures) QueryStakingPool(flags ...string) staking.Pool { + cmd := fmt.Sprintf("%s query staking pool %v", f.AppCliBinary, f.Flags()) + out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + var pool staking.Pool + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &pool) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return pool +} + +// QueryStakingParameters is gaiacli query staking parameters +func (f *Fixtures) QueryStakingParameters(flags ...string) staking.Params { + cmd := fmt.Sprintf("%s query staking params %v", f.AppCliBinary, f.Flags()) + out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + var params staking.Params + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), ¶ms) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return params +} + +//___________________________________________________________________________________ +// gaiacli query gov + +// QueryGovParamDeposit is gaiacli query gov param deposit +func (f *Fixtures) QueryGovParamDeposit() gov.DepositParams { + cmd := fmt.Sprintf("%s query gov param deposit %s", f.AppCliBinary, f.Flags()) + out, _ := tests.ExecuteT(f.T, cmd, "") + var depositParam gov.DepositParams + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &depositParam) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return depositParam +} + +// QueryGovParamVoting is gaiacli query gov param voting +func (f *Fixtures) QueryGovParamVoting() gov.VotingParams { + cmd := fmt.Sprintf("%s query gov param voting %s", f.AppCliBinary, f.Flags()) + out, _ := tests.ExecuteT(f.T, cmd, "") + var votingParam gov.VotingParams + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &votingParam) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return votingParam +} + +// QueryGovParamTallying is gaiacli query gov param tallying +func (f *Fixtures) QueryGovParamTallying() gov.TallyParams { + cmd := fmt.Sprintf("%s query gov param tallying %s", f.AppCliBinary, f.Flags()) + out, _ := tests.ExecuteT(f.T, cmd, "") + var tallyingParam gov.TallyParams + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &tallyingParam) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return tallyingParam +} + +// QueryGovProposals is gaiacli query gov proposals +func (f *Fixtures) QueryGovProposals(flags ...string) gov.Proposals { + cmd := fmt.Sprintf("%s query gov proposals %v", f.AppCliBinary, f.Flags()) + stdout, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + if strings.Contains(stderr, "No matching proposals found") { + return gov.Proposals{} + } + require.Empty(f.T, stderr) + var out gov.Proposals + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(stdout), &out) + require.NoError(f.T, err) + return out +} + +// QueryGovProposal is gaiacli query gov proposal +func (f *Fixtures) QueryGovProposal(proposalID int, flags ...string) gov.Proposal { + cmd := fmt.Sprintf("%s query gov proposal %d %v", f.AppCliBinary, proposalID, f.Flags()) + out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + var proposal gov.Proposal + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &proposal) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return proposal +} + +// QueryGovVote is gaiacli query gov vote +func (f *Fixtures) QueryGovVote(proposalID int, voter sdk.AccAddress, flags ...string) gov.Vote { + cmd := fmt.Sprintf("%s query gov vote %d %s %v", f.AppCliBinary, proposalID, voter, f.Flags()) + out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + var vote gov.Vote + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &vote) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return vote +} + +// QueryGovVotes is gaiacli query gov votes +func (f *Fixtures) QueryGovVotes(proposalID int, flags ...string) []gov.Vote { + cmd := fmt.Sprintf("%s query gov votes %d %v", f.AppCliBinary, proposalID, f.Flags()) + out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + var votes []gov.Vote + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &votes) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return votes +} + +// QueryGovDeposit is gaiacli query gov deposit +func (f *Fixtures) QueryGovDeposit(proposalID int, depositor sdk.AccAddress, flags ...string) gov.Deposit { + cmd := fmt.Sprintf("%s query gov deposit %d %s %v", f.AppCliBinary, proposalID, depositor, f.Flags()) + out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + var deposit gov.Deposit + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &deposit) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return deposit +} + +// QueryGovDeposits is gaiacli query gov deposits +func (f *Fixtures) QueryGovDeposits(propsalID int, flags ...string) []gov.Deposit { + cmd := fmt.Sprintf("%s query gov deposits %d %v", f.AppCliBinary, propsalID, f.Flags()) + out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + var deposits []gov.Deposit + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &deposits) + require.NoError(f.T, err, "out %v\n, err %v", out, err) + return deposits +} + +//___________________________________________________________________________________ +// query slashing + +// QuerySigningInfo returns the signing info for a validator +func (f *Fixtures) QuerySigningInfo(val string) slashing.ValidatorSigningInfo { + cmd := fmt.Sprintf("%s query slashing signing-info %s %s", f.AppCliBinary, val, f.Flags()) + res, errStr := tests.ExecuteT(f.T, cmd, "") + require.Empty(f.T, errStr) + cdc := app.MakeCodec() + var sinfo slashing.ValidatorSigningInfo + err := cdc.UnmarshalJSON([]byte(res), &sinfo) + require.NoError(f.T, err) + return sinfo +} + +// QuerySlashingParams is gaiacli query slashing params +func (f *Fixtures) QuerySlashingParams() slashing.Params { + cmd := fmt.Sprintf("%s query slashing params %s", f.AppCliBinary, f.Flags()) + res, errStr := tests.ExecuteT(f.T, cmd, "") + require.Empty(f.T, errStr) + cdc := app.MakeCodec() + var params slashing.Params + err := cdc.UnmarshalJSON([]byte(res), ¶ms) + require.NoError(f.T, err) + return params +} + +//___________________________________________________________________________________ +// executors + +func executeWriteCheckErr(t *testing.T, cmdStr string, writes ...string) { + require.True(t, executeWrite(t, cmdStr, writes...)) +} + +func executeWrite(t *testing.T, cmdStr string, writes ...string) (exitSuccess bool) { + exitSuccess, _, _ = executeWriteRetStdStreams(t, cmdStr, writes...) + return +} + +func executeWriteRetStdStreams(t *testing.T, cmdStr string, writes ...string) (bool, string, string) { + proc := tests.GoExecuteT(t, cmdStr) + + // Enables use of interactive commands + for _, write := range writes { + _, err := proc.StdinPipe.Write([]byte(write + "\n")) + require.NoError(t, err) + } + + // Read both stdout and stderr from the process + stdout, stderr, err := proc.ReadAll() + if err != nil { + fmt.Println("Err on proc.ReadAll()", err, cmdStr) + } + + // Log output. + if len(stdout) > 0 { + t.Log("Stdout:", cmn.Green(string(stdout))) + } + if len(stderr) > 0 { + t.Log("Stderr:", cmn.Red(string(stderr))) + } + + // Wait for process to exit + proc.Wait() + + // Return succes, stdout, stderr + return proc.ExitState.Success(), string(stdout), string(stderr) +} + +//___________________________________________________________________________________ +// utils + +func addFlags(cmd string, flags []string) string { + for _, f := range flags { + cmd += " " + f + } + return strings.TrimSpace(cmd) +} + +func queryTags(tags []string) (out string) { + for _, tag := range tags { + out += tag + "&" + } + return strings.TrimSuffix(out, "&") +} + +// Write the given string to a new temporary file +func WriteToNewTempFile(t *testing.T, s string) *os.File { + fp, err := ioutil.TempFile(os.TempDir(), "cosmos_cli_test_") + require.Nil(t, err) + _, err = fp.WriteString(s) + require.Nil(t, err) + return fp +} + +func marshalStdTx(t *testing.T, stdTx auth.StdTx) []byte { + cdc := app.MakeCodec() + bz, err := cdc.MarshalBinaryBare(stdTx) + require.NoError(t, err) + return bz +} + +func unmarshalStdTx(t *testing.T, s string) (stdTx auth.StdTx) { + cdc := app.MakeCodec() + require.Nil(t, cdc.UnmarshalJSON([]byte(s), &stdTx)) + return +} diff --git a/cmd/kvcli/main.go b/cmd/kvcli/main.go index 975c9240..755cb715 100644 --- a/cmd/kvcli/main.go +++ b/cmd/kvcli/main.go @@ -54,9 +54,7 @@ func main() { // Read in the configuration file for the sdk config := sdk.GetConfig() - config.SetBech32PrefixForAccount(app.Bech32MainPrefix, app.Bech32MainPrefix+sdk.PrefixPublic) - config.SetBech32PrefixForValidator(app.Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixOperator, app.Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixOperator+sdk.PrefixPublic) - config.SetBech32PrefixForConsensusNode(app.Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixConsensus, app.Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixConsensus+sdk.PrefixPublic) + app.SetBech32AddressPrefixes(config) config.Seal() // TODO: setup keybase, viper object, etc. to be passed into diff --git a/cmd/kvd/main.go b/cmd/kvd/main.go index 520badc4..e982a8ee 100644 --- a/cmd/kvd/main.go +++ b/cmd/kvd/main.go @@ -31,9 +31,7 @@ func main() { cdc := app.MakeCodec() config := sdk.GetConfig() - config.SetBech32PrefixForAccount(app.Bech32MainPrefix, app.Bech32MainPrefix+sdk.PrefixPublic) - config.SetBech32PrefixForValidator(app.Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixOperator, app.Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixOperator+sdk.PrefixPublic) - config.SetBech32PrefixForConsensusNode(app.Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixConsensus, app.Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixConsensus+sdk.PrefixPublic) + app.SetBech32AddressPrefixes(config) config.Seal() ctx := server.NewDefaultContext()