678 lines
25 KiB
Go
678 lines
25 KiB
Go
package cli_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
tmcrypto "github.com/tendermint/tendermint/crypto"
|
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
codec2 "github.com/cosmos/cosmos-sdk/codec"
|
|
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
|
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
|
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
|
|
"github.com/cosmos/cosmos-sdk/simapp"
|
|
"github.com/cosmos/cosmos-sdk/testutil"
|
|
"github.com/cosmos/cosmos-sdk/testutil/network"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
authcli "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
|
authtest "github.com/cosmos/cosmos-sdk/x/auth/client/testutil"
|
|
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
|
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
|
)
|
|
|
|
type IntegrationTestSuite struct {
|
|
suite.Suite
|
|
|
|
cfg network.Config
|
|
network *network.Network
|
|
}
|
|
|
|
func (s *IntegrationTestSuite) SetupSuite() {
|
|
s.T().Log("setting up integration test suite")
|
|
|
|
cfg := network.DefaultConfig()
|
|
cfg.NumValidators = 1
|
|
|
|
s.cfg = cfg
|
|
s.network = network.New(s.T(), cfg)
|
|
|
|
kb := s.network.Validators[0].ClientCtx.Keyring
|
|
_, _, err := kb.NewMnemonic("newAccount", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
|
|
s.Require().NoError(err)
|
|
|
|
account1, _, err := kb.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
|
|
s.Require().NoError(err)
|
|
|
|
account2, _, err := kb.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
|
|
s.Require().NoError(err)
|
|
|
|
multi := multisig.NewPubKeyMultisigThreshold(2, []tmcrypto.PubKey{account1.GetPubKey(), account2.GetPubKey()})
|
|
_, err = kb.SaveMultisig("multi", multi)
|
|
s.Require().NoError(err)
|
|
|
|
_, err = s.network.WaitForHeight(1)
|
|
s.Require().NoError(err)
|
|
}
|
|
|
|
func (s *IntegrationTestSuite) TearDownSuite() {
|
|
s.T().Log("tearing down integration test suite")
|
|
s.network.Cleanup()
|
|
}
|
|
|
|
func (s *IntegrationTestSuite) TestCLIValidateSignatures() {
|
|
val := s.network.Validators[0]
|
|
res, err := bankcli.MsgSendExec(
|
|
val.ClientCtx,
|
|
val.Address,
|
|
val.Address,
|
|
sdk.NewCoins(
|
|
sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)),
|
|
sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)),
|
|
),
|
|
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
|
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
|
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
|
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
// write unsigned tx to file
|
|
unsignedTx, cleanup := testutil.WriteToNewTempFile(s.T(), res.String())
|
|
defer cleanup()
|
|
|
|
res, err = authtest.TxSignExec(val.ClientCtx, val.Address, unsignedTx.Name())
|
|
s.Require().NoError(err)
|
|
signedTx, err := val.ClientCtx.TxConfig.TxJSONDecoder()(res.Bytes())
|
|
s.Require().NoError(err)
|
|
|
|
signedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), res.String())
|
|
defer cleanup()
|
|
txBuilder, err := val.ClientCtx.TxConfig.WrapTxBuilder(signedTx)
|
|
res, err = authtest.TxValidateSignaturesExec(val.ClientCtx, signedTxFile.Name())
|
|
s.Require().NoError(err)
|
|
|
|
txBuilder.SetMemo("MODIFIED TX")
|
|
bz, err := val.ClientCtx.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
|
|
s.Require().NoError(err)
|
|
|
|
modifiedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), string(bz))
|
|
defer cleanup()
|
|
|
|
res, err = authtest.TxValidateSignaturesExec(val.ClientCtx, modifiedTxFile.Name())
|
|
s.Require().EqualError(err, "signatures validation failed")
|
|
}
|
|
|
|
func (s *IntegrationTestSuite) TestCLISignBatch() {
|
|
val := s.network.Validators[0]
|
|
generatedStd, err := bankcli.MsgSendExec(
|
|
val.ClientCtx,
|
|
val.Address,
|
|
val.Address,
|
|
sdk.NewCoins(
|
|
sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)),
|
|
sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)),
|
|
),
|
|
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
|
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
|
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
|
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
// Write the output to disk
|
|
filename, cleanup1 := testutil.WriteToNewTempFile(s.T(), strings.Repeat(generatedStd.String(), 3))
|
|
defer cleanup1()
|
|
|
|
// sign-batch file - offline is set but account-number and sequence are not
|
|
val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1)
|
|
res, err := authtest.TxSignBatchExec(val.ClientCtx, val.Address, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--offline")
|
|
s.Require().EqualError(err, "required flag(s) \"account-number\", \"sequence\" not set")
|
|
|
|
// sign-batch file
|
|
res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID))
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
|
|
|
|
// sign-batch file
|
|
res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only")
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
|
|
|
|
// Sign batch malformed tx file.
|
|
malformedFile, cleanup2 := testutil.WriteToNewTempFile(s.T(), fmt.Sprintf("%smalformed", generatedStd))
|
|
defer cleanup2()
|
|
|
|
res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID))
|
|
s.Require().Error(err)
|
|
|
|
// Sign batch malformed tx file signature only.
|
|
res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only")
|
|
s.Require().Error(err)
|
|
}
|
|
|
|
func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
|
|
val1 := s.network.Validators[0]
|
|
|
|
account, err := val1.ClientCtx.Keyring.Key("newAccount")
|
|
s.Require().NoError(err)
|
|
|
|
sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10))
|
|
|
|
normalGeneratedTx, err := bankcli.MsgSendExec(
|
|
val1.ClientCtx,
|
|
val1.Address,
|
|
account.GetAddress(),
|
|
sdk.NewCoins(sendTokens),
|
|
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
|
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
|
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
|
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
txCfg := val1.ClientCtx.TxConfig
|
|
|
|
normalGeneratedStdTx, err := txCfg.TxJSONDecoder()(normalGeneratedTx.Bytes())
|
|
s.Require().NoError(err)
|
|
txBuilder, err := txCfg.WrapTxBuilder(normalGeneratedStdTx)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(txBuilder.GetTx().GetGas(), uint64(flags.DefaultGasLimit))
|
|
s.Require().Equal(len(txBuilder.GetTx().GetMsgs()), 1)
|
|
s.Require().Equal(0, len(txBuilder.GetTx().GetSignatures()))
|
|
|
|
// Test generate sendTx with --gas=$amount
|
|
limitedGasGeneratedTx, err := bankcli.MsgSendExec(
|
|
val1.ClientCtx,
|
|
val1.Address,
|
|
account.GetAddress(),
|
|
sdk.NewCoins(sendTokens),
|
|
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
|
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
|
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
|
fmt.Sprintf("--gas=%d", 100),
|
|
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
limitedGasStdTx, err := txCfg.TxJSONDecoder()(limitedGasGeneratedTx.Bytes())
|
|
s.Require().NoError(err)
|
|
txBuilder, err = txCfg.WrapTxBuilder(limitedGasStdTx)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(txBuilder.GetTx().GetGas(), uint64(100))
|
|
s.Require().Equal(len(txBuilder.GetTx().GetMsgs()), 1)
|
|
s.Require().Equal(0, len(txBuilder.GetTx().GetSignatures()))
|
|
|
|
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx.WithOutputFormat("json"), val1.Address)
|
|
s.Require().NoError(err)
|
|
|
|
var coins sdk.Coins
|
|
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
|
|
s.Require().NoError(err)
|
|
startTokens := coins.AmountOf(s.cfg.BondDenom)
|
|
|
|
// Test generate sendTx, estimate gas
|
|
finalGeneratedTx, err := bankcli.MsgSendExec(
|
|
val1.ClientCtx,
|
|
val1.Address,
|
|
account.GetAddress(),
|
|
sdk.NewCoins(sendTokens),
|
|
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
|
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
|
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
|
fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
|
|
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
finalStdTx, err := txCfg.TxJSONDecoder()(finalGeneratedTx.Bytes())
|
|
s.Require().NoError(err)
|
|
txBuilder, err = txCfg.WrapTxBuilder(finalStdTx)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(uint64(flags.DefaultGasLimit), txBuilder.GetTx().GetGas())
|
|
s.Require().Equal(len(finalStdTx.GetMsgs()), 1)
|
|
|
|
// Write the output to disk
|
|
unsignedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), finalGeneratedTx.String())
|
|
defer cleanup()
|
|
|
|
// Test validate-signatures
|
|
res, err := authtest.TxValidateSignaturesExec(val1.ClientCtx, unsignedTxFile.Name())
|
|
s.Require().EqualError(err, "signatures validation failed")
|
|
s.Require().True(strings.Contains(res.String(), fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n\n", val1.Address.String())))
|
|
|
|
// Test sign
|
|
|
|
// Does not work in offline mode
|
|
res, err = authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name(), "--offline")
|
|
s.Require().EqualError(err, "required flag(s) \"account-number\", \"sequence\" not set")
|
|
|
|
// But works offline if we set account number and sequence
|
|
val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1)
|
|
res, err = authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name(), "--offline", "--account-number", "1", "--sequence", "1")
|
|
s.Require().NoError(err)
|
|
|
|
// Sign transaction
|
|
signedTx, err := authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name())
|
|
s.Require().NoError(err)
|
|
signedFinalTx, err := txCfg.TxJSONDecoder()(signedTx.Bytes())
|
|
s.Require().NoError(err)
|
|
txBuilder, err = val1.ClientCtx.TxConfig.WrapTxBuilder(signedFinalTx)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(len(txBuilder.GetTx().GetMsgs()), 1)
|
|
s.Require().Equal(1, len(txBuilder.GetTx().GetSignatures()))
|
|
s.Require().Equal(val1.Address.String(), txBuilder.GetTx().GetSigners()[0].String())
|
|
|
|
// Write the output to disk
|
|
signedTxFile, cleanup2 := testutil.WriteToNewTempFile(s.T(), signedTx.String())
|
|
defer cleanup2()
|
|
|
|
// Validate Signature
|
|
res, err = authtest.TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name())
|
|
s.Require().NoError(err)
|
|
s.Require().True(strings.Contains(res.String(), "[OK]"))
|
|
|
|
// Ensure foo has right amount of funds
|
|
resp, err = bankcli.QueryBalancesExec(val1.ClientCtx.WithOutputFormat("json"), val1.Address)
|
|
s.Require().NoError(err)
|
|
|
|
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(startTokens, coins.AmountOf(s.cfg.BondDenom))
|
|
|
|
// Test broadcast
|
|
|
|
// Does not work in offline mode
|
|
res, err = authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name(), "--offline")
|
|
s.Require().EqualError(err, "cannot broadcast tx during offline mode")
|
|
|
|
s.Require().NoError(s.network.WaitForNextBlock())
|
|
|
|
// Broadcast correct transaction.
|
|
val1.ClientCtx.BroadcastMode = flags.BroadcastBlock
|
|
res, err = authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name())
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NoError(s.network.WaitForNextBlock())
|
|
|
|
// Ensure destiny account state
|
|
resp, err = bankcli.QueryBalancesExec(val1.ClientCtx.WithOutputFormat("json"), account.GetAddress())
|
|
s.Require().NoError(err)
|
|
|
|
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(sendTokens.Amount, coins.AmountOf(s.cfg.BondDenom))
|
|
|
|
// Ensure origin account state
|
|
resp, err = bankcli.QueryBalancesExec(val1.ClientCtx.WithOutputFormat("json"), val1.Address)
|
|
s.Require().NoError(err)
|
|
|
|
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
|
|
s.Require().NoError(err)
|
|
}
|
|
|
|
func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
|
|
val1 := s.network.Validators[0]
|
|
|
|
codec := codec2.New()
|
|
sdk.RegisterCodec(codec)
|
|
banktypes.RegisterCodec(codec)
|
|
val1.ClientCtx.Codec = codec
|
|
|
|
// Generate 2 accounts and a multisig.
|
|
account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
|
|
s.Require().NoError(err)
|
|
|
|
multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
|
|
s.Require().NoError(err)
|
|
|
|
// Send coins from validator to multisig.
|
|
_, err = bankcli.MsgSendExec(
|
|
val1.ClientCtx,
|
|
val1.Address,
|
|
multisigInfo.GetAddress(),
|
|
sdk.NewCoins(
|
|
sdk.NewInt64Coin(s.cfg.BondDenom, 10),
|
|
),
|
|
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
|
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
|
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
|
fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NoError(s.network.WaitForNextBlock())
|
|
|
|
// Generate multisig transaction.
|
|
multiGeneratedTx, err := bankcli.MsgSendExec(
|
|
val1.ClientCtx,
|
|
multisigInfo.GetAddress(),
|
|
val1.Address,
|
|
sdk.NewCoins(
|
|
sdk.NewInt64Coin(s.cfg.BondDenom, 5),
|
|
),
|
|
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
|
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
|
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
|
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
// Save tx to file
|
|
multiGeneratedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String())
|
|
defer cleanup()
|
|
|
|
// Multisign, sign with one signature
|
|
val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1)
|
|
account1Signature, err := authtest.TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
|
|
s.Require().NoError(err)
|
|
|
|
sign1File, cleanup2 := testutil.WriteToNewTempFile(s.T(), account1Signature.String())
|
|
defer cleanup2()
|
|
|
|
multiSigWith1Signature, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name())
|
|
s.Require().NoError(err)
|
|
|
|
// Save tx to file
|
|
multiSigWith1SignatureFile, cleanup3 := testutil.WriteToNewTempFile(s.T(), multiSigWith1Signature.String())
|
|
defer cleanup3()
|
|
|
|
exec, err := authtest.TxValidateSignaturesExec(val1.ClientCtx, multiSigWith1SignatureFile.Name())
|
|
s.Require().Error(err)
|
|
|
|
fmt.Printf("%s", exec)
|
|
}
|
|
|
|
func (s *IntegrationTestSuite) TestCLIEncode() {
|
|
val1 := s.network.Validators[0]
|
|
|
|
sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10))
|
|
|
|
normalGeneratedTx, err := bankcli.MsgSendExec(
|
|
val1.ClientCtx,
|
|
val1.Address,
|
|
val1.Address,
|
|
sdk.NewCoins(sendTokens),
|
|
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
|
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
|
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
|
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), "--memo", "deadbeef",
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
// Save tx to file
|
|
savedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String())
|
|
defer cleanup()
|
|
|
|
// Encode
|
|
encodeExec, err := authtest.TxEncodeExec(val1.ClientCtx, savedTxFile.Name())
|
|
s.Require().NoError(err)
|
|
|
|
trimmedBase64 := strings.Trim(encodeExec.String(), "\"\n")
|
|
// Check that the transaction decodes as expected
|
|
|
|
decodedTx, err := authtest.TxDecodeExec(val1.ClientCtx, trimmedBase64)
|
|
s.Require().NoError(err)
|
|
|
|
txCfg := val1.ClientCtx.TxConfig
|
|
theTx, err := txCfg.TxJSONDecoder()(decodedTx.Bytes())
|
|
s.Require().NoError(err)
|
|
txBuilder, err := val1.ClientCtx.TxConfig.WrapTxBuilder(theTx)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal("deadbeef", txBuilder.GetTx().GetMemo())
|
|
}
|
|
|
|
func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
|
|
val1 := s.network.Validators[0]
|
|
|
|
codec := codec2.New()
|
|
sdk.RegisterCodec(codec)
|
|
banktypes.RegisterCodec(codec)
|
|
val1.ClientCtx.Codec = codec
|
|
|
|
// Generate 2 accounts and a multisig.
|
|
account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
|
|
s.Require().NoError(err)
|
|
|
|
account2, err := val1.ClientCtx.Keyring.Key("newAccount2")
|
|
s.Require().NoError(err)
|
|
|
|
multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
|
|
s.Require().NoError(err)
|
|
|
|
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx.WithOutputFormat("json"), multisigInfo.GetAddress())
|
|
s.Require().NoError(err)
|
|
|
|
var coins sdk.Coins
|
|
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
|
|
s.Require().NoError(err)
|
|
intialCoins := coins
|
|
|
|
// Send coins from validator to multisig.
|
|
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
|
|
_, err = bankcli.MsgSendExec(
|
|
val1.ClientCtx,
|
|
val1.Address,
|
|
multisigInfo.GetAddress(),
|
|
sdk.NewCoins(sendTokens),
|
|
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
|
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
|
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
|
fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NoError(s.network.WaitForNextBlock())
|
|
|
|
resp, err = bankcli.QueryBalancesExec(val1.ClientCtx.WithOutputFormat("json"), multisigInfo.GetAddress())
|
|
s.Require().NoError(err)
|
|
|
|
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
|
|
s.Require().NoError(err)
|
|
diff, _ := coins.SafeSub(intialCoins)
|
|
s.Require().Equal(sendTokens.Amount, diff.AmountOf(s.cfg.BondDenom))
|
|
|
|
// Generate multisig transaction.
|
|
multiGeneratedTx, err := bankcli.MsgSendExec(
|
|
val1.ClientCtx,
|
|
multisigInfo.GetAddress(),
|
|
val1.Address,
|
|
sdk.NewCoins(
|
|
sdk.NewInt64Coin(s.cfg.BondDenom, 5),
|
|
),
|
|
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
|
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
|
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
|
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
// Save tx to file
|
|
multiGeneratedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String())
|
|
defer cleanup()
|
|
|
|
// Sign with account1
|
|
val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1)
|
|
account1Signature, err := authtest.TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
|
|
s.Require().NoError(err)
|
|
|
|
sign1File, cleanup2 := testutil.WriteToNewTempFile(s.T(), account1Signature.String())
|
|
defer cleanup2()
|
|
|
|
// Sign with account1
|
|
account2Signature, err := authtest.TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
|
|
s.Require().NoError(err)
|
|
|
|
sign2File, cleanup3 := testutil.WriteToNewTempFile(s.T(), account2Signature.String())
|
|
defer cleanup3()
|
|
|
|
multiSigWith2Signatures, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name())
|
|
s.Require().NoError(err)
|
|
|
|
// Write the output to disk
|
|
signedTxFile, cleanup4 := testutil.WriteToNewTempFile(s.T(), multiSigWith2Signatures.String())
|
|
defer cleanup4()
|
|
|
|
_, err = authtest.TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name())
|
|
s.Require().NoError(err)
|
|
|
|
val1.ClientCtx.BroadcastMode = flags.BroadcastBlock
|
|
_, err = authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name())
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NoError(s.network.WaitForNextBlock())
|
|
}
|
|
|
|
func (s *IntegrationTestSuite) TestCLIMultisign() {
|
|
val1 := s.network.Validators[0]
|
|
|
|
codec := codec2.New()
|
|
sdk.RegisterCodec(codec)
|
|
banktypes.RegisterCodec(codec)
|
|
val1.ClientCtx.Codec = codec
|
|
|
|
// Generate 2 accounts and a multisig.
|
|
account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
|
|
s.Require().NoError(err)
|
|
|
|
account2, err := val1.ClientCtx.Keyring.Key("newAccount2")
|
|
s.Require().NoError(err)
|
|
|
|
multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
|
|
s.Require().NoError(err)
|
|
|
|
// Send coins from validator to multisig.
|
|
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
|
|
_, err = bankcli.MsgSendExec(
|
|
val1.ClientCtx,
|
|
val1.Address,
|
|
multisigInfo.GetAddress(),
|
|
sdk.NewCoins(sendTokens),
|
|
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
|
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
|
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
|
fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
|
|
)
|
|
|
|
s.Require().NoError(s.network.WaitForNextBlock())
|
|
|
|
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx.WithOutputFormat("json"), multisigInfo.GetAddress())
|
|
s.Require().NoError(err)
|
|
|
|
var coins sdk.Coins
|
|
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(sendTokens.Amount, coins.AmountOf(s.cfg.BondDenom))
|
|
|
|
// Generate multisig transaction.
|
|
multiGeneratedTx, err := bankcli.MsgSendExec(
|
|
val1.ClientCtx,
|
|
multisigInfo.GetAddress(),
|
|
val1.Address,
|
|
sdk.NewCoins(
|
|
sdk.NewInt64Coin(s.cfg.BondDenom, 5),
|
|
),
|
|
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
|
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
|
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
|
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
// Save tx to file
|
|
multiGeneratedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String())
|
|
defer cleanup()
|
|
|
|
// Sign with account1
|
|
val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1)
|
|
account1Signature, err := authtest.TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
|
|
s.Require().NoError(err)
|
|
|
|
sign1File, cleanup2 := testutil.WriteToNewTempFile(s.T(), account1Signature.String())
|
|
defer cleanup2()
|
|
|
|
// Sign with account1
|
|
account2Signature, err := authtest.TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
|
|
s.Require().NoError(err)
|
|
|
|
sign2File, cleanup3 := testutil.WriteToNewTempFile(s.T(), account2Signature.String())
|
|
defer cleanup3()
|
|
|
|
// Does not work in offline mode.
|
|
_, err = authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), "--offline", sign1File.Name(), sign2File.Name())
|
|
s.Require().EqualError(err, "couldn't verify signature")
|
|
|
|
val1.ClientCtx.Offline = false
|
|
multiSigWith2Signatures, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name())
|
|
s.Require().NoError(err)
|
|
|
|
// Write the output to disk
|
|
signedTxFile, cleanup4 := testutil.WriteToNewTempFile(s.T(), multiSigWith2Signatures.String())
|
|
defer cleanup4()
|
|
|
|
_, err = authtest.TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name())
|
|
s.Require().NoError(err)
|
|
|
|
val1.ClientCtx.BroadcastMode = flags.BroadcastBlock
|
|
_, err = authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name())
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NoError(s.network.WaitForNextBlock())
|
|
}
|
|
|
|
func TestGetBroadcastCommand_OfflineFlag(t *testing.T) {
|
|
clientCtx := client.Context{}.WithOffline(true)
|
|
clientCtx = clientCtx.WithTxConfig(simapp.MakeEncodingConfig().TxConfig)
|
|
|
|
cmd := authcli.GetBroadcastCommand()
|
|
_ = testutil.ApplyMockIODiscardOutErr(cmd)
|
|
cmd.SetArgs([]string{fmt.Sprintf("--%s=true", flags.FlagOffline), ""})
|
|
|
|
require.EqualError(t, cmd.Execute(), "cannot broadcast tx during offline mode")
|
|
}
|
|
|
|
func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) {
|
|
clientCtx := client.Context{}
|
|
txCfg := simapp.MakeEncodingConfig().TxConfig
|
|
clientCtx = clientCtx.WithTxConfig(txCfg)
|
|
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
|
|
|
|
cmd := authcli.GetBroadcastCommand()
|
|
_, out := testutil.ApplyMockIO(cmd)
|
|
|
|
testDir, cleanFunc := testutil.NewTestCaseDir(t)
|
|
t.Cleanup(cleanFunc)
|
|
|
|
// Create new file with tx
|
|
builder := txCfg.NewTxBuilder()
|
|
builder.SetGasLimit(200000)
|
|
from, err := sdk.AccAddressFromBech32("cosmos1cxlt8kznps92fwu3j6npahx4mjfutydyene2qw")
|
|
require.NoError(t, err)
|
|
to, err := sdk.AccAddressFromBech32("cosmos1cxlt8kznps92fwu3j6npahx4mjfutydyene2qw")
|
|
require.NoError(t, err)
|
|
err = builder.SetMsgs(banktypes.NewMsgSend(from, to, sdk.Coins{sdk.NewInt64Coin("stake", 10000)}))
|
|
require.NoError(t, err)
|
|
txContents, err := txCfg.TxJSONEncoder()(builder.GetTx())
|
|
txFileName := filepath.Join(testDir, "tx.json")
|
|
err = ioutil.WriteFile(txFileName, txContents, 0644)
|
|
require.NoError(t, err)
|
|
|
|
cmd.SetArgs([]string{txFileName})
|
|
require.Error(t, cmd.ExecuteContext(ctx))
|
|
require.Contains(t, out.String(), "unsupported return type ; supported types: sync, async, block")
|
|
}
|
|
|
|
func TestIntegrationTestSuite(t *testing.T) {
|
|
suite.Run(t, new(IntegrationTestSuite))
|
|
}
|