From c6a9e652b40de08f36d11a7522f173e01118635e Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 28 Sep 2020 11:28:00 +0300 Subject: [PATCH 1/5] cli/wallet: improve token parameter help --- cli/wallet/nep5.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/wallet/nep5.go b/cli/wallet/nep5.go index 5ca1e293f..ffaea7232 100644 --- a/cli/wallet/nep5.go +++ b/cli/wallet/nep5.go @@ -28,7 +28,7 @@ var ( var ( tokenFlag = cli.StringFlag{ Name: "token", - Usage: "Token to use", + Usage: "Token to use (hash or name (for NEO/GAS or imported tokens))", } gasFlag = flags.Fixed8Flag{ Name: "gas", From aba9c9c0a8cd23548001198052bc86968a6943f7 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 28 Sep 2020 16:47:47 +0300 Subject: [PATCH 2/5] cli/wallet: print token symbol and name in balance output Make it a bit more user-friendly. --- cli/nep5_test.go | 4 ++-- cli/wallet/nep5.go | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/cli/nep5_test.go b/cli/nep5_test.go index 2f879ecc3..c99f3cda1 100644 --- a/cli/nep5_test.go +++ b/cli/nep5_test.go @@ -27,7 +27,7 @@ func TestNEP5Balance(t *testing.T) { t.Run("NEO", func(t *testing.T) { b, index := e.Chain.GetGoverningTokenBalance(validatorHash) checkResult := func(t *testing.T) { - e.checkNextLine(t, "^\\s*TokenHash:\\s*"+e.Chain.GoverningTokenHash().StringLE()) + e.checkNextLine(t, "^\\s*NEO:\\s+NEO \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)") e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()) e.checkNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10)) e.checkEOF(t) @@ -43,7 +43,7 @@ func TestNEP5Balance(t *testing.T) { }) t.Run("GAS", func(t *testing.T) { e.Run(t, append(cmd, "--token", "gas")...) - e.checkNextLine(t, "^\\s*TokenHash:\\s*"+e.Chain.UtilityTokenHash().StringLE()) + e.checkNextLine(t, "^\\s*GAS:\\s+GAS \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)") b := e.Chain.GetUtilityTokenBalance(validatorHash) e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+util.Fixed8(b.Int64()).String()) }) diff --git a/cli/wallet/nep5.go b/cli/wallet/nep5.go index ffaea7232..106857e6a 100644 --- a/cli/wallet/nep5.go +++ b/cli/wallet/nep5.go @@ -177,11 +177,23 @@ func getNEP5Balance(ctx *cli.Context) error { } for i := range balances.Balances { + var tokenName, tokenSymbol string + asset := balances.Balances[i].Asset if name != "" && !token.Hash.Equals(asset) { continue } - fmt.Fprintf(ctx.App.Writer, "TokenHash: %s\n", asset.StringLE()) + token, err := getMatchingToken(ctx, wall, asset.StringLE()) + if err != nil { + token, err = c.NEP5TokenInfo(asset) + } + if err == nil { + tokenName = token.Name + tokenSymbol = token.Symbol + } else { + tokenSymbol = "UNKNOWN" + } + fmt.Fprintf(ctx.App.Writer, "%s: %s (%s)\n", strings.ToUpper(tokenSymbol), tokenName, asset.StringLE()) fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", balances.Balances[i].Amount) fmt.Fprintf(ctx.App.Writer, "\tUpdated: %d\n", balances.Balances[i].LastUpdated) } @@ -190,9 +202,9 @@ func getNEP5Balance(ctx *cli.Context) error { func getMatchingToken(ctx *cli.Context, w *wallet.Wallet, name string) (*wallet.Token, error) { switch strings.ToLower(name) { - case "neo": + case "neo", client.NeoContractHash.StringLE(): return neoToken, nil - case "gas": + case "gas", client.GasContractHash.StringLE(): return gasToken, nil } return getMatchingTokenAux(ctx, func(i int) *wallet.Token { From 8d3e06498c03572ddea7f3822de981d1fed81fef Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 28 Sep 2020 16:53:35 +0300 Subject: [PATCH 3/5] rpc/client: handle tx creation error Fix neo-go contract invokefunction -w wallets/neofs1.json -a NXnzw3J9VvKXjM1BPAJK4QUpTtEQu4TpU6 -r http://main_chain.neofs.devenv:30333 af5dc5f7e6a6efc64d679098f328027591a2e518 deposit 12b97a2206ae4b10c7e0194b7b655c32cc912057 int:50 bytes: -- 12b97a2206ae4b10c7e0194b7b655c32cc912057 Enter account NXnzw3J9VvKXjM1BPAJK4QUpTtEQu4TpU6 password > panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x80 pc=0x934bbc] goroutine 1 [running]: github.com/nspcc-dev/neo-go/pkg/core/transaction.(*Transaction).GetSignedPart(0x0, 0x1028200, 0xc00013c000, 0xc0001a2680) github.com/nspcc-dev/neo-go/pkg/core/transaction/transaction.go:208 +0x13c github.com/nspcc-dev/neo-go/pkg/wallet.(*Account).SignTx(0xc0000ef880, 0x0, 0x40, 0x80) github.com/nspcc-dev/neo-go/pkg/wallet/account.go:105 +0x61 github.com/nspcc-dev/neo-go/pkg/rpc/client.(*Client).SignAndPushInvocationTx(0xc0001a0180, 0xc00008e280, 0x40, 0x80, 0xc0000ef880, 0xc140c6, 0x0, 0xc000218b90, 0x1, 0x1, ...) github.com/nspcc-dev/neo-go/pkg/rpc/client/rpc.go:449 +0xfe github.com/nspcc-dev/neo-go/cli/smartcontract.invokeInternal(0xc0000acb00, 0x1, 0x0, 0x0) github.com/nspcc-dev/neo-go/cli/smartcontract/smart_contract.go:493 +0xa4d github.com/nspcc-dev/neo-go/cli/smartcontract.invokeFunction(0xc0000acb00, 0x10100, 0xc0000acb00) github.com/nspcc-dev/neo-go/cli/smartcontract/smart_contract.go:418 +0x30 github.com/urfave/cli.HandleAction(0xc76cc0, 0xf175d0, 0xc0000acb00, 0xc00007ef00, 0x0) github.com/urfave/cli@v1.20.0/app.go:490 +0xc8 github.com/urfave/cli.Command.Run(0xdbcc3c, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdd9659, 0x2a, 0xde821b, ...) github.com/urfave/cli@v1.20.0/command.go:210 +0x9e8 github.com/urfave/cli.(*App).RunAsSubcommand(0xc00021e000, 0xc0000ac840, 0x0, 0x0) github.com/urfave/cli@v1.20.0/app.go:379 +0x88b github.com/urfave/cli.Command.startApp(0xdb803f, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdd7472, 0x28, 0x0, ...) github.com/urfave/cli@v1.20.0/command.go:298 +0x81a github.com/urfave/cli.Command.Run(0xdb803f, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdd7472, 0x28, 0x0, ...) github.com/urfave/cli@v1.20.0/command.go:98 +0x1219 github.com/urfave/cli.(*App).Run(0xc00009bd40, 0xc000030100, 0x10, 0x10, 0x0, 0x0) github.com/urfave/cli@v1.20.0/app.go:255 +0x741 main.main() command-line-arguments/main.go:18 +0x4b --- pkg/rpc/client/rpc.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/rpc/client/rpc.go b/pkg/rpc/client/rpc.go index 47c3c5219..e08c0f611 100644 --- a/pkg/rpc/client/rpc.go +++ b/pkg/rpc/client/rpc.go @@ -446,6 +446,9 @@ func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sys var err error tx, err := c.CreateTxFromScript(script, acc, sysfee, int64(netfee), cosigners...) + if err != nil { + return txHash, fmt.Errorf("failed to create tx: %w", err) + } if err = acc.SignTx(tx); err != nil { return txHash, fmt.Errorf("failed to sign tx: %w", err) } From fdcc72dad0868af7a7482abd8287a2fa9c74ffea Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 28 Sep 2020 17:24:21 +0300 Subject: [PATCH 4/5] cli/wallet: make 'addr' optional for NEP5 balances query Iterate over all accounts by default. --- cli/executor_test.go | 7 +++- cli/nep5_test.go | 61 ++++++++++++++++++++++++---- cli/wallet/nep5.go | 96 +++++++++++++++++++++++++------------------- 3 files changed, 115 insertions(+), 49 deletions(-) diff --git a/cli/executor_test.go b/cli/executor_test.go index 2a753d02b..e4198d437 100644 --- a/cli/executor_test.go +++ b/cli/executor_test.go @@ -127,9 +127,14 @@ func (e *executor) GetTransaction(t *testing.T, h util.Uint256) (*transaction.Tr return tx, height } -func (e *executor) checkNextLine(t *testing.T, expected string) { +func (e *executor) getNextLine(t *testing.T) string { line, err := e.Out.ReadString('\n') require.NoError(t, err) + return line +} + +func (e *executor) checkNextLine(t *testing.T, expected string) { + line := e.getNextLine(t) e.checkLine(t, line, expected) } diff --git a/cli/nep5_test.go b/cli/nep5_test.go index c99f3cda1..57d1185a8 100644 --- a/cli/nep5_test.go +++ b/cli/nep5_test.go @@ -6,6 +6,7 @@ import ( "os" "path" "strconv" + "strings" "testing" "github.com/nspcc-dev/neo-go/pkg/encoding/address" @@ -18,15 +19,16 @@ import ( func TestNEP5Balance(t *testing.T) { e := newExecutor(t, true) defer e.Close(t) - cmd := []string{ - "neo-go", "wallet", "nep5", "balance", - "--rpc-endpoint", "http://" + e.RPC.Addr, + cmdbalance := []string{"neo-go", "wallet", "nep5", "balance"} + cmdbase := append(cmdbalance, + "--rpc-endpoint", "http://"+e.RPC.Addr, "--wallet", validatorWallet, - "--addr", validatorAddr, - } + ) + cmd := append(cmdbase, "--addr", validatorAddr) t.Run("NEO", func(t *testing.T) { b, index := e.Chain.GetGoverningTokenBalance(validatorHash) checkResult := func(t *testing.T) { + e.checkNextLine(t, "^\\s*Account\\s+"+validatorAddr) e.checkNextLine(t, "^\\s*NEO:\\s+NEO \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)") e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()) e.checkNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10)) @@ -43,12 +45,57 @@ func TestNEP5Balance(t *testing.T) { }) t.Run("GAS", func(t *testing.T) { e.Run(t, append(cmd, "--token", "gas")...) + e.checkNextLine(t, "^\\s*Account\\s+"+validatorAddr) e.checkNextLine(t, "^\\s*GAS:\\s+GAS \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)") b := e.Chain.GetUtilityTokenBalance(validatorHash) e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+util.Fixed8(b.Int64()).String()) }) - t.Run("Invalid", func(t *testing.T) { - e.RunWithError(t, append(cmd, "--token", "kek")...) + t.Run("all accounts", func(t *testing.T) { + e.Run(t, cmdbase...) + addr1, err := address.StringToUint160("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc") + require.NoError(t, err) + e.checkNextLine(t, "^Account "+address.Uint160ToString(addr1)) + e.checkNextLine(t, "^\\s*GAS:\\s+GAS \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)") + balance := e.Chain.GetUtilityTokenBalance(addr1) + e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+util.Fixed8(balance.Int64()).String()) + e.checkNextLine(t, "^\\s*Updated:") + e.checkNextLine(t, "^\\s*$") + + addr2, err := address.StringToUint160("NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY") + require.NoError(t, err) + e.checkNextLine(t, "^Account "+address.Uint160ToString(addr2)) + e.checkNextLine(t, "^\\s*$") + + addr3, err := address.StringToUint160("NVNvVRW5Q5naSx2k2iZm7xRgtRNGuZppAK") + require.NoError(t, err) + e.checkNextLine(t, "^Account "+address.Uint160ToString(addr3)) + // The order of assets is undefined. + for i := 0; i < 2; i++ { + line := e.getNextLine(t) + if strings.Contains(line, "GAS") { + e.checkLine(t, line, "^\\s*GAS:\\s+GAS \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)") + balance = e.Chain.GetUtilityTokenBalance(addr3) + e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+util.Fixed8(balance.Int64()).String()) + e.checkNextLine(t, "^\\s*Updated:") + } else { + balance, index := e.Chain.GetGoverningTokenBalance(validatorHash) + e.checkLine(t, line, "^\\s*NEO:\\s+NEO \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)") + e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+balance.String()) + e.checkNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10)) + } + } + e.checkEOF(t) + }) + t.Run("Bad token", func(t *testing.T) { + e.Run(t, append(cmd, "--token", "kek")...) + e.checkNextLine(t, "^\\s*Account\\s+"+validatorAddr) + e.checkEOF(t) + }) + t.Run("Bad wallet", func(t *testing.T) { + e.RunWithError(t, append(cmdbalance, "--wallet", "/dev/null")...) + }) + t.Run("Bad address", func(t *testing.T) { + e.RunWithError(t, append(cmdbalance, "--rpc-endpoint", "http://"+e.RPC.Addr, "--wallet", validatorWallet, "--addr", "xxx")...) }) return } diff --git a/cli/wallet/nep5.go b/cli/wallet/nep5.go index 106857e6a..727be16e6 100644 --- a/cli/wallet/nep5.go +++ b/cli/wallet/nep5.go @@ -78,7 +78,7 @@ func newNEP5Commands() []cli.Command { { Name: "balance", Usage: "get address balance", - UsageText: "balance --wallet --rpc-endpoint --timeout