Update auth cli commands (#6717)

* add utils

* update sign cmd

* update multisign cmd

* update sign batch cmd

* update genutil cmd

* add wrap tx builder

* update gentx cli

* update validate sigs cmd

* fix lint

* add flag reader to cli

* update marshaler for batchscan

* add register query server

* update to master

* remove depricated methods

* fix keyring issue

* update wraptx

* Fix batch scan

* fix register interfaces issue

* update printOutput

* Update Validate Sigs test

* WIP on signature JSON

* Cleanup

* Cleanup

* Test fixes

* Test fixes

* Fixes

* WIP on tests

* Fix gov tests

* fix lint

* fix MultiSign tests

* fix tests

* refactor tests

* Cleanup

* Address review comments

* Update encode

* Test fix

* Rename SignData func

* Fix lint

* Fix lint

* Revert ReadTxCommandFlags

Co-authored-by: Aaron Craelius <aaron@regen.network>
Co-authored-by: Aaron Craelius <aaronc@users.noreply.github.com>
This commit is contained in:
SaReN
2020-07-29 22:33:42 +00:00
committed by GitHub
co-authored by Aaron Craelius Aaron Craelius
parent cf078c0c88
commit 72ebafeeca
31 changed files with 1985 additions and 536 deletions
+111 -94
View File
@@ -14,19 +14,16 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
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"
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
"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"
"github.com/cosmos/cosmos-sdk/x/auth/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
@@ -47,7 +44,21 @@ func (s *IntegrationTestSuite) SetupSuite() {
s.cfg = cfg
s.network = network.New(s.T(), cfg)
_, err := s.network.WaitForHeight(1)
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)
}
@@ -73,29 +84,23 @@ func (s *IntegrationTestSuite) TestCLIValidateSignatures() {
)
s.Require().NoError(err)
var tx types.StdTx
err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res.Bytes(), &tx)
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)
var signedTx types.StdTx
err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res.Bytes(), &signedTx)
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)
signedTx.Memo = "MODIFIED STD TX"
bz, err := val.ClientCtx.JSONMarshaler.MarshalJSON(signedTx)
txBuilder.SetMemo("MODIFIED TX")
bz, err := val.ClientCtx.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
s.Require().NoError(err)
modifiedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), string(bz))
@@ -147,28 +152,26 @@ func (s *IntegrationTestSuite) TestCLISignBatch() {
defer cleanup2()
res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID))
s.Require().EqualError(err, "cannot parse disfix JSON wrapper: invalid character 'm' looking for beginning of value")
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().EqualError(err, "cannot parse disfix JSON wrapper: invalid character 'm' looking for beginning of value")
s.Require().Error(err)
}
func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
val1 := s.network.Validators[0]
account, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
account, err := val1.ClientCtx.Keyring.Key("newAccount")
s.Require().NoError(err)
sendTokens := sdk.TokensFromConsensusPower(10)
sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10))
normalGeneratedTx, err := bankcli.MsgSendExec(
val1.ClientCtx,
val1.Address,
account.GetAddress(),
sdk.NewCoins(
sdk.NewCoin(s.cfg.BondDenom, sendTokens),
),
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()),
@@ -176,19 +179,22 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
)
s.Require().NoError(err)
normalGeneratedStdTx := unmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, normalGeneratedTx.String())
s.Require().Equal(normalGeneratedStdTx.Fee.Gas, uint64(flags.DefaultGasLimit))
s.Require().Equal(len(normalGeneratedStdTx.Msgs), 1)
s.Require().Equal(0, len(normalGeneratedStdTx.GetSignatures()))
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(
sdk.NewCoin(s.cfg.BondDenom, sendTokens),
),
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()),
@@ -197,19 +203,28 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
)
s.Require().NoError(err)
limitedGasStdTx := unmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, limitedGasGeneratedTx.String())
s.Require().Equal(limitedGasStdTx.Fee.Gas, uint64(100))
s.Require().Equal(len(limitedGasStdTx.Msgs), 1)
s.Require().Equal(0, len(limitedGasStdTx.GetSignatures()))
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, 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(
sdk.NewCoin(s.cfg.BondDenom, sendTokens),
),
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()),
@@ -218,9 +233,12 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
)
s.Require().NoError(err)
finalStdTx := unmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, finalGeneratedTx.String())
s.Require().Equal(uint64(flags.DefaultGasLimit), finalStdTx.Fee.Gas)
s.Require().Equal(len(finalStdTx.Msgs), 1)
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())
@@ -245,11 +263,13 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
// Sign transaction
signedTx, err := authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name())
s.Require().NoError(err)
signedFinalTx := unmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, signedTx.String())
s.Require().Equal(len(signedFinalTx.Msgs), 1)
s.Require().Equal(1, len(signedFinalTx.GetSignatures()))
s.Require().Equal(val1.Address.String(), signedFinalTx.GetSigners()[0].String())
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())
@@ -261,11 +281,9 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
s.Require().True(strings.Contains(res.String(), "[OK]"))
// Ensure foo has right amount of funds
startTokens := sdk.TokensFromConsensusPower(400)
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address)
resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address)
s.Require().NoError(err)
var coins sdk.Coins
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
s.Require().NoError(err)
s.Require().Equal(startTokens, coins.AmountOf(s.cfg.BondDenom))
@@ -291,7 +309,7 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
s.Require().NoError(err)
s.Require().Equal(sendTokens, coins.AmountOf(s.cfg.BondDenom))
s.Require().Equal(sendTokens.Amount, coins.AmountOf(s.cfg.BondDenom))
// Ensure origin account state
resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address)
@@ -299,11 +317,9 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
s.Require().NoError(err)
s.Require().Equal(sdk.NewInt(389999990), coins.AmountOf(s.cfg.BondDenom))
}
func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
s.T().SkipNow() // TODO check encoding.
val1 := s.network.Validators[0]
codec := codec2.New()
@@ -312,14 +328,10 @@ func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
val1.ClientCtx.Codec = codec
// Generate 2 accounts and a multisig.
account1, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
s.Require().NoError(err)
account2, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
s.Require().NoError(err)
multi := multisig.NewPubKeyMultisigThreshold(2, []tmcrypto.PubKey{account1.GetPubKey(), account2.GetPubKey()})
multisigInfo, err := val1.ClientCtx.Keyring.SaveMultisig("multi", multi)
multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
s.Require().NoError(err)
// Send coins from validator to multisig.
@@ -374,7 +386,7 @@ func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
defer cleanup3()
exec, err := authtest.TxValidateSignaturesExec(val1.ClientCtx, multiSigWith1SignatureFile.Name())
s.Require().NoError(err)
s.Require().Error(err)
fmt.Printf("%s", exec)
}
@@ -382,15 +394,13 @@ func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
func (s *IntegrationTestSuite) TestCLIEncode() {
val1 := s.network.Validators[0]
sendTokens := sdk.TokensFromConsensusPower(10)
sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10))
normalGeneratedTx, err := bankcli.MsgSendExec(
val1.ClientCtx,
val1.Address,
val1.Address,
sdk.NewCoins(
sdk.NewCoin(s.cfg.BondDenom, sendTokens),
),
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()),
@@ -402,7 +412,7 @@ func (s *IntegrationTestSuite) TestCLIEncode() {
savedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String())
defer cleanup()
// Enconde
// Encode
encodeExec, err := authtest.TxEncodeExec(val1.ClientCtx, savedTxFile.Name())
s.Require().NoError(err)
@@ -412,12 +422,15 @@ func (s *IntegrationTestSuite) TestCLIEncode() {
decodedTx, err := authtest.TxDecodeExec(val1.ClientCtx, trimmedBase64)
s.Require().NoError(err)
theTx := unmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, decodedTx.String())
s.Require().Equal("deadbeef", theTx.Memo)
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() {
s.T().SkipNow()
val1 := s.network.Validators[0]
codec := codec2.New()
@@ -426,25 +439,30 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
val1.ClientCtx.Codec = codec
// Generate 2 accounts and a multisig.
account1, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
s.Require().NoError(err)
account2, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
account2, err := val1.ClientCtx.Keyring.Key("newAccount2")
s.Require().NoError(err)
multi := multisig.NewPubKeyMultisigThreshold(2, []tmcrypto.PubKey{account1.GetPubKey(), account2.GetPubKey()})
multisigInfo, err := val1.ClientCtx.Keyring.SaveMultisig("multi", multi)
multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
s.Require().NoError(err)
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, 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,
),
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()),
@@ -454,13 +472,13 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
s.Require().NoError(s.network.WaitForNextBlock())
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress())
resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, 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))
diff, _ := coins.SafeSub(intialCoins)
s.Require().Equal(sendTokens.Amount, diff.AmountOf(s.cfg.BondDenom))
// Generate multisig transaction.
multiGeneratedTx, err := bankcli.MsgSendExec(
@@ -514,7 +532,6 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
}
func (s *IntegrationTestSuite) TestCLIMultisign() {
s.T().SkipNow()
val1 := s.network.Validators[0]
codec := codec2.New()
@@ -523,14 +540,13 @@ func (s *IntegrationTestSuite) TestCLIMultisign() {
val1.ClientCtx.Codec = codec
// Generate 2 accounts and a multisig.
account1, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
s.Require().NoError(err)
account2, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
account2, err := val1.ClientCtx.Keyring.Key("newAccount2")
s.Require().NoError(err)
multi := multisig.NewPubKeyMultisigThreshold(2, []tmcrypto.PubKey{account1.GetPubKey(), account2.GetPubKey()})
multisigInfo, err := val1.ClientCtx.Keyring.SaveMultisig("multi", multi)
multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
s.Require().NoError(err)
// Send coins from validator to multisig.
@@ -539,9 +555,7 @@ func (s *IntegrationTestSuite) TestCLIMultisign() {
val1.ClientCtx,
val1.Address,
multisigInfo.GetAddress(),
sdk.NewCoins(
sendTokens,
),
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()),
@@ -593,8 +607,7 @@ func (s *IntegrationTestSuite) TestCLIMultisign() {
defer cleanup3()
// Does not work in offline mode.
val1.ClientCtx.Offline = true
_, err = authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name())
_, 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
@@ -617,7 +630,7 @@ func (s *IntegrationTestSuite) TestCLIMultisign() {
func TestGetBroadcastCommand_OfflineFlag(t *testing.T) {
clientCtx := client.Context{}.WithOffline(true)
clientCtx = clientCtx.WithTxConfig(simappparams.MakeEncodingConfig().TxConfig)
clientCtx = clientCtx.WithTxConfig(simapp.MakeEncodingConfig().TxConfig)
cmd := authcli.GetBroadcastCommand()
_ = testutil.ApplyMockIODiscardOutErr(cmd)
@@ -628,7 +641,8 @@ func TestGetBroadcastCommand_OfflineFlag(t *testing.T) {
func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) {
clientCtx := client.Context{}
clientCtx = clientCtx.WithTxConfig(simappparams.MakeEncodingConfig().TxConfig)
txCfg := simapp.MakeEncodingConfig().TxConfig
clientCtx = clientCtx.WithTxConfig(txCfg)
ctx := context.Background()
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
@@ -639,9 +653,17 @@ func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) {
t.Cleanup(cleanFunc)
// Create new file with tx
txContents := []byte("{\"type\":\"cosmos-sdk/StdTx\",\"value\":{\"msg\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"from_address\":\"cosmos1cxlt8kznps92fwu3j6npahx4mjfutydyene2qw\",\"to_address\":\"cosmos1wc8mpr8m3sy3ap3j7fsgqfzx36um05pystems4\",\"amount\":[{\"denom\":\"stake\",\"amount\":\"10000\"}]}}],\"fee\":{\"amount\":[],\"gas\":\"200000\"},\"signatures\":null,\"memo\":\"\"}}")
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)
err = ioutil.WriteFile(txFileName, txContents, 0644)
require.NoError(t, err)
cmd.SetArgs([]string{txFileName})
@@ -654,8 +676,3 @@ func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) {
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}
func unmarshalStdTx(t require.TestingT, c codec.JSONMarshaler, s string) (stdTx authtypes.StdTx) {
require.Nil(t, c.UnmarshalJSON([]byte(s), &stdTx))
return stdTx
}
+7 -1
View File
@@ -3,6 +3,7 @@ package cli
import (
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/spf13/cobra"
@@ -37,7 +38,12 @@ func GetDecodeCommand() *cobra.Command {
return err
}
return clientCtx.PrintOutput(tx)
json, err := clientCtx.TxConfig.TxJSONEncoder()(tx)
if err != nil {
return err
}
return clientCtx.PrintString(fmt.Sprintf("%s\n", json))
},
}
+2 -9
View File
@@ -2,6 +2,7 @@ package cli
import (
"encoding/base64"
"fmt"
"github.com/spf13/cobra"
@@ -10,13 +11,6 @@ import (
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
)
// txEncodeRespStr implements a simple Stringer wrapper for a encoded tx.
type txEncodeRespStr string
func (txr txEncodeRespStr) String() string {
return string(txr)
}
// GetEncodeCommand returns the encode command to take a JSONified transaction and turn it into
// Amino-serialized bytes
func GetEncodeCommand() *cobra.Command {
@@ -44,8 +38,7 @@ If you supply a dash (-) argument in place of an input filename, the command rea
// base64 encode the encoded tx bytes
txBytesBase64 := base64.StdEncoding.EncodeToString(txBytes)
response := txEncodeRespStr(txBytesBase64)
return clientCtx.PrintOutput(response)
return clientCtx.PrintString(fmt.Sprintf("%s\n", txBytesBase64))
},
}
+14 -10
View File
@@ -23,15 +23,17 @@ func TestGetCommandEncode(t *testing.T) {
authtypes.RegisterCodec(encodingConfig.Amino)
sdk.RegisterCodec(encodingConfig.Amino)
txGen := encodingConfig.TxConfig
txCfg := encodingConfig.TxConfig
// Build a test transaction
fee := authtypes.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)})
stdTx := authtypes.NewStdTx([]sdk.Msg{}, fee, []authtypes.StdSignature{}, "foomemo")
JSONEncoded, err := txGen.TxJSONEncoder()(stdTx)
builder := txCfg.NewTxBuilder()
builder.SetGasLimit(50000)
builder.SetFeeAmount(sdk.Coins{sdk.NewInt64Coin("atom", 150)})
builder.SetMemo("foomemo")
jsonEncoded, err := txCfg.TxJSONEncoder()(builder.GetTx())
require.NoError(t, err)
txFile, cleanup := testutil.WriteToNewTempFile(t, string(JSONEncoded))
txFile, cleanup := testutil.WriteToNewTempFile(t, string(jsonEncoded))
txFileName := txFile.Name()
t.Cleanup(cleanup)
@@ -58,15 +60,17 @@ func TestGetCommandDecode(t *testing.T) {
sdk.RegisterCodec(encodingConfig.Amino)
txGen := encodingConfig.TxConfig
clientCtx = clientCtx.WithTxConfig(txGen)
txCfg := encodingConfig.TxConfig
clientCtx = clientCtx.WithTxConfig(txCfg)
// Build a test transaction
fee := authtypes.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)})
stdTx := authtypes.NewStdTx([]sdk.Msg{}, fee, []authtypes.StdSignature{}, "foomemo")
builder := txCfg.NewTxBuilder()
builder.SetGasLimit(50000)
builder.SetFeeAmount(sdk.Coins{sdk.NewInt64Coin("atom", 150)})
builder.SetMemo("foomemo")
// Encode transaction
txBytes, err := clientCtx.TxConfig.TxEncoder()(stdTx)
txBytes, err := clientCtx.TxConfig.TxEncoder()(builder.GetTx())
require.NoError(t, err)
// Convert the transaction into base64 encoded string
+44 -43
View File
@@ -11,13 +11,14 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/errors"
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/version"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
@@ -60,13 +61,27 @@ recommended to set such parameters manually.
func makeMultiSignCmd() func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) (err error) {
clientCtx := client.GetClientContextFromCmd(cmd)
cdc := clientCtx.Codec
tx, err := authclient.ReadTxFromFile(clientCtx, args[0])
stdTx := tx.(types.StdTx)
clientCtx, err = client.ReadTxCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}
parsedTx, err := authclient.ReadTxFromFile(clientCtx, args[0])
if err != nil {
return
}
txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())
if txFactory.SignMode() == signingtypes.SignMode_SIGN_MODE_UNSPECIFIED {
txFactory = txFactory.WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
}
txCfg := clientCtx.TxConfig
txBuilder, err := txCfg.WrapTxBuilder(parsedTx)
if err != nil {
return err
}
backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
inBuf := bufio.NewReader(cmd.InOrStdin())
@@ -85,63 +100,53 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) error {
multisigPub := multisigInfo.GetPubKey().(multisig.PubKeyMultisigThreshold)
multisigSig := multisig.NewMultisig(len(multisigPub.PubKeys))
txBldr, err := types.NewTxBuilderFromFlags(inBuf, cmd.Flags(), clientCtx.HomeDir)
if err != nil {
return errors.Wrap(err, "error creating tx builder from flags")
}
if !clientCtx.Offline {
accnum, seq, err := types.NewAccountRetriever(clientCtx.JSONMarshaler).GetAccountNumberSequence(clientCtx, multisigInfo.GetAddress())
if err != nil {
return err
}
txBldr = txBldr.WithAccountNumber(accnum).WithSequence(seq)
txFactory = txFactory.WithAccountNumber(accnum).WithSequence(seq)
}
// read each signature and add it to the multisig if valid
for i := 2; i < len(args); i++ {
stdSig, err := readAndUnmarshalStdSignature(cdc, args[i])
sigs, err := unmarshalSignatureJSON(clientCtx, args[i])
if err != nil {
return err
}
// Validate each signature
sigBytes := types.StdSignBytes(
txBldr.ChainID(), txBldr.AccountNumber(), txBldr.Sequence(),
stdTx.Fee, stdTx.GetMsgs(), stdTx.GetMemo(),
)
if ok := stdSig.GetPubKey().VerifyBytes(sigBytes, stdSig.Signature); !ok {
return fmt.Errorf("couldn't verify signature")
signingData := signing.SignerData{
ChainID: txFactory.ChainID(),
AccountNumber: txFactory.AccountNumber(),
AccountSequence: txFactory.Sequence(),
}
sigV2, err := types.StdSignatureToSignatureV2(cdc, stdSig)
if err != nil {
return nil
}
for _, sig := range sigs {
err = signing.VerifySignature(sig.PubKey, signingData, sig.Data, txCfg.SignModeHandler(), txBuilder.GetTx())
if err != nil {
return fmt.Errorf("couldn't verify signature")
}
if err := multisig.AddSignatureV2(multisigSig, sigV2, multisigPub.PubKeys); err != nil {
return err
if err := multisig.AddSignatureV2(multisigSig, sig, multisigPub.PubKeys); err != nil {
return err
}
}
}
sigBz, err := types.SignatureDataToAminoSignature(cdc, multisigSig)
sigV2 := signingtypes.SignatureV2{
PubKey: multisigPub,
Data: multisigSig,
}
err = txBuilder.SetSignatures(sigV2)
if err != nil {
return err
}
newStdSig := types.StdSignature{Signature: sigBz, PubKey: multisigPub.Bytes()} //nolint:staticcheck
newTx := types.NewStdTx(stdTx.GetMsgs(), stdTx.Fee, []types.StdSignature{newStdSig}, stdTx.GetMemo()) //nolint:staticcheck
var json []byte
sigOnly, _ := cmd.Flags().GetBool(flagSigOnly)
if sigOnly {
json, err = cdc.MarshalJSON(newTx.Signatures[0])
} else {
json, err = cdc.MarshalJSON(newTx)
}
json, err := marshalSignatureJSON(txCfg, txBuilder, sigOnly)
if err != nil {
return err
}
@@ -158,18 +163,14 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) error {
}
defer fp.Close()
fmt.Fprintf(fp, "%s\n", json)
return
return clientCtx.PrintString(fmt.Sprintf("%s\n", json))
}
}
func readAndUnmarshalStdSignature(cdc *codec.Codec, filename string) (stdSig types.StdSignature, err error) { //nolint:staticcheck
func unmarshalSignatureJSON(clientCtx client.Context, filename string) (sigs []signingtypes.SignatureV2, err error) {
var bytes []byte
if bytes, err = ioutil.ReadFile(filename); err != nil {
return
}
if err = cdc.UnmarshalJSON(bytes, &stdSig); err != nil {
return
}
return
return clientCtx.TxConfig.UnmarshalSignatureJSON(bytes)
}
+53 -38
View File
@@ -1,7 +1,6 @@
package cli
import (
"bufio"
"fmt"
"os"
@@ -9,10 +8,10 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
const (
@@ -61,12 +60,13 @@ account key. It implies --signature-only.
func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
txBldr, err := types.NewTxBuilderFromFlags(bufio.NewReader(cmd.InOrStdin()), cmd.Flags(), clientCtx.HomeDir)
clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}
txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())
txCfg := clientCtx.TxConfig
generateSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly)
var (
@@ -97,34 +97,34 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
return err
}
}
scanner := authclient.NewBatchScanner(txCfg, infile)
scanner := authclient.NewBatchScanner(clientCtx.JSONMarshaler, infile)
for sequence := txBldr.Sequence(); scanner.Scan(); sequence++ {
var stdTx types.StdTx
unsignedStdTx := scanner.StdTx()
txBldr = txBldr.WithSequence(sequence)
for sequence := txFactory.Sequence(); scanner.Scan(); sequence++ {
unsignedStdTx := scanner.Tx()
txFactory = txFactory.WithSequence(sequence)
txBuilder, err := txCfg.WrapTxBuilder(unsignedStdTx)
if err != nil {
return err
}
if multisigAddr.Empty() {
from, _ := cmd.Flags().GetString(flags.FlagFrom)
_, fromName, err := client.GetFromFields(txBldr.Keybase(), from, clientCtx.GenerateOnly)
_, fromName, err := client.GetFromFields(txFactory.Keybase(), from, clientCtx.GenerateOnly)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
stdTx, err = authclient.SignStdTx(txBldr, clientCtx, fromName, unsignedStdTx, false, true)
err = authclient.SignTx(txFactory, clientCtx, fromName, txBuilder, true)
if err != nil {
return err
}
} else {
stdTx, err = authclient.SignStdTxWithSignerAddress(txBldr, clientCtx, multisigAddr, clientCtx.GetFromName(), unsignedStdTx, true)
if err != nil {
return err
}
err = authclient.SignTxWithSignerAddress(txFactory, clientCtx, multisigAddr, clientCtx.GetFromName(), txBuilder, true)
}
json, err := getSignatureJSON(clientCtx.JSONMarshaler, stdTx, generateSignatureOnly)
if err != nil {
return err
}
json, err := marshalSignatureJSON(txCfg, txBuilder, generateSignatureOnly)
if err != nil {
return err
}
@@ -206,20 +206,31 @@ func preSignCmd(cmd *cobra.Command, _ []string) {
func makeSignCmd() func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}
txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())
clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0])
clientCtx, txF, newTx, err := readTxAndInitContexts(clientCtx, cmd, args[0])
if err != nil {
return err
}
if txF.SignMode() == signing.SignMode_SIGN_MODE_UNSPECIFIED {
txF = txF.WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
}
txCfg := clientCtx.TxConfig
txBuilder, err := txCfg.WrapTxBuilder(newTx)
if err != nil {
return err
}
stdTx := tx.(types.StdTx)
// if --signature-only is on, then override --append
var newTx types.StdTx
generateSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly)
multisigAddrStr, _ := cmd.Flags().GetString(flagMultisig)
from, _ := cmd.Flags().GetString(flags.FlagFrom)
_, fromName, err := client.GetFromFields(txBldr.Keybase(), from, clientCtx.GenerateOnly)
_, fromName, err := client.GetFromFields(txFactory.Keybase(), from, clientCtx.GenerateOnly)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
@@ -232,23 +243,22 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error {
return err
}
newTx, err = authclient.SignStdTxWithSignerAddress(
txBldr, clientCtx, multisigAddr, fromName, stdTx, clientCtx.Offline,
err = authclient.SignTxWithSignerAddress(
txF, clientCtx, multisigAddr, fromName, txBuilder, clientCtx.Offline,
)
generateSignatureOnly = true
} else {
append, _ := cmd.Flags().GetBool(flagAppend)
appendSig := append && !generateSignatureOnly
newTx, err = authclient.SignStdTx(txBldr, clientCtx, fromName, stdTx, appendSig, clientCtx.Offline)
if err != nil {
return err
flagAppend, _ := cmd.Flags().GetBool(flagAppend)
appendSig := flagAppend && !generateSignatureOnly
if appendSig {
err = authclient.SignTx(txF, clientCtx, clientCtx.GetFromName(), txBuilder, clientCtx.Offline)
}
}
if err != nil {
return err
}
json, err := getSignatureJSON(clientCtx.JSONMarshaler, newTx, generateSignatureOnly)
json, err := marshalSignatureJSON(txCfg, txBuilder, generateSignatureOnly)
if err != nil {
return err
}
@@ -265,15 +275,20 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error {
}
defer fp.Close()
fmt.Fprintf(fp, "%s\n", json)
return nil
return clientCtx.PrintString(fmt.Sprintf("%s\n", json))
}
}
func getSignatureJSON(cdc codec.JSONMarshaler, newTx types.StdTx, generateSignatureOnly bool) ([]byte, error) {
func marshalSignatureJSON(txConfig client.TxConfig, txBldr client.TxBuilder, generateSignatureOnly bool) ([]byte, error) {
parsedTx := txBldr.GetTx()
if generateSignatureOnly {
return cdc.MarshalJSON(newTx.Signatures[0])
sigs, err := parsedTx.GetSignaturesV2()
if err != nil {
return nil, err
}
return txConfig.MarshalSignatureJSON(sigs)
}
return cdc.MarshalJSON(newTx)
return txConfig.TxJSONEncoder()(parsedTx)
}
+31 -50
View File
@@ -1,18 +1,16 @@
package cli
import (
"bufio"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
"github.com/cosmos/cosmos-sdk/x/auth/types"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
)
func GetValidateSignaturesCommand() *cobra.Command {
@@ -41,11 +39,15 @@ transaction will be not be performed as that will require RPC communication with
func makeValidateSignaturesCmd() func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0])
clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}
clientCtx, txBldr, stdTx, err := readTxAndInitContexts(clientCtx, cmd, args[0])
if err != nil {
return err
}
stdTx := tx.(types.StdTx)
if !printAndValidateSigs(cmd, clientCtx, txBldr.ChainID(), stdTx, clientCtx.Offline) {
return fmt.Errorf("signatures validation failed")
@@ -59,17 +61,22 @@ func makeValidateSignaturesCmd() func(cmd *cobra.Command, args []string) error {
// expected signers. In addition, if offline has not been supplied, the signature is
// verified over the transaction sign bytes. Returns false if the validation fails.
func printAndValidateSigs(
cmd *cobra.Command, clientCtx client.Context, chainID string, stdTx types.StdTx, offline bool,
cmd *cobra.Command, clientCtx client.Context, chainID string, tx sdk.Tx, offline bool,
) bool {
cmd.Println("Signers:")
signers := stdTx.GetSigners()
sigTx := tx.(authsigning.SigVerifiableTx)
signModeHandler := clientCtx.TxConfig.SignModeHandler()
cmd.Println("Signers:")
signers := sigTx.GetSigners()
for i, signer := range signers {
cmd.Printf(" %v: %v\n", i, signer.String())
}
success := true
sigs := stdTx.Signatures
sigs, err := sigTx.GetSignaturesV2()
if err != nil {
panic(err)
}
cmd.Println("")
cmd.Println("Signatures:")
@@ -79,9 +86,10 @@ func printAndValidateSigs(
for i, sig := range sigs {
var (
pubKey = sig.PubKey
multiSigHeader string
multiSigMsg string
sigAddr = sdk.AccAddress(sig.GetPubKey().Address())
sigAddr = sdk.AccAddress(pubKey.Address())
sigSanity = "OK"
)
@@ -93,40 +101,21 @@ func printAndValidateSigs(
// Validate the actual signature over the transaction bytes since we can
// reach out to a full node to query accounts.
if !offline && success {
acc, err := types.NewAccountRetriever(clientCtx.JSONMarshaler).GetAccount(clientCtx, sigAddr)
accNum, accSeq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, sigAddr)
if err != nil {
cmd.Printf("failed to get account: %s\n", sigAddr)
return false
}
sigBytes := types.StdSignBytes(
chainID, acc.GetAccountNumber(), acc.GetSequence(),
stdTx.Fee, stdTx.GetMsgs(), stdTx.GetMemo(),
)
if ok := sig.GetPubKey().VerifyBytes(sigBytes, sig.Signature); !ok {
sigSanity = "ERROR: signature invalid"
success = false
signingData := authsigning.SignerData{
ChainID: chainID,
AccountNumber: accNum,
AccountSequence: accSeq,
}
}
multiPK, ok := sig.GetPubKey().(multisig.PubKeyMultisigThreshold)
if ok {
var multiSig multisig.AminoMultisignature
clientCtx.Codec.MustUnmarshalBinaryBare(sig.Signature, &multiSig)
var b strings.Builder
b.WriteString("\n MultiSig Signatures:\n")
for i := 0; i < multiSig.BitArray.Count(); i++ {
if multiSig.BitArray.GetIndex(i) {
addr := sdk.AccAddress(multiPK.PubKeys[i].Address().Bytes())
b.WriteString(fmt.Sprintf(" %d: %s (weight: %d)\n", i, addr, 1))
}
err = authsigning.VerifySignature(pubKey, signingData, sig.Data, signModeHandler, sigTx)
if err != nil {
return false
}
multiSigHeader = fmt.Sprintf(" [multisig threshold: %d/%d]", multiPK.K, len(multiPK.PubKeys))
multiSigMsg = b.String()
}
cmd.Printf(" %d: %s\t\t\t[%s]%s%s\n", i, sigAddr.String(), sigSanity, multiSigHeader, multiSigMsg)
@@ -137,21 +126,13 @@ func printAndValidateSigs(
return success
}
func readStdTxAndInitContexts(clientCtx client.Context, cmd *cobra.Command, filename string) (
client.Context, types.TxBuilder, sdk.Tx, error,
) {
func readTxAndInitContexts(clientCtx client.Context, cmd *cobra.Command, filename string) (client.Context, tx.Factory, sdk.Tx, error) {
stdTx, err := authclient.ReadTxFromFile(clientCtx, filename)
if err != nil {
return client.Context{}, types.TxBuilder{}, types.StdTx{}, err
return clientCtx, tx.Factory{}, nil, err
}
inBuf := bufio.NewReader(cmd.InOrStdin())
clientCtx = clientCtx.WithInput(inBuf)
txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())
txBldr, err := types.NewTxBuilderFromFlags(inBuf, cmd.Flags(), clientCtx.HomeDir)
if err != nil {
return client.Context{}, types.TxBuilder{}, types.StdTx{}, err
}
return clientCtx, txBldr, stdTx, nil
return clientCtx, txFactory, stdTx, nil
}
+33 -179
View File
@@ -10,10 +10,9 @@ import (
"strings"
"github.com/gogo/protobuf/jsonpb"
"github.com/pkg/errors"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/input"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -38,81 +37,6 @@ func (gr GasEstimateResponse) String() string {
return fmt.Sprintf("gas estimate: %d", gr.GasEstimate)
}
// GenerateOrBroadcastMsgs creates a StdTx given a series of messages. If
// the provided context has generate-only enabled, the tx will only be printed
// to STDOUT in a fully offline manner. Otherwise, the tx will be signed and
// broadcasted.
func GenerateOrBroadcastMsgs(clientCtx client.Context, txBldr authtypes.TxBuilder, msgs []sdk.Msg) error {
if clientCtx.GenerateOnly {
return PrintUnsignedStdTx(txBldr, clientCtx, msgs)
}
return CompleteAndBroadcastTxCLI(txBldr, clientCtx, msgs)
}
// CompleteAndBroadcastTxCLI implements a utility function that facilitates
// sending a series of messages in a signed transaction given a TxBuilder and a
// QueryContext. It ensures that the account exists, has a proper number and
// sequence set. In addition, it builds and signs a transaction with the
// supplied messages. Finally, it broadcasts the signed transaction to a node.
func CompleteAndBroadcastTxCLI(txBldr authtypes.TxBuilder, clientCtx client.Context, msgs []sdk.Msg) error {
txBldr, err := PrepareTxBuilder(txBldr, clientCtx)
if err != nil {
return err
}
fromName := clientCtx.GetFromName()
if txBldr.SimulateAndExecute() || clientCtx.Simulate {
txBldr, err = EnrichWithGas(txBldr, clientCtx, msgs)
if err != nil {
return err
}
gasEst := GasEstimateResponse{GasEstimate: txBldr.Gas()}
_, _ = fmt.Fprintf(os.Stderr, "%s\n", gasEst.String())
}
if clientCtx.Simulate {
return nil
}
if !clientCtx.SkipConfirm {
stdSignMsg, err := txBldr.BuildSignMsg(msgs)
if err != nil {
return err
}
json, err := clientCtx.JSONMarshaler.MarshalJSON(stdSignMsg)
if err != nil {
return err
}
_, _ = fmt.Fprintf(os.Stderr, "%s\n\n", json)
buf := bufio.NewReader(os.Stdin)
ok, err := input.GetConfirmation("confirm transaction before signing and broadcasting", buf, os.Stderr)
if err != nil || !ok {
_, _ = fmt.Fprintf(os.Stderr, "%s\n", "cancelled transaction")
return err
}
}
// build and sign the transaction
txBytes, err := txBldr.BuildAndSign(fromName, msgs)
if err != nil {
return err
}
// broadcast to a Tendermint node
res, err := clientCtx.BroadcastTx(txBytes)
if err != nil {
return err
}
return clientCtx.PrintOutput(res)
}
// EnrichWithGas calculates the gas estimate that would be consumed by the
// transaction and set the transaction's respective value accordingly.
func EnrichWithGas(txBldr authtypes.TxBuilder, clientCtx client.Context, msgs []sdk.Msg) (authtypes.TxBuilder, error) {
@@ -148,74 +72,52 @@ func CalculateGas(
}
// PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout.
func PrintUnsignedStdTx(txBldr authtypes.TxBuilder, clientCtx client.Context, msgs []sdk.Msg) error {
stdTx, err := buildUnsignedStdTxOffline(txBldr, clientCtx, msgs)
if err != nil {
return err
}
json, err := clientCtx.JSONMarshaler.MarshalJSON(stdTx)
if err != nil {
return err
}
_, _ = fmt.Fprintf(clientCtx.Output, "%s\n", json)
return nil
func PrintUnsignedStdTx(txBldr tx.Factory, clientCtx client.Context, msgs []sdk.Msg) error {
err := tx.GenerateOrBroadcastTxWithFactory(clientCtx, txBldr, msgs...)
return err
}
// SignStdTx appends a signature to a StdTx and returns a copy of it. If appendSig
// SignTx appends a signature to a transaction. If appendSig
// is false, it replaces the signatures already attached with the new signature.
// Don't perform online validation or lookups if offline is true.
func SignStdTx(
txBldr authtypes.TxBuilder, clientCtx client.Context, name string,
stdTx authtypes.StdTx, appendSig bool, offline bool,
) (authtypes.StdTx, error) {
var signedStdTx authtypes.StdTx
info, err := txBldr.Keybase().Key(name)
func SignTx(txFactory tx.Factory, clientCtx client.Context, name string, stdTx client.TxBuilder, offline bool) error {
info, err := txFactory.Keybase().Key(name)
if err != nil {
return signedStdTx, err
return err
}
addr := info.GetPubKey().Address()
// check whether the address is a signer
if !isTxSigner(sdk.AccAddress(addr), stdTx.GetSigners()) {
return signedStdTx, fmt.Errorf("%s: %s", sdkerrors.ErrorInvalidSigner, name)
addr := sdk.AccAddress(info.GetPubKey().Address())
if !isTxSigner(addr, stdTx.GetTx().GetSigners()) {
return fmt.Errorf("%s: %s", sdkerrors.ErrorInvalidSigner, name)
}
if !offline {
txBldr, err = populateAccountFromState(txBldr, clientCtx, sdk.AccAddress(addr))
txFactory, err = populateAccountFromState(txFactory, clientCtx, addr)
if err != nil {
return signedStdTx, err
return err
}
}
return txBldr.SignStdTx(name, stdTx, appendSig)
return tx.Sign(txFactory, name, stdTx)
}
// SignStdTxWithSignerAddress attaches a signature to a StdTx and returns a copy of a it.
// SignTxWithSignerAddress attaches a signature to a transaction.
// Don't perform online validation or lookups if offline is true, else
// populate account and sequence numbers from a foreign account.
func SignStdTxWithSignerAddress(
txBldr authtypes.TxBuilder, clientCtx client.Context,
addr sdk.AccAddress, name string, stdTx authtypes.StdTx, offline bool,
) (signedStdTx authtypes.StdTx, err error) {
func SignTxWithSignerAddress(txFactory tx.Factory, clientCtx client.Context, addr sdk.AccAddress,
name string, txBuilder client.TxBuilder, offline bool) (err error) {
// check whether the address is a signer
if !isTxSigner(addr, stdTx.GetSigners()) {
return signedStdTx, fmt.Errorf("%s: %s", sdkerrors.ErrorInvalidSigner, name)
if !isTxSigner(addr, txBuilder.GetTx().GetSigners()) {
return fmt.Errorf("%s: %s", sdkerrors.ErrorInvalidSigner, name)
}
if !offline {
txBldr, err = populateAccountFromState(txBldr, clientCtx, addr)
txFactory, err = populateAccountFromState(txFactory, clientCtx, addr)
if err != nil {
return signedStdTx, err
return err
}
}
return txBldr.SignStdTx(name, stdTx, false)
return tx.Sign(txFactory, name, txBuilder)
}
// Read and decode a StdTx from the given filename. Can pass "-" to read from stdin.
@@ -236,21 +138,21 @@ func ReadTxFromFile(ctx client.Context, filename string) (tx sdk.Tx, err error)
}
// NewBatchScanner returns a new BatchScanner to read newline-delimited StdTx transactions from r.
func NewBatchScanner(cdc codec.JSONMarshaler, r io.Reader) *BatchScanner {
return &BatchScanner{Scanner: bufio.NewScanner(r), cdc: cdc}
func NewBatchScanner(cfg client.TxConfig, r io.Reader) *BatchScanner {
return &BatchScanner{Scanner: bufio.NewScanner(r), cfg: cfg}
}
// BatchScanner provides a convenient interface for reading batch data such as a file
// of newline-delimited JSON encoded StdTx.
type BatchScanner struct {
*bufio.Scanner
stdTx authtypes.StdTx
cdc codec.JSONMarshaler
theTx sdk.Tx
cfg client.TxConfig
unmarshalErr error
}
// StdTx returns the most recent StdTx unmarshalled by a call to Scan.
func (bs BatchScanner) StdTx() authtypes.StdTx { return bs.stdTx }
// Tx returns the most recent Tx unmarshalled by a call to Scan.
func (bs BatchScanner) Tx() sdk.Tx { return bs.theTx }
// UnmarshalErr returns the first unmarshalling error that was encountered by the scanner.
func (bs BatchScanner) UnmarshalErr() error { return bs.unmarshalErr }
@@ -261,7 +163,9 @@ func (bs *BatchScanner) Scan() bool {
return false
}
if err := bs.cdc.UnmarshalJSON(bs.Bytes(), &bs.stdTx); err != nil && bs.unmarshalErr == nil {
tx, err := bs.cfg.TxJSONDecoder()(bs.Bytes())
bs.theTx = tx
if err != nil && bs.unmarshalErr == nil {
bs.unmarshalErr = err
return false
}
@@ -270,8 +174,8 @@ func (bs *BatchScanner) Scan() bool {
}
func populateAccountFromState(
txBldr authtypes.TxBuilder, clientCtx client.Context, addr sdk.AccAddress,
) (authtypes.TxBuilder, error) {
txBldr tx.Factory, clientCtx client.Context, addr sdk.AccAddress,
) (tx.Factory, error) {
num, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, addr)
if err != nil {
@@ -316,56 +220,6 @@ func parseQueryResponse(bz []byte) (sdk.SimulationResponse, error) {
return simRes, nil
}
// PrepareTxBuilder populates a TxBuilder in preparation for the build of a Tx.
func PrepareTxBuilder(txBldr authtypes.TxBuilder, clientCtx client.Context) (authtypes.TxBuilder, error) {
from := clientCtx.GetFromAddress()
accGetter := clientCtx.AccountRetriever
if err := accGetter.EnsureExists(clientCtx, from); err != nil {
return txBldr, err
}
txbldrAccNum, txbldrAccSeq := txBldr.AccountNumber(), txBldr.Sequence()
// TODO: (ref #1903) Allow for user supplied account number without
// automatically doing a manual lookup.
if txbldrAccNum == 0 || txbldrAccSeq == 0 {
num, seq, err := accGetter.GetAccountNumberSequence(clientCtx, from)
if err != nil {
return txBldr, err
}
if txbldrAccNum == 0 {
txBldr = txBldr.WithAccountNumber(num)
}
if txbldrAccSeq == 0 {
txBldr = txBldr.WithSequence(seq)
}
}
return txBldr, nil
}
func buildUnsignedStdTxOffline(txBldr authtypes.TxBuilder, clientCtx client.Context, msgs []sdk.Msg) (stdTx authtypes.StdTx, err error) {
if txBldr.SimulateAndExecute() {
if clientCtx.Offline {
return stdTx, errors.New("cannot estimate gas in offline mode")
}
txBldr, err = EnrichWithGas(txBldr, clientCtx, msgs)
if err != nil {
return stdTx, err
}
_, _ = fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.Gas())
}
stdSignMsg, err := txBldr.BuildSignMsg(msgs)
if err != nil {
return stdTx, err
}
return authtypes.NewStdTx(stdSignMsg.Msgs, stdSignMsg.Fee, nil, stdSignMsg.Memo), nil
}
func isTxSigner(user sdk.AccAddress, signers []sdk.AccAddress) bool {
for _, s := range signers {
if bytes.Equal(user.Bytes(), s.Bytes()) {
+10 -47
View File
@@ -6,6 +6,7 @@ import (
"strings"
"testing"
"github.com/cosmos/cosmos-sdk/std"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
@@ -149,8 +150,12 @@ func TestReadStdTxFromFile(t *testing.T) {
func TestBatchScanner_Scan(t *testing.T) {
t.Parallel()
cdc := codec.New()
sdk.RegisterCodec(cdc)
encodingConfig := simappparams.MakeEncodingConfig()
std.RegisterCodec(encodingConfig.Amino)
txGen := encodingConfig.TxConfig
clientCtx := client.Context{}
clientCtx = clientCtx.WithTxConfig(txGen)
batch1 := `{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"150"}],"gas":"50000"},"signatures":[],"memo":"foomemo"}
{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"150"}],"gas":"10000"},"signatures":[],"memo":"foomemo"}
@@ -182,12 +187,12 @@ malformed
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
scanner, i := NewBatchScanner(cdc, strings.NewReader(tt.batch)), 0
scanner, i := NewBatchScanner(clientCtx.TxConfig, strings.NewReader(tt.batch)), 0
for scanner.Scan() {
_ = scanner.StdTx()
_ = scanner.Tx()
i++
}
t.Log(scanner.theTx)
require.Equal(t, tt.wantScannerError, scanner.Err() != nil)
require.Equal(t, tt.wantUnmarshalError, scanner.UnmarshalErr() != nil)
require.Equal(t, tt.numTxs, i)
@@ -206,48 +211,6 @@ func compareEncoders(t *testing.T, expected sdk.TxEncoder, actual sdk.TxEncoder)
require.Equal(t, defaultEncoderBytes, encoderBytes)
}
func TestPrepareTxBuilder(t *testing.T) {
cdc := makeCodec()
encodingConfig := simappparams.MakeEncodingConfig()
sdk.RegisterCodec(encodingConfig.Amino)
fromAddr := sdk.AccAddress("test-addr0000000000")
fromAddrStr := fromAddr.String()
var accNum uint64 = 10
var accSeq uint64 = 17
txGen := encodingConfig.TxConfig
clientCtx := client.Context{}
clientCtx = clientCtx.
WithTxConfig(txGen).
WithJSONMarshaler(encodingConfig.Marshaler).
WithAccountRetriever(client.TestAccountRetriever{Accounts: map[string]struct {
Address sdk.AccAddress
Num uint64
Seq uint64
}{
fromAddrStr: {
Address: fromAddr,
Num: accNum,
Seq: accSeq,
},
}}).
WithFromAddress(fromAddr)
bldr := authtypes.NewTxBuilder(
authtypes.DefaultTxEncoder(cdc), 0, 0,
200000, 1.1, false, "test-chain",
"test-builder", sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))),
sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDecWithPrec(10000, sdk.Precision))})
bldr, err := PrepareTxBuilder(bldr, clientCtx)
require.NoError(t, err)
require.Equal(t, accNum, bldr.AccountNumber())
require.Equal(t, accSeq, bldr.Sequence())
}
func makeCodec() *codec.Codec {
var cdc = codec.New()
sdk.RegisterCodec(cdc)