cosmos-sdk/x/auth/client/cli/cli_test.go

452 lines
15 KiB
Go

// +build cli_test
package cli_test
import (
"encoding/base64"
"fmt"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/tests"
"github.com/cosmos/cosmos-sdk/tests/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/client/testutil"
"github.com/cosmos/cosmos-sdk/x/auth/types"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
)
func TestCLIValidateSignatures(t *testing.T) {
t.Parallel()
f := cli.InitFixtures(t)
// start simd server
proc := f.SDStart()
t.Cleanup(func() { proc.Stop(false) })
f.ValidateGenesis()
fooAddr := f.KeyAddress(cli.KeyFoo)
barAddr := f.KeyAddress(cli.KeyBar)
// generate sendTx with default gas
success, stdout, stderr := bankcli.TxSend(f, fooAddr.String(), barAddr, sdk.NewInt64Coin("stake", 10), "--generate-only")
require.True(t, success)
require.Empty(t, stderr)
// write unsigned tx to file
unsignedTxFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// validate we can successfully sign
success, stdout, _ = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name())
require.True(t, success)
stdTx := cli.UnmarshalStdTx(t, f.Cdc, 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, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// validate signatures
success, _, _ = testutil.TxValidateSignatures(f, signedTxFile.Name())
require.True(t, success)
// modify the transaction
stdTx.Memo = "MODIFIED-ORIGINAL-TX-BAD"
bz := cli.MarshalStdTx(t, f.Cdc, stdTx)
modSignedTxFile, cleanup := tests.WriteToNewTempFile(t, string(bz))
t.Cleanup(cleanup)
// validate signature validation failure due to different transaction sig bytes
success, _, _ = testutil.TxValidateSignatures(f, modSignedTxFile.Name())
require.False(t, success)
// Cleanup testing directories
f.Cleanup()
}
func TestCLISignBatch(t *testing.T) {
t.Parallel()
f := cli.InitFixtures(t)
fooAddr := f.KeyAddress(cli.KeyFoo)
barAddr := f.KeyAddress(cli.KeyBar)
sendTokens := sdk.TokensFromConsensusPower(10)
success, generatedStdTx, stderr := bankcli.TxSend(f, fooAddr.String(), barAddr, sdk.NewCoin(cli.Denom, sendTokens), "--generate-only")
require.True(t, success)
require.Empty(t, stderr)
// Write the output to disk
batchfile, cleanup1 := tests.WriteToNewTempFile(t, strings.Repeat(generatedStdTx, 3))
t.Cleanup(cleanup1)
// sign-batch file - offline is set but account-number and sequence are not
success, _, stderr = testutil.TxSignBatch(f, cli.KeyFoo, batchfile.Name(), "--offline")
require.Contains(t, stderr, "required flag(s) \"account-number\", \"sequence\" not set")
require.False(t, success)
// sign-batch file
success, stdout, stderr := testutil.TxSignBatch(f, cli.KeyFoo, batchfile.Name())
require.True(t, success)
require.Empty(t, stderr)
require.Equal(t, 3, len(strings.Split(strings.Trim(stdout, "\n"), "\n")))
// sign-batch file
success, stdout, stderr = testutil.TxSignBatch(f, cli.KeyFoo, batchfile.Name(), "--signature-only")
require.True(t, success)
require.Empty(t, stderr)
require.Equal(t, 3, len(strings.Split(strings.Trim(stdout, "\n"), "\n")))
malformedFile, cleanup2 := tests.WriteToNewTempFile(t, fmt.Sprintf("%smalformed", generatedStdTx))
t.Cleanup(cleanup2)
// sign-batch file
success, stdout, stderr = testutil.TxSignBatch(f, cli.KeyFoo, malformedFile.Name())
require.False(t, success)
require.Equal(t, 1, len(strings.Split(strings.Trim(stdout, "\n"), "\n")))
require.Equal(t, "ERROR: cannot parse disfix JSON wrapper: invalid character 'm' looking for beginning of value\n", stderr)
// sign-batch file
success, stdout, _ = testutil.TxSignBatch(f, cli.KeyFoo, malformedFile.Name(), "--signature-only")
require.False(t, success)
require.Equal(t, 1, len(strings.Split(strings.Trim(stdout, "\n"), "\n")))
f.Cleanup()
}
func TestCLISendGenerateSignAndBroadcast(t *testing.T) {
t.Parallel()
f := cli.InitFixtures(t)
// start simd server
proc := f.SDStart()
t.Cleanup(func() { proc.Stop(false) })
fooAddr := f.KeyAddress(cli.KeyFoo)
barAddr := f.KeyAddress(cli.KeyBar)
// Test generate sendTx with default gas
sendTokens := sdk.TokensFromConsensusPower(10)
success, stdout, stderr := bankcli.TxSend(f, fooAddr.String(), barAddr, sdk.NewCoin(cli.Denom, sendTokens), "--generate-only")
require.True(t, success)
require.Empty(t, stderr)
msg := cli.UnmarshalStdTx(t, f.Cdc, stdout)
require.Equal(t, msg.Fee.Gas, uint64(flags.DefaultGasLimit))
require.Equal(t, len(msg.Msgs), 1)
require.Equal(t, 0, len(msg.GetSignatures()))
// Test generate sendTx with --gas=$amount
success, stdout, stderr = bankcli.TxSend(f, fooAddr.String(), barAddr, sdk.NewCoin(cli.Denom, sendTokens), "--gas=100", "--generate-only")
require.True(t, success)
require.Empty(t, stderr)
msg = cli.UnmarshalStdTx(t, f.Cdc, 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 = bankcli.TxSend(f, fooAddr.String(), barAddr, sdk.NewCoin(cli.Denom, sendTokens), "--generate-only")
require.True(t, success)
require.Empty(t, stderr)
msg = cli.UnmarshalStdTx(t, f.Cdc, stdout)
require.True(t, msg.Fee.Gas > 0)
require.Equal(t, len(msg.Msgs), 1)
// Write the output to disk
unsignedTxFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Test validate-signatures
success, stdout, _ = testutil.TxValidateSignatures(f, unsignedTxFile.Name())
require.False(t, success)
require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n\n", fooAddr.String()), stdout)
// Test sign
// Does not work in offline mode
success, stdout, stderr = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name(), "--offline")
require.Contains(t, stderr, "required flag(s) \"account-number\", \"sequence\" not set")
require.False(t, success)
// But works offline if we set account number and sequence
success, _, _ = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name(), "--offline", "--account-number", "1", "--sequence", "1")
require.True(t, success)
// Sign transaction
success, stdout, _ = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name())
require.True(t, success)
msg = cli.UnmarshalStdTx(t, f.Cdc, 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, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Test validate-signatures
success, stdout, _ = testutil.TxValidateSignatures(f, signedTxFile.Name())
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
startTokens := sdk.TokensFromConsensusPower(50)
require.Equal(t, startTokens, bankcli.QueryBalances(f, fooAddr).AmountOf(cli.Denom))
// Test broadcast
// Does not work in offline mode
success, _, stderr = testutil.TxBroadcast(f, signedTxFile.Name(), "--offline")
require.Contains(t, stderr, "cannot broadcast tx during offline mode")
require.False(t, success)
tests.WaitForNextNBlocksTM(1, f.Port)
success, stdout, _ = testutil.TxBroadcast(f, signedTxFile.Name())
require.True(t, success)
tests.WaitForNextNBlocksTM(1, f.Port)
// Ensure account state
require.Equal(t, sendTokens, bankcli.QueryBalances(f, barAddr).AmountOf(cli.Denom))
require.Equal(t, startTokens.Sub(sendTokens), bankcli.QueryBalances(f, fooAddr).AmountOf(cli.Denom))
f.Cleanup()
}
func TestCLIMultisignInsufficientCosigners(t *testing.T) {
t.Parallel()
f := cli.InitFixtures(t)
// start simd server with minimum fees
proc := f.SDStart()
t.Cleanup(func() { proc.Stop(false) })
fooBarBazAddr := f.KeyAddress(cli.KeyFooBarBaz)
barAddr := f.KeyAddress(cli.KeyBar)
// Send some tokens from one account to the other
success, _, _ := bankcli.TxSend(f, cli.KeyFoo, fooBarBazAddr, sdk.NewInt64Coin(cli.Denom, 10), "-y")
require.True(t, success)
tests.WaitForNextNBlocksTM(1, f.Port)
// Test generate sendTx with multisig
success, stdout, _ := bankcli.TxSend(f, fooBarBazAddr.String(), barAddr, sdk.NewInt64Coin(cli.Denom, 5), "--generate-only")
require.True(t, success)
// Write the output to disk
unsignedTxFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Sign with foo's key
success, stdout, _ = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String(), "-y")
require.True(t, success)
// Write the output to disk
fooSignatureFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Multisign, not enough signatures
success, stdout, _ = testutil.TxMultisign(f, unsignedTxFile.Name(), cli.KeyFooBarBaz, []string{fooSignatureFile.Name()})
require.True(t, success)
// Write the output to disk
signedTxFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Validate the multisignature
success, _, _ = testutil.TxValidateSignatures(f, signedTxFile.Name())
require.False(t, success)
// Broadcast the transaction
success, stdOut, _ := testutil.TxBroadcast(f, signedTxFile.Name())
require.Contains(t, stdOut, "signature verification failed")
require.True(t, success)
// Cleanup testing directories
f.Cleanup()
}
func TestCLIEncode(t *testing.T) {
t.Parallel()
f := cli.InitFixtures(t)
// start simd server
proc := f.SDStart()
t.Cleanup(func() { proc.Stop(false) })
// Build a testing transaction and write it to disk
barAddr := f.KeyAddress(cli.KeyBar)
keyAddr := f.KeyAddress(cli.KeyFoo)
sendTokens := sdk.TokensFromConsensusPower(10)
success, stdout, stderr := bankcli.TxSend(f, keyAddr.String(), barAddr, sdk.NewCoin(cli.Denom, sendTokens), "--generate-only", "--memo", "deadbeef")
require.True(t, success)
require.Empty(t, stderr)
// Write it to disk
jsonTxFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Run the encode command, and trim the extras from the stdout capture
success, base64Encoded, _ := testutil.TxEncode(f, 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 types.StdTx
require.Nil(t, f.Cdc.UnmarshalBinaryBare(decodedBytes, &decodedTx))
require.Equal(t, "deadbeef", decodedTx.Memo)
}
func TestCLIMultisignSortSignatures(t *testing.T) {
t.Parallel()
f := cli.InitFixtures(t)
// start simd server with minimum fees
proc := f.SDStart()
t.Cleanup(func() { proc.Stop(false) })
fooBarBazAddr := f.KeyAddress(cli.KeyFooBarBaz)
barAddr := f.KeyAddress(cli.KeyBar)
// Send some tokens from one account to the other
success, _, _ := bankcli.TxSend(f, cli.KeyFoo, fooBarBazAddr, sdk.NewInt64Coin(cli.Denom, 10), "-y")
require.True(t, success)
tests.WaitForNextNBlocksTM(1, f.Port)
// Ensure account balances match expected
require.Equal(t, int64(10), bankcli.QueryBalances(f, fooBarBazAddr).AmountOf(cli.Denom).Int64())
// Test generate sendTx with multisig
success, stdout, _ := bankcli.TxSend(f, fooBarBazAddr.String(), barAddr, sdk.NewInt64Coin(cli.Denom, 5), "--generate-only")
require.True(t, success)
// Write the output to disk
unsignedTxFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Sign with foo's key
success, stdout, _ = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String())
require.True(t, success)
// Write the output to disk
fooSignatureFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Sign with baz's key
success, stdout, _ = testutil.TxSign(f, cli.KeyBaz, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String())
require.True(t, success)
// Write the output to disk
bazSignatureFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Multisign, keys in different order
success, stdout, _ = testutil.TxMultisign(f, unsignedTxFile.Name(), cli.KeyFooBarBaz, []string{
bazSignatureFile.Name(), fooSignatureFile.Name()})
require.True(t, success)
// Write the output to disk
signedTxFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Validate the multisignature
success, _, _ = testutil.TxValidateSignatures(f, signedTxFile.Name())
require.True(t, success)
// Broadcast the transaction
success, _, _ = testutil.TxBroadcast(f, signedTxFile.Name())
require.True(t, success)
// Cleanup testing directories
f.Cleanup()
}
func TestCLIMultisign(t *testing.T) {
t.Parallel()
f := cli.InitFixtures(t)
// start simd server with minimum fees
proc := f.SDStart()
t.Cleanup(func() { proc.Stop(false) })
fooBarBazAddr := f.KeyAddress(cli.KeyFooBarBaz)
bazAddr := f.KeyAddress(cli.KeyBaz)
// Send some tokens from one account to the other
success, _, _ := bankcli.TxSend(f, cli.KeyFoo, fooBarBazAddr, sdk.NewInt64Coin(cli.Denom, 10), "-y")
require.True(t, success)
tests.WaitForNextNBlocksTM(1, f.Port)
// Ensure account balances match expected
require.Equal(t, int64(10), bankcli.QueryBalances(f, fooBarBazAddr).AmountOf(cli.Denom).Int64())
// Test generate sendTx with multisig
success, stdout, stderr := bankcli.TxSend(f, fooBarBazAddr.String(), bazAddr, sdk.NewInt64Coin(cli.Denom, 10), "--generate-only")
require.True(t, success)
require.Empty(t, stderr)
// Write the output to disk
unsignedTxFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Sign with foo's key
success, stdout, _ = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String(), "-y")
require.True(t, success)
// Write the output to disk
fooSignatureFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Sign with bar's key
success, stdout, _ = testutil.TxSign(f, cli.KeyBar, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String(), "-y")
require.True(t, success)
// Write the output to disk
barSignatureFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Multisign
// Does not work in offline mode
success, stdout, _ = testutil.TxMultisign(f, unsignedTxFile.Name(), cli.KeyFooBarBaz, []string{
fooSignatureFile.Name(), barSignatureFile.Name()}, "--offline")
require.Contains(t, "couldn't verify signature", stdout)
require.False(t, success)
// Success multisign
success, stdout, _ = testutil.TxMultisign(f, unsignedTxFile.Name(), cli.KeyFooBarBaz, []string{
fooSignatureFile.Name(), barSignatureFile.Name()})
require.True(t, success)
// Write the output to disk
signedTxFile, cleanup := tests.WriteToNewTempFile(t, stdout)
t.Cleanup(cleanup)
// Validate the multisignature
success, _, _ = testutil.TxValidateSignatures(f, signedTxFile.Name())
require.True(t, success)
// Broadcast the transaction
success, _, _ = testutil.TxBroadcast(f, signedTxFile.Name())
require.True(t, success)
// Cleanup testing directories
f.Cleanup()
}