Skip to content

Commit

Permalink
feat(cmd): introduce node command (#2669)
Browse files Browse the repository at this point in the history
* add node command with bank query and send

Bounty address: cosmos1zra3wz596n0qc898myceka3q23x9rk8fuw65c7

* Code review cleanup

* Code review fix

* fix merge

* refactor

* Merge branch 'develop' into issue-2489-node-banks-cmds

Fixed a bunch of conflicts with recent renaming

* wip: fix integration tests due to recent refac

* test: finish apply refac in tests

* Fix integration test on node command

* various improvments in node integration test

* test: read test.v to add more trace on step execution

That helps when some commands are not running properly.

* fix: spinner hides os keyring prompt

* Ensure bank send can take account name or address

Also simplify the logic by removing the read of the --from flag, which
is no longer used in this command.

BroadcastTx now takes a cosmosaccount.Account instead of just an account
name. Since ensure the account comes from the keyring, and avoid the
BroadcastTx impl to re-check that (because the keyring is always
checked before the call to BroadcastTx).

* fix after rebase

* fix: bank balance can take an address absent of the keyring

* fix tx broadcast error message

* add fees flag to node tx bank send cmd

fees are required, at least in cosmos-hub to send funds to an other
account. W/o fees the transaction returns this message:
error code: '13' msg: 'insufficient fees; got:  required: 8uatom:
insufficient fee'

Also increase the additional gas amount added to the simulated gas,
because I got some insufficient gas error with the previous value.

* Change tx BroadcastMode to BroadcastSync

Previous mode BroadcastBlock alweus triggered a timeout error, even if
the tx was finally accepted in a block.

RPC error -32603 - Internal error: timed out waiting for tx to be
included in a block

* fix linter

* fix other lint

* improve lookupAddress error report

* fix typo

* wip

* simplify

* add assertBankBalanceOutput

* wip find a way to wait for block height

* test: replace time.Sleep with app.WaitNBlocks

* gofumpt

* fix integration test

* BroadcastBlock is deprecated

* simplify node query

* feat: move WaitForBlock methods in cosmosclient

* fix: revert usage of BroadcastSync mode

* docs: adapt blog tutorial to cosmosclient changes

* feat: add --broadcasd-mode flag to node tx command

The default value is still block but the flag can change to sync in
order to avoid timeout when the tx is broadcasted to busy nodes.

Also add a `node query tx` so the user can check when his tx is
included in a block.

* comments

* style: consolidate arg names

* fix: add port to default node

* merge const decls

* fix merge error

* fix after merge

* fix after merge

Co-authored-by: Gjermund Bjaanes <[email protected]>
Co-authored-by: İlker G. Öztürk <[email protected]>
Co-authored-by: Alex Johnson <[email protected]>
  • Loading branch information
4 people authored Aug 22, 2022
1 parent e2eb141 commit 781e90a
Show file tree
Hide file tree
Showing 67 changed files with 2,232 additions and 790 deletions.
2 changes: 1 addition & 1 deletion docs/docs/guide/03-blog/02-connect-blockchain.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func main() {

// Broadcast a transaction from account `alice` with the message
// to create a post store response in txResp
txResp, err := cosmos.BroadcastTx(accountName, msg)
txResp, err := cosmos.BroadcastTx(account, msg)
if err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ require (
golang.org/x/text v0.3.7
google.golang.org/grpc v1.48.0
google.golang.org/protobuf v1.28.1
gopkg.in/yaml.v2 v2.4.0
)

require (
Expand Down Expand Up @@ -235,7 +236,6 @@ require (
google.golang.org/genproto v0.0.0-20220805133916-01dd62135a58 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
nhooyr.io/websocket v1.8.6 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ ignite scaffold chain github.com/username/mars`,
c.AddCommand(NewChain())
c.AddCommand(NewGenerate())
c.AddCommand(NewNetwork())
c.AddCommand(NewNode())
c.AddCommand(NewAccount())
c.AddCommand(NewRelayer())
c.AddCommand(NewTools())
Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ func getNetworkCosmosClient(cmd *cobra.Command) (cosmosclient.Client, error) {
cosmosclient.WithAddressPrefix(networktypes.SPN),
cosmosclient.WithUseFaucet(spnFaucetAddress, networktypes.SPNDenom, 5),
cosmosclient.WithKeyringServiceName(cosmosaccount.KeyringServiceName),
cosmosclient.WithKeyringDir(getKeyringDir(cmd)),
}

keyringBackend := getKeyringBackend(cmd)
Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network_campaign_publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func NewNetworkCampaignPublish() *cobra.Command {
c.Flags().String(flagMetadata, "", "Add a metada to the chain")
c.Flags().AddFlagSet(flagNetworkFrom())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())
c.Flags().AddFlagSet(flagSetHome())
return c
}
Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network_campaign_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func NewNetworkCampaignUpdate() *cobra.Command {
c.Flags().String(flagCampaignTotalSupply, "", "Update the total of the mainnet of a campaign")
c.Flags().AddFlagSet(flagNetworkFrom())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())
return c
}

Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network_chain_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func NewNetworkChainInit() *cobra.Command {
c.Flags().AddFlagSet(flagNetworkFrom())
c.Flags().AddFlagSet(flagSetHome())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())
c.Flags().AddFlagSet(flagSetYes())
c.Flags().AddFlagSet(flagSetCheckDependencies())
return c
Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network_chain_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func NewNetworkChainJoin() *cobra.Command {
c.Flags().AddFlagSet(flagNetworkFrom())
c.Flags().AddFlagSet(flagSetHome())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())
c.Flags().AddFlagSet(flagSetYes())
c.Flags().AddFlagSet(flagSetCheckDependencies())

Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network_chain_launch.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func NewNetworkChainLaunch() *cobra.Command {
c.Flags().Duration(flagRemainingTime, 0, "Duration of time in seconds before the chain is effectively launched")
c.Flags().AddFlagSet(flagNetworkFrom())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())

return c
}
Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network_chain_prepare.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func NewNetworkChainPrepare() *cobra.Command {
c.Flags().BoolP(flagForce, "f", false, "Force the prepare command to run even if the chain is not launched")
c.Flags().AddFlagSet(flagNetworkFrom())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())
c.Flags().AddFlagSet(flagSetHome())
c.Flags().AddFlagSet(flagSetCheckDependencies())

Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network_chain_publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ func NewNetworkChainPublish() *cobra.Command {
c.Flags().String(flagAmount, "", "Amount of coins for account request")
c.Flags().AddFlagSet(flagNetworkFrom())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())
c.Flags().AddFlagSet(flagSetHome())
c.Flags().AddFlagSet(flagSetYes())
c.Flags().AddFlagSet(flagSetCheckDependencies())
Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network_chain_revert_launch.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func NewNetworkChainRevertLaunch() *cobra.Command {

c.Flags().AddFlagSet(flagNetworkFrom())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())

return c
}
Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network_request_approve.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func NewNetworkRequestApprove() *cobra.Command {
c.Flags().AddFlagSet(flagNetworkFrom())
c.Flags().AddFlagSet(flagSetHome())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())
return c
}

Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network_request_reject.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func NewNetworkRequestReject() *cobra.Command {
c.Flags().AddFlagSet(flagNetworkFrom())
c.Flags().AddFlagSet(flagSetHome())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())
return c
}

Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network_request_verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func NewNetworkRequestVerify() *cobra.Command {
c.Flags().AddFlagSet(flagNetworkFrom())
c.Flags().AddFlagSet(flagSetHome())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())
return c
}

Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/network_reward_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func NewNetworkRewardSet() *cobra.Command {
RunE: networkChainRewardSetHandler,
}
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())
c.Flags().AddFlagSet(flagNetworkFrom())
c.Flags().AddFlagSet(flagSetHome())
return c
Expand Down
67 changes: 67 additions & 0 deletions ignite/cmd/node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package ignitecmd

import (
"github.com/ignite/cli/ignite/pkg/cosmosclient"
"github.com/ignite/cli/ignite/pkg/xurl"
"github.com/spf13/cobra"
)

const (
flagNode = "node"
cosmosRPCAddress = "https://rpc.cosmos.network:443"
)

func NewNode() *cobra.Command {
c := &cobra.Command{
Use: "node [command]",
Short: "Make calls to a live blockchain node",
Args: cobra.ExactArgs(1),
}

c.PersistentFlags().String(flagNode, cosmosRPCAddress, "<host>:<port> to tendermint rpc interface for this chain")

c.AddCommand(NewNodeQuery())
c.AddCommand(NewNodeTx())

return c
}

func newNodeCosmosClient(cmd *cobra.Command) (cosmosclient.Client, error) {
var (
home = getHome(cmd)
prefix = getAddressPrefix(cmd)
node = getRPC(cmd)
keyringBackend = getKeyringBackend(cmd)
keyringDir = getKeyringDir(cmd)
gas = getGas(cmd)
gasPrices = getGasPrices(cmd)
fees = getFees(cmd)
broadcastMode = getBroadcastMode(cmd)
)

options := []cosmosclient.Option{
cosmosclient.WithAddressPrefix(prefix),
cosmosclient.WithHome(home),
cosmosclient.WithKeyringBackend(keyringBackend),
cosmosclient.WithKeyringDir(keyringDir),
cosmosclient.WithNodeAddress(xurl.HTTPEnsurePort(node)),
cosmosclient.WithBroadcastMode(broadcastMode),
}

if gas != "" {
options = append(options, cosmosclient.WithGas(gas))
}
if gasPrices != "" {
options = append(options, cosmosclient.WithGasPrices(gasPrices))
}
if fees != "" {
options = append(options, cosmosclient.WithFees(fees))
}

return cosmosclient.New(cmd.Context(), options...)
}

func getRPC(cmd *cobra.Command) (rpc string) {
rpc, _ = cmd.Flags().GetString(flagNode)
return
}
72 changes: 72 additions & 0 deletions ignite/cmd/node_query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package ignitecmd

import (
"errors"
"fmt"

"github.com/cosmos/cosmos-sdk/types/query"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
)

const (
flagPage = "page"
flagLimit = "limit"
flagPageKey = "page-key"
flagOffset = "offset"
flagCountTotal = "count-total"
flagReverse = "reverse"
)

func NewNodeQuery() *cobra.Command {
c := &cobra.Command{
Use: "query",
Short: "Querying subcommands",
Aliases: []string{"q"},
}

c.AddCommand(NewNodeQueryBank())
c.AddCommand(NewNodeQueryTx())

return c
}

func flagSetPagination(query string) *flag.FlagSet {
fs := flag.NewFlagSet("", flag.ContinueOnError)

fs.Uint64(flagPage, 1, fmt.Sprintf("pagination page of %s to query for. This sets offset to a multiple of limit", query))
fs.String(flagPageKey, "", fmt.Sprintf("pagination page-key of %s to query for", query))
fs.Uint64(flagOffset, 0, fmt.Sprintf("pagination offset of %s to query for", query))
fs.Uint64(flagLimit, 100, fmt.Sprintf("pagination limit of %s to query for", query))
fs.Bool(flagCountTotal, false, fmt.Sprintf("count total number of records in %s to query for", query))
fs.Bool(flagReverse, false, "results are sorted in descending order")

return fs
}

func getPagination(cmd *cobra.Command) (*query.PageRequest, error) {
var (
pageKey, _ = cmd.Flags().GetString(flagPageKey)
offset, _ = cmd.Flags().GetUint64(flagOffset)
limit, _ = cmd.Flags().GetUint64(flagLimit)
countTotal, _ = cmd.Flags().GetBool(flagCountTotal)
page, _ = cmd.Flags().GetUint64(flagPage)
reverse, _ = cmd.Flags().GetBool(flagReverse)
)

if page > 1 && offset > 0 {
return nil, errors.New("page and offset cannot be used together")
}

if page > 1 {
offset = (page - 1) * limit
}

return &query.PageRequest{
Key: []byte(pageKey),
Offset: offset,
Limit: limit,
CountTotal: countTotal,
Reverse: reverse,
}, nil
}
14 changes: 14 additions & 0 deletions ignite/cmd/node_query_bank.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package ignitecmd

import "github.com/spf13/cobra"

func NewNodeQueryBank() *cobra.Command {
c := &cobra.Command{
Use: "bank",
Short: "Querying commands for the bank module",
}

c.AddCommand(NewNodeQueryBankBalances())

return c
}
61 changes: 61 additions & 0 deletions ignite/cmd/node_query_bank_balances.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package ignitecmd

import (
"fmt"

"github.com/ignite/cli/ignite/pkg/cliui"
"github.com/spf13/cobra"
)

func NewNodeQueryBankBalances() *cobra.Command {
c := &cobra.Command{
Use: "balances [from_account_or_address]",
Short: "Query for account balances by account name or address",
RunE: nodeQueryBankBalancesHandler,
Args: cobra.ExactArgs(1),
}

c.Flags().AddFlagSet(flagSetHome())
c.Flags().AddFlagSet(flagSetAccountPrefixes())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetKeyringDir())
c.Flags().AddFlagSet(flagSetPagination("all balances"))

return c
}

func nodeQueryBankBalancesHandler(cmd *cobra.Command, args []string) error {
inputAccount := args[0]

client, err := newNodeCosmosClient(cmd)
if err != nil {
return err
}

// inputAccount can be an account of the keyring or a raw address
address, err := client.Address(inputAccount)
if err != nil {
address = inputAccount
}

pagination, err := getPagination(cmd)
if err != nil {
return err
}

session := cliui.New()
defer session.Cleanup()
session.StartSpinner("Querying...")
balances, err := client.BankBalances(cmd.Context(), address, pagination)
if err != nil {
return err
}

var rows [][]string
for _, b := range balances {
rows = append(rows, []string{fmt.Sprintf("%s", b.Amount), b.Denom})
}

session.StopSpinner()
return session.PrintTable([]string{"Amount", "Denom"}, rows...)
}
41 changes: 41 additions & 0 deletions ignite/cmd/node_query_tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ignitecmd

import (
"encoding/hex"
"encoding/json"
"fmt"

sdkclient "github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"
)

func NewNodeQueryTx() *cobra.Command {
c := &cobra.Command{
Use: "tx [hash]",
Short: "Query for transaction by hash",
RunE: nodeQueryTxHandler,
Args: cobra.ExactArgs(1),
}
return c
}

func nodeQueryTxHandler(cmd *cobra.Command, args []string) error {
bz, err := hex.DecodeString(args[0])
if err != nil {
return err
}
rpc, err := sdkclient.NewClientFromNode(getRPC(cmd))
if err != nil {
return err
}
resp, err := rpc.Tx(cmd.Context(), bz, false)
if err != nil {
return err
}
bz, err = json.MarshalIndent(resp, "", " ")
if err != nil {
return err
}
fmt.Println(string(bz))
return nil
}
Loading

0 comments on commit 781e90a

Please sign in to comment.