Skip to content

Commit

Permalink
feat: add --broadcasd-mode flag to node tx command
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tbruyelle committed Aug 11, 2022
1 parent 89a0349 commit e3b92cf
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 31 deletions.
2 changes: 2 additions & 0 deletions ignite/cmd/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func newNodeCosmosClient(cmd *cobra.Command) (cosmosclient.Client, error) {
gas = getGas(cmd)
gasPrices = getGasPrices(cmd)
fees = getFees(cmd)
broadcastMode = getBroadcastMode(cmd)
)

options := []cosmosclient.Option{
Expand All @@ -44,6 +45,7 @@ func newNodeCosmosClient(cmd *cobra.Command) (cosmosclient.Client, error) {
cosmosclient.WithKeyringBackend(keyringBackend),
cosmosclient.WithKeyringDir(keyringDir),
cosmosclient.WithNodeAddress(xurl.HTTPEnsurePort(node)),
cosmosclient.WithBroadcastMode(broadcastMode),
}

if gas != "" {
Expand Down
1 change: 1 addition & 0 deletions ignite/cmd/node_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func NewNodeQuery() *cobra.Command {
}

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

return c
}
Expand Down
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
}
23 changes: 19 additions & 4 deletions ignite/cmd/node_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,34 @@ package ignitecmd
import (
"fmt"

"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
)

const (
flagGenerateOnly = "generate-only"

gasFlagAuto = "auto"
flagGasPrices = "gas-prices"
flagGas = "gas"
flagFees = "fees"
gasFlagAuto = "auto"
flagGasPrices = "gas-prices"
flagGas = "gas"
flagFees = "fees"
flagBroadcastMode = "broadcast-mode"
)

func NewNodeTx() *cobra.Command {
c := &cobra.Command{
Use: "tx",
Short: "Transactions subcommands",
}
c.PersistentFlags().AddFlagSet(flagSetHome())
c.PersistentFlags().AddFlagSet(flagSetKeyringBackend())
c.PersistentFlags().AddFlagSet(flagSetAccountPrefixes())
c.PersistentFlags().AddFlagSet(flagSetKeyringDir())
c.PersistentFlags().AddFlagSet(flagSetGenerateOnly())
c.PersistentFlags().AddFlagSet(flagSetGasFlags())
c.PersistentFlags().String(flagFees, "", "Fees to pay along with transaction; eg: 10uatom")
c.PersistentFlags().String(flagBroadcastMode, flags.BroadcastBlock, "Transaction broadcasting mode (sync|async|block), use sync if you encounter timeouts")

c.AddCommand(NewNodeTxBank())

Expand Down Expand Up @@ -59,3 +69,8 @@ func getFees(cmd *cobra.Command) string {
fees, _ := cmd.Flags().GetString(flagFees)
return fees
}

func getBroadcastMode(cmd *cobra.Command) string {
broadcastMode, _ := cmd.Flags().GetString(flagBroadcastMode)
return broadcastMode
}
22 changes: 11 additions & 11 deletions ignite/cmd/node_tx_bank_send.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ignitecmd

import (
"github.com/cosmos/cosmos-sdk/client/flags"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ignite/cli/ignite/pkg/cliui"
"github.com/spf13/cobra"
Expand All @@ -14,14 +15,6 @@ func NewNodeTxBankSend() *cobra.Command {
Args: cobra.ExactArgs(3),
}

c.Flags().AddFlagSet(flagSetHome())
c.Flags().AddFlagSet(flagSetKeyringBackend())
c.Flags().AddFlagSet(flagSetAccountPrefixes())
c.Flags().AddFlagSet(flagSetKeyringDir())
c.Flags().AddFlagSet(flagSetGenerateOnly())
c.Flags().AddFlagSet(flagSetGasFlags())
c.Flags().String(flagFees, "", "Fees to pay along with transaction; eg: 10uatom")

return c
}

Expand Down Expand Up @@ -73,11 +66,18 @@ func nodeTxBankSendHandler(cmd *cobra.Command, args []string) error {
}

session.StartSpinner("Sending transaction...")
if _, err := tx.Broadcast(); err != nil {
resp, err := tx.Broadcast()
if err != nil {
return err
}

session.StopSpinner()
session.Println("Transaction broadcast successful!")
return session.Printf("%s sent from %s to %s\n", amount, fromAccountInput, toAccountInput)
session.Printf("Transaction broadcast successful! (hash = %s)\n", resp.TxHash)
session.Printf("%s sent from %s to %s\n", amount, fromAccountInput, toAccountInput)
if getBroadcastMode(cmd) != flags.BroadcastBlock {
session.Println("Transaction waiting to be included in a block.")
session.Println("Run the following command to follow the transaction status:")
session.Printf(" ignite node --node %s q tx %s\n", getRPC(cmd), resp.TxHash)
}
return nil
}
37 changes: 21 additions & 16 deletions ignite/pkg/cosmosclient/cosmosclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,10 @@ type Client struct {
keyringBackend cosmosaccount.KeyringBackend
keyringDir string

gas string
gasPrices string
fees string
gas string
gasPrices string
fees string
broadcastMode string
}

// Option configures your client.
Expand Down Expand Up @@ -172,6 +173,13 @@ func WithFees(fees string) Option {
}
}

// WithBroadcastMode sets the broadcast mode
func WithBroadcastMode(broadcastMode string) Option {
return func(c *Client) {
c.broadcastMode = broadcastMode
}
}

// New creates a new client with given options.
func New(ctx context.Context, options ...Option) (Client, error) {
c := Client{
Expand All @@ -183,6 +191,7 @@ func New(ctx context.Context, options ...Option) (Client, error) {
faucetMinAmount: defaultFaucetMinAmount,
out: io.Discard,
gas: strconv.Itoa(defaultGasLimit),
broadcastMode: flags.BroadcastBlock,
}

var err error
Expand Down Expand Up @@ -223,7 +232,7 @@ func New(ctx context.Context, options ...Option) (Client, error) {
return Client{}, err
}

c.context = newContext(c.RPC, c.out, c.chainID, c.homePath).WithKeyring(c.AccountRegistry.Keyring)
c.context = c.newContext()
c.Factory = newFactory(c.context)

return c, nil
Expand Down Expand Up @@ -535,12 +544,7 @@ func prepareFactory(clientCtx client.Context, txf tx.Factory) (tx.Factory, error
return txf, nil
}

func newContext(
c *rpchttp.HTTP,
out io.Writer,
chainID,
home string,
) client.Context {
func (c Client) newContext() client.Context {
var (
amino = codec.NewLegacyAmino()
interfaceRegistry = codectypes.NewInterfaceRegistry()
Expand All @@ -556,18 +560,19 @@ func newContext(
banktypes.RegisterInterfaces(interfaceRegistry)

return client.Context{}.
WithChainID(chainID).
WithChainID(c.chainID).
WithInterfaceRegistry(interfaceRegistry).
WithCodec(marshaler).
WithTxConfig(txConfig).
WithLegacyAmino(amino).
WithInput(os.Stdin).
WithOutput(out).
WithOutput(c.out).
WithAccountRetriever(authtypes.AccountRetriever{}).
WithBroadcastMode(flags.BroadcastBlock).
WithHomeDir(home).
WithClient(c).
WithSkipConfirmation(true)
WithBroadcastMode(c.broadcastMode).
WithHomeDir(c.homePath).
WithClient(c.RPC).
WithSkipConfirmation(true).
WithKeyring(c.AccountRegistry.Keyring)
}

func newFactory(clientCtx client.Context) tx.Factory {
Expand Down
97 changes: 97 additions & 0 deletions integration/node/cmd_query_tx_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package node_test

import (
"bytes"
"context"
"regexp"
"testing"

"github.com/stretchr/testify/require"

"github.com/ignite/cli/ignite/pkg/cmdrunner/step"
"github.com/ignite/cli/ignite/pkg/cosmosclient"
"github.com/ignite/cli/ignite/pkg/randstr"
"github.com/ignite/cli/ignite/pkg/xurl"
envtest "github.com/ignite/cli/integration"
)

func TestNodeQueryTx(t *testing.T) {
var (
appname = randstr.Runes(10)
// alice = "alice"
// bob = "bob"

env = envtest.New(t)
app = env.Scaffold(appname)
home = env.AppHome(appname)
servers = app.RandomizeServerPorts()

// accKeyringDir = t.TempDir()
)

node, err := xurl.HTTP(servers.RPC)
require.NoError(t, err)

var (
ctx, cancel = context.WithTimeout(env.Ctx(), envtest.ServeTimeout)
isBackendAliveErr error
)

go func() {
defer cancel()

if isBackendAliveErr = env.IsAppServed(ctx, servers); isBackendAliveErr != nil {
return
}
client, err := cosmosclient.New(context.Background(),
cosmosclient.WithAddressPrefix(testPrefix),
cosmosclient.WithNodeAddress(node),
)
require.NoError(t, err)
require.NoError(t, client.WaitForNextBlock())

b := &bytes.Buffer{}
env.Exec("send 100token from alice to bob",
step.NewSteps(step.New(
step.Exec(
envtest.IgniteApp,
"node",
"tx",
"bank",
"send",
"alice",
"bob",
"100token",
"--node", node,
"--keyring-dir", home,
"--broadcast-mode", "sync",
),
step.Stdout(b),
)),
)
require.False(t, env.HasFailed(), b.String())

// Parse tx hash from output
res := regexp.MustCompile(`\(hash = (\w+)\)`).FindAllStringSubmatch(b.String(), -1)
require.Len(t, res[0], 2, "can't extract hash from command output")
hash := res[0][1]
require.NoError(t, client.WaitForNextBlock())

env.Must(env.Exec("query tx",
step.NewSteps(step.New(
step.Exec(
envtest.IgniteApp,
"node",
"query",
"tx",
hash,
"--node", node,
),
)),
))
}()

env.Must(app.Serve("should serve with Stargate version", envtest.ExecCtx(ctx)))

require.NoError(t, isBackendAliveErr, "app cannot get online in time")
}

0 comments on commit e3b92cf

Please sign in to comment.