Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add node command with bank query and send #2539

Closed

Conversation

gjermundgaraba
Copy link
Contributor

@gjermundgaraba gjermundgaraba commented May 30, 2022

Bounty address: cosmos1zra3wz596n0qc898myceka3q23x9rk8fuw65c7

Closes #2489

Bounty address: cosmos1zra3wz596n0qc898myceka3q23x9rk8fuw65c7
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))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flags and the code below is pretty much a copy paste from cosmos-sdk

flagGenerateOnly = "generate-only"

gasFlagAuto = "auto"
flagGasPrices = "gas-prices"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opted to only include gas and gas-prices. The gas-adjustment flag doesn't seem to be necessary since we already have logic in cosmosclient to increase gas when using "auto"


func flagSetGasFlags() *flag.FlagSet {
fs := flag.NewFlagSet("", flag.ContinueOnError)
fs.String(flagGasPrices, "", "Gas prices in decimal format to determine the transaction fee (e.g. 0.1uatom)")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of these strings are just copy pasted from cosmos-sdk

@@ -51,7 +51,7 @@ const (

// Registry for accounts.
type Registry struct {
homePath string
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed this to avoid confusion. This is really the keyring dir, and was already used as such.

@@ -0,0 +1,66 @@
package cosmosclient
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this out of the cosmosclient file so that any non-generic functionality is separated into files

func (c Client) Status(ctx context.Context) (*ctypes.ResultStatus, error) {
return c.RPC.Status(ctx)
}
func performQuery[T any](c Client, q func() (T, error)) (T, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just to have a wrapper function that locks the bech32 prefix for queries. See how it is used in the bank client

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool!

func (c Client) BroadcastTxWithProvision(accountName string, msgs ...sdktypes.Msg) (
gas uint64, broadcast func() (Response, error), err error) {
unsignedTx client.TxBuilder, broadcast func() (Response, error), err error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed for this to return the unsigned transaction instead so that this could be used for generate-only commands. You simply don't call the broadcast function.
You can still get the gas from the unsigned tx.


const testAccountMnemonic = "develop mansion drum glow husband trophy labor jelly fault run pause inside jazz foil page injury foam oppose fruit chunk segment morning series nation"

func TestAccount(t *testing.T) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized there were no integration tests for account, so I added some (they are really fast)

@gjermundgaraba gjermundgaraba changed the title add node command with bank query and send feat: add node command with bank query and send May 30, 2022
Copy link
Member

@ilgooz ilgooz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works like a charm! 🎊 👏

}

func getPagination(cmd *cobra.Command) (*query.PageRequest, error) {
pageKey, _ := cmd.Flags().GetString(flagPageKey)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about wrapping al these under a single var block, so it can be better fmt'ed?

banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

func (c Client) BankBalances(address string, pagination *query.PageRequest) (sdk.Coins, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func (c Client) BankBalances(address string, pagination *query.PageRequest) (sdk.Coins, error) {
func (c Client) BankBalances(ctx context.Context, address string, pagination *query.PageRequest) (sdk.Coins, error) {

and same for others

}

_, err := c.BroadcastTx(fromAccountName, msg)
if err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if err != nil {
return err

func NewNodeQueryBankBalances() *cobra.Command {
c := &cobra.Command{
Use: "balances [address]",
Short: "Query for account balances by address",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Short: "Query for account balances by address",
Short: "Query for account balances by account name or address",


func NewNodeQueryBankBalances() *cobra.Command {
c := &cobra.Command{
Use: "balances [address]",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Use: "balances [address]",
Use: "balances [account-name|address]",

Pagination: pagination,
}

resp, err := performQuery[*banktypes.QueryAllBalancesResponse](c, func() (*banktypes.QueryAllBalancesResponse, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool generics!


commit, err := node.Commit(ctx, &height)
func (c Client) GenerateTx(accountName string, msgs ...sdktypes.Msg) (string, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func (c Client) GenerateTx(accountName string, msgs ...sdktypes.Msg) (string, error) {

What if we

  • drop this func
  • rename/refactor BroadcastTxWithProvision to CreateTx (because it doesn't really broadcast by default)
func CreateTx(accountName string, msgs ...sdktypes.Msg) (txService TxService, err error)


type TxService struct {
    client.TxBuilder
}

// Gas is gas decided to use for this tx.
// either calculated or configured by the caller.
func (s TxService) Gas() uint64 {}

// Broadcast signs and broadcasts this tx.
func (s TxService) Broadcast() error {}

func (s TxService) EncodeJSON() []byte {}

And we call CreateTx in the cmd, then string(TxService.EncodeJSON())

Can you please check if we really need an accountName param in CreateTx? I see in the code that we use it to set these before preparing the broadcast func. Looks like this has to be set anyway even if we just want to create an unsigned tx, can you please confirm that? Otherwise we can move the accountName param to TxService.Broadcast(accountName string).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good idea. I was indeed confused by that naming, so cleaning this up would be great. Will do!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ilgooz I did most of the work for this and there is one thing that is making accountName necessary in the current design.
It is needed for the gas simulation (it will fail without it because of sequence mismatch).

So the question becomes: should we

  1. Pre-calculate gas in CreateTx similar to what has been done now
    or
  2. Not (if so, should we do it only when asked in Gas()?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I think let's stick with the current API, option 1, where we get the accountName in CreateTx and calculate the gas beforehand. Otherwise the API will be a bit more complicated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ilgooz I made the changes. Take a look at the design and see if it makes sense to you.

func (c Client) Status(ctx context.Context) (*ctypes.ResultStatus, error) {
return c.RPC.Status(ctx)
}
func performQuery[T any](c Client, q func() (T, error)) (T, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool!

@@ -143,6 +150,18 @@ func WithUseFaucet(faucetAddress, denom string, minAmount uint64) Option {
}
}

func WithGas(gas string) Option {
Copy link
Contributor

@ivanovpetr ivanovpetr Jun 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add comments to the method, same for WithGasPrices


// Bech32Address returns the bech32 address, with the correct prefix, from account name or address.
func (c Client) Bech32Address(accountNameOrAddress string) (string, error) {
unlockFn := c.lockBech32Prefix()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
unlockFn := c.lockBech32Prefix()
defer c.lockBech32Prefix()()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about this. I'll do it, but I just wasn't sure if this really reads very clearly (it sort of looks like we're deferring the locking).

return c.RPC.Status(ctx)
}
func performQuery[T any](c Client, q func() (T, error)) (T, error) {
unlockFn := c.lockBech32Prefix()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
unlockFn := c.lockBech32Prefix()
defer c.lockBech32Prefix()()

defer mconf.Unlock()
config := sdktypes.GetConfig()
config.SetBech32PrefixForAccount(c.addressPrefix, c.addressPrefix+"pub")
unlockFn := c.lockBech32Prefix()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
unlockFn := c.lockBech32Prefix()
defer c.lockBech32Prefix()()

return err
}

session.Println("Transaction broadcast successful!")
Copy link
Contributor

@ivanovpetr ivanovpetr Jun 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
session.Println("Transaction broadcast successful!")
session.StopSpinner()
session.Println("Transaction broadcast successful!")

At this point spinner should be stopped manually

rows = append(rows, []string{fmt.Sprintf("%s", b.Amount), b.Denom})
}

return session.PrintTable([]string{"Amount", "Denom"}, rows...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return session.PrintTable([]string{"Amount", "Denom"}, rows...)
session.StopSpinner()
return session.PrintTable([]string{"Amount", "Denom"}, rows...)


// EncodeJSON encodes the transaction as a json string
func (s TxService) EncodeJSON() ([]byte, error) {
json, err := s.client.context.TxConfig.TxJSONEncoder()(s.txBuilder.GetTx())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
json, err := s.client.context.TxConfig.TxJSONEncoder()(s.txBuilder.GetTx())
return s.client.context.TxConfig.TxJSONEncoder()(s.txBuilder.GetTx())

@gjermundgaraba
Copy link
Contributor Author

@ilgooz Just to make sure, you're not waiting for me to do anything here right?

@ilgooz
Copy link
Member

ilgooz commented Jun 14, 2022

Hey Gjermund!

I'm refactoring some bits, will push some commits soon!

Copy link
Member

@ilgooz ilgooz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not require address prefix when querying, if the account address is used while querying

@gjermundgaraba
Copy link
Contributor Author

We should not require address prefix when querying, if the account address is used while querying

I don't think we are. I just tested it and it seems to work fine without the prefix. Updating the tests to show this now.

@ilgooz
Copy link
Member

ilgooz commented Jun 18, 2022

@bjaanes oh okay, that comment was more like a comment to remind to myself during review, sorry for the confusion!

@ilgooz ilgooz added this to the Priority milestone Jul 25, 2022
@ilgooz
Copy link
Member

ilgooz commented Jul 25, 2022

I was making some fixes and improvements on this PR and also tweaking the integration package's API.

My changes are in this branch within a50618c commit.

@jeronimoalbi @tbruyelle can you please take a look and maybe continue from here? So we can add those changes into this PR and finally merge it.

@aljo242
Copy link
Contributor

aljo242 commented Aug 25, 2022

Can we close this?

@ilgooz ilgooz closed this Aug 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

add node command set w/ token transfer functionality
4 participants