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/cmd/gaia/app" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/gov" ) 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) f.KeysAddRecover("test-recover", "dentist task convince chimney quality leave banana trade firm crawl eternal easily") require.Equal(t, "cosmos1qcfdf69js922qrdr4yaww3ax7gjml6pdds46f4", 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, "cosmos1qcfdf69js922qrdr4yaww3ax7gjml6pdds46f4", 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, "cosmos1pdfav2cjhry9k79nu6r8kgknnjtq6a7rykmafy", 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, "cosmos1909k354n6wl8ujzu6kmh49w4d02ax7qvlkv4sn", 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, "cosmos1v9plmhvyhgxk3th9ydacm7j4z357s3nhtwsjat", 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)) 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) 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) 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))) 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))) 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))) 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))) 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)) 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)) 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'") 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 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") 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") 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") 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") 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)) 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(keyBar, 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)) 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.OperatorAddr, 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 unbondTokens := sdk.TokensFromTendermintPower(1) success = f.TxStakingUnbond(keyBar, unbondTokens.String(), barVal) require.True(t, success) tests.WaitForNextNBlocksTM(1, f.Port) // Ensure bonded staking is correct remainingTokens := newValTokens.Sub(unbondTokens) 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( keyFoo, "Text", "Test", "test", sdk.NewCoin(denom, proposalTokens), "--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())) // 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)) 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.GetProposalID()) require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus()) // Ensure query proposals returns properly proposalsQuery = f.QueryGovProposals() require.Equal(t, uint64(1), proposalsQuery[0].GetProposalID()) // 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, keyFoo, 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)) 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.GetProposalID()) require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus()) // Test vote generate only success, stdout, stderr = f.TxGovVote(1, gov.OptionYes, keyFoo, "--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) 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].GetProposalID()) // submit a second test proposal f.TxGovSubmitProposal(keyFoo, "Text", "Apples", "test", sdk.NewCoin(denom, proposalTokens)) tests.WaitForNextNBlocksTM(1, f.Port) // Test limit on proposals query proposalsQuery = f.QueryGovProposals("--limit=1") require.Equal(t, uint64(2), proposalsQuery[0].GetProposalID()) 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)) 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(keyFoo, 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(keyFoo, 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(keyFoo, 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(keyFoo, 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[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)) require.True(t, success) tests.WaitForNextNBlocksTM(1, f.Port) // Test generate sendTx with multisig success, stdout, _ := f.TxSend(keyFooBarBaz, 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()) // 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) sendTokens := sdk.TokensFromTendermintPower(10) success, stdout, stderr := f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--generate-only", "--memo", "deadbeef") require.True(t, success) require.Empty(t, stderr) // Write it to disk jsonTxFile := WriteToNewTempFile(t, stdout) defer os.Remove(jsonTxFile.Name()) // Run the encode command, and trim the extras from the stdout capture success, base64Encoded, _ := f.TxEncode(jsonTxFile.Name()) require.True(t, success) trimmedBase64 := strings.Trim(base64Encoded, "\"\n") // Decode the base64 decodedBytes, err := base64.StdEncoding.DecodeString(trimmedBase64) require.Nil(t, err) // Check that the transaction decodes as epxceted var decodedTx auth.StdTx require.Nil(t, cdc.UnmarshalBinaryLengthPrefixed(decodedBytes, &decodedTx)) require.Equal(t, "deadbeef", decodedTx.Memo) } func TestGaiaCLIMultisignSortSignatures(t *testing.T) { t.Parallel() f := InitFixtures(t) // 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)) 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(keyFooBarBaz, 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)) 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(keyFooBarBaz, 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()) 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()) 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") 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("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(`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() }