Merge pull request #2625 from nspcc-dev/excessive-cli-positionals

Handle excessive positional arguments in the CLI
This commit is contained in:
Roman Khimov 2022-08-05 19:05:54 +03:00 committed by GitHub
commit 41613cd631
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 339 additions and 93 deletions

View file

@ -41,6 +41,13 @@ func TestRegisterCandidate(t *testing.T) {
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", validatorWallet) "--wallet", validatorWallet)
// additional parameter
e.RunWithError(t, "neo-go", "wallet", "candidate", "register",
"--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", validatorWallet,
"--address", validatorPriv.Address(),
"error")
e.In.WriteString("one\r") e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "candidate", "register", e.Run(t, "neo-go", "wallet", "candidate", "register",
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
@ -55,6 +62,13 @@ func TestRegisterCandidate(t *testing.T) {
require.Equal(t, big.NewInt(0), vs[0].Votes) require.Equal(t, big.NewInt(0), vs[0].Votes)
t.Run("VoteUnvote", func(t *testing.T) { t.Run("VoteUnvote", func(t *testing.T) {
// positional instead of a flag.
e.RunWithError(t, "neo-go", "wallet", "candidate", "vote",
"--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", validatorWallet,
"--address", validatorPriv.Address(),
validatorHex) // not "--candidate hex", but "hex".
e.In.WriteString("one\r") e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "candidate", "vote", e.Run(t, "neo-go", "wallet", "candidate", "vote",
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
@ -115,6 +129,12 @@ func TestRegisterCandidate(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "candidate", "unregister", e.RunWithError(t, "neo-go", "wallet", "candidate", "unregister",
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", validatorWallet) "--wallet", validatorWallet)
// additional argument
e.RunWithError(t, "neo-go", "wallet", "candidate", "unregister",
"--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", validatorWallet,
"--address", validatorPriv.Address(),
"argument")
e.In.WriteString("one\r") e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "candidate", "unregister", e.Run(t, "neo-go", "wallet", "candidate", "unregister",
@ -128,4 +148,8 @@ func TestRegisterCandidate(t *testing.T) {
// query voter: missing address // query voter: missing address
e.RunWithError(t, "neo-go", "query", "voter") e.RunWithError(t, "neo-go", "query", "voter")
// Excessive parameters.
e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addr, validatorPriv.Address(), validatorPriv.Address())
e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addr, "something")
e.RunWithError(t, "neo-go", "query", "candidates", "--rpc-endpoint", "http://"+e.RPC.Addr, "something")
} }

View file

@ -131,6 +131,15 @@ func GetDataFromContext(ctx *cli.Context) (int, interface{}, *cli.ExitError) {
return offset, data, nil return offset, data, nil
} }
// EnsureNone returns an error if there are any positional arguments present.
// It can be used to check for them in commands that don't accept arguments.
func EnsureNone(ctx *cli.Context) *cli.ExitError {
if ctx.Args().Present() {
return cli.NewExitError("additional arguments given while this command expects none", 1)
}
return nil
}
// ParseParams extracts array of smartcontract.Parameter from the given args and // ParseParams extracts array of smartcontract.Parameter from the given args and
// returns the number of handled words, the array itself and an error. // returns the number of handled words, the array itself and an error.
// `calledFromMain` denotes whether the method was called from the outside or // `calledFromMain` denotes whether the method was called from the outside or

View file

@ -78,6 +78,9 @@ func TestCalcHash(t *testing.T) {
cmd = append(cmd, "--in", nefPath, "--manifest", manifestPath) cmd = append(cmd, "--in", nefPath, "--manifest", manifestPath)
expected := state.CreateContractHash(sender, nefF.Checksum, manif.Name) expected := state.CreateContractHash(sender, nefF.Checksum, manif.Name)
t.Run("excessive parameters", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "something")...)
})
t.Run("valid, uint160", func(t *testing.T) { t.Run("valid, uint160", func(t *testing.T) {
e.Run(t, append(cmd, "--sender", sender.StringLE())...) e.Run(t, append(cmd, "--sender", sender.StringLE())...)
e.checkNextLine(t, expected.StringLE()) e.checkNextLine(t, expected.StringLE())
@ -156,6 +159,9 @@ func Blocks() []*alias.Block {
"--out", filepath.Join(tmpDir, "out.nef"), "--out", filepath.Join(tmpDir, "out.nef"),
"--manifest", manifestPath, "--manifest", manifestPath,
"--bindings", bindingsPath) "--bindings", bindingsPath)
t.Run("excessive parameters", func(t *testing.T) {
e.RunWithError(t, append(cmd, "something")...)
})
e.Run(t, cmd...) e.Run(t, cmd...)
e.checkEOF(t) e.checkEOF(t)
require.FileExists(t, bindingsPath) require.FileExists(t, bindingsPath)
@ -220,6 +226,10 @@ func TestContractInitAndCompile(t *testing.T) {
}) })
ctrPath := filepath.Join(tmpDir, "testcontract") ctrPath := filepath.Join(tmpDir, "testcontract")
t.Run("excessive parameters", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "init", "--name", ctrPath, "something")
})
e.Run(t, "neo-go", "contract", "init", "--name", ctrPath) e.Run(t, "neo-go", "contract", "init", "--name", ctrPath)
t.Run("don't rewrite existing directory", func(t *testing.T) { t.Run("don't rewrite existing directory", func(t *testing.T) {
@ -263,6 +273,11 @@ func TestContractInitAndCompile(t *testing.T) {
require.NoError(t, os.WriteFile(goMod, data, os.ModePerm)) require.NoError(t, os.WriteFile(goMod, data, os.ModePerm))
cmd = append(cmd, "--config", cfgPath) cmd = append(cmd, "--config", cfgPath)
t.Run("excessive parameters", func(t *testing.T) {
e.RunWithError(t, append(cmd, "something")...)
})
e.Run(t, cmd...) e.Run(t, cmd...)
e.checkEOF(t) e.checkEOF(t)
require.FileExists(t, nefPath) require.FileExists(t, nefPath)
@ -504,6 +519,10 @@ func TestContractManifestGroups(t *testing.T) {
cmd := []string{"neo-go", "contract", "manifest", "add-group", cmd := []string{"neo-go", "contract", "manifest", "add-group",
"--nef", nefName, "--manifest", manifestName} "--nef", nefName, "--manifest", manifestName}
t.Run("excessive parameters", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--wallet", testWalletPath,
"--sender", testWalletAccount, "--address", testWalletAccount, "something")...)
})
e.In.WriteString("testpass\r") e.In.WriteString("testpass\r")
e.Run(t, append(cmd, "--wallet", testWalletPath, e.Run(t, append(cmd, "--wallet", testWalletPath,
"--sender", testWalletAccount, "--address", testWalletAccount)...) "--sender", testWalletAccount, "--address", testWalletAccount)...)
@ -916,6 +935,7 @@ func TestContractInspect(t *testing.T) {
t.Run("with nef", func(t *testing.T) { t.Run("with nef", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--in", nefName, "--compile")...) e.RunWithError(t, append(cmd, "--in", nefName, "--compile")...)
e.RunWithError(t, append(cmd, "--in", filepath.Join(tmpDir, "not.exists"))...) e.RunWithError(t, append(cmd, "--in", filepath.Join(tmpDir, "not.exists"))...)
e.RunWithError(t, append(cmd, "--in", nefName, "something")...)
e.Run(t, append(cmd, "--in", nefName)...) e.Run(t, append(cmd, "--in", nefName)...)
require.True(t, strings.Contains(e.Out.String(), "SYSCALL")) require.True(t, strings.Contains(e.Out.String(), "SYSCALL"))
}) })

View file

@ -38,6 +38,9 @@ func TestDBRestoreDump(t *testing.T) {
baseArgs := []string{"neo-go", "db", "restore", "--unittest", baseArgs := []string{"neo-go", "db", "restore", "--unittest",
"--config-path", tmpDir, "--in", inDump, "--dump", stateDump} "--config-path", tmpDir, "--in", inDump, "--dump", stateDump}
t.Run("excessive restore parameters", func(t *testing.T) {
e.RunWithError(t, append(baseArgs, "something")...)
})
// First 15 blocks. // First 15 blocks.
e.Run(t, append(baseArgs, "--count", "15")...) e.Run(t, append(baseArgs, "--count", "15")...)
@ -94,6 +97,9 @@ func TestDBRestoreDump(t *testing.T) {
t.Run("invalid start/count", func(t *testing.T) { t.Run("invalid start/count", func(t *testing.T) {
e.RunWithError(t, append(baseCmd, "--start", "5", "--count", strconv.Itoa(50-5+1+1))...) e.RunWithError(t, append(baseCmd, "--start", "5", "--count", strconv.Itoa(50-5+1+1))...)
}) })
t.Run("excessive dump parameters", func(t *testing.T) {
e.RunWithError(t, append(baseCmd, "something")...)
})
e.Run(t, baseCmd...) e.Run(t, baseCmd...)

View file

@ -148,6 +148,11 @@ func TestSignMultisigTx(t *testing.T) {
e.checkEOF(t) e.checkEOF(t)
}) })
t.Run("excessive parameters", func(t *testing.T) {
e.RunWithError(t, "neo-go", "util", "txdump",
"--rpc-endpoint", "http://"+e.RPC.Addr,
txPath, "garbage")
})
e.Run(t, "neo-go", "util", "txdump", e.Run(t, "neo-go", "util", "txdump",
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
txPath) txPath)

View file

@ -52,6 +52,9 @@ func TestNEP11Import(t *testing.T) {
// missing token hash // missing token hash
e.RunWithError(t, args...) e.RunWithError(t, args...)
// excessive parameters
e.RunWithError(t, append(args, "--token", nnsContractHash.StringLE(), "something")...)
// good: non-divisible // good: non-divisible
e.Run(t, append(args, "--token", nnsContractHash.StringLE())...) e.Run(t, append(args, "--token", nnsContractHash.StringLE())...)
@ -73,6 +76,10 @@ func TestNEP11Import(t *testing.T) {
e.checkNextLine(t, "^Standard:\\s*"+string(manifest.NEP11StandardName)) e.checkNextLine(t, "^Standard:\\s*"+string(manifest.NEP11StandardName))
} }
t.Run("Info", func(t *testing.T) { t.Run("Info", func(t *testing.T) {
t.Run("excessive parameters", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "nep11", "info",
"--wallet", walletPath, "--token", nnsContractHash.StringLE(), "qwerty")
})
t.Run("WithToken", func(t *testing.T) { t.Run("WithToken", func(t *testing.T) {
e.Run(t, "neo-go", "wallet", "nep11", "info", e.Run(t, "neo-go", "wallet", "nep11", "info",
"--wallet", walletPath, "--token", nnsContractHash.StringLE()) "--wallet", walletPath, "--token", nnsContractHash.StringLE())
@ -88,6 +95,8 @@ func TestNEP11Import(t *testing.T) {
}) })
t.Run("Remove", func(t *testing.T) { t.Run("Remove", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "nep11", "remove",
"--wallet", walletPath, "--token", nnsContractHash.StringLE(), "parameter")
e.In.WriteString("y\r") e.In.WriteString("y\r")
e.Run(t, "neo-go", "wallet", "nep11", "remove", e.Run(t, "neo-go", "wallet", "nep11", "remove",
"--wallet", walletPath, "--token", nnsContractHash.StringLE()) "--wallet", walletPath, "--token", nnsContractHash.StringLE())
@ -166,6 +175,8 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
} }
// balance check: by symbol, token is not imported // balance check: by symbol, token is not imported
e.RunWithError(t, append(cmdCheckBalance, "--token", "HASHY")...) e.RunWithError(t, append(cmdCheckBalance, "--token", "HASHY")...)
// balance check: excessive parameters
e.RunWithError(t, append(cmdCheckBalance, "--token", h.StringLE(), "neo-go")...)
// balance check: by hash, ok // balance check: by hash, ok
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...) e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
checkBalanceResult(t, nftOwnerAddr, "1") checkBalanceResult(t, nftOwnerAddr, "1")
@ -256,6 +267,8 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
e.RunWithError(t, cmdTokens...) e.RunWithError(t, cmdTokens...)
cmdTokens = append(cmdTokens, "--token", h.StringLE()) cmdTokens = append(cmdTokens, "--token", h.StringLE())
// tokens: excessive parameters
e.RunWithError(t, append(cmdTokens, "additional")...)
// tokens: good, several tokens // tokens: good, several tokens
e.Run(t, cmdTokens...) e.Run(t, cmdTokens...)
require.Equal(t, hex.EncodeToString(fst), e.getNextLine(t)) require.Equal(t, hex.EncodeToString(fst), e.getNextLine(t))
@ -482,6 +495,9 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
e.RunWithError(t, cmdProperties...) e.RunWithError(t, cmdProperties...)
cmdProperties = append(cmdProperties, "--id", hex.EncodeToString(token2ID)) cmdProperties = append(cmdProperties, "--id", hex.EncodeToString(token2ID))
// properties: additional parameter
e.RunWithError(t, append(cmdProperties, "additiona")...)
// properties: ok // properties: ok
e.Run(t, cmdProperties...) e.Run(t, cmdProperties...)
jProps = e.getNextLine(t) jProps = e.getNextLine(t)

View file

@ -24,6 +24,9 @@ func TestNEP17Balance(t *testing.T) {
"--wallet", validatorWallet, "--wallet", validatorWallet,
) )
cmd := append(cmdbase, "--address", validatorAddr) cmd := append(cmdbase, "--address", validatorAddr)
t.Run("excessive parameters", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--token", "NEO", "gas")...)
})
t.Run("NEO", func(t *testing.T) { t.Run("NEO", func(t *testing.T) {
b, index := e.Chain.GetGoverningTokenBalance(validatorHash) b, index := e.Chain.GetGoverningTokenBalance(validatorHash)
checkResult := func(t *testing.T) { checkResult := func(t *testing.T) {
@ -321,6 +324,11 @@ func TestNEP17ImportToken(t *testing.T) {
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", walletPath) "--wallet", walletPath)
// additional parameter
e.RunWithError(t, "neo-go", "wallet", "nep17", "import",
"--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", walletPath,
"--token", gasContractHash.StringLE(), "useless")
e.Run(t, "neo-go", "wallet", "nep17", "import", e.Run(t, "neo-go", "wallet", "nep17", "import",
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", walletPath, "--wallet", walletPath,
@ -345,6 +353,10 @@ func TestNEP17ImportToken(t *testing.T) {
e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(gasContractHash)) e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(gasContractHash))
e.checkNextLine(t, "^Standard:\\s*"+string(manifest.NEP17StandardName)) e.checkNextLine(t, "^Standard:\\s*"+string(manifest.NEP17StandardName))
} }
t.Run("excessive parameters", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "nep17", "info",
"--wallet", walletPath, "--token", gasContractHash.StringLE(), "parameter")
})
t.Run("WithToken", func(t *testing.T) { t.Run("WithToken", func(t *testing.T) {
e.Run(t, "neo-go", "wallet", "nep17", "info", e.Run(t, "neo-go", "wallet", "nep17", "info",
"--wallet", walletPath, "--token", gasContractHash.StringLE()) "--wallet", walletPath, "--token", gasContractHash.StringLE())
@ -364,6 +376,8 @@ func TestNEP17ImportToken(t *testing.T) {
e.checkNextLine(t, "^Standard:\\s*"+string(manifest.NEP17StandardName)) e.checkNextLine(t, "^Standard:\\s*"+string(manifest.NEP17StandardName))
}) })
t.Run("Remove", func(t *testing.T) { t.Run("Remove", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "nep17", "remove",
"--wallet", walletPath, "--token", neoContractHash.StringLE(), "add")
e.In.WriteString("y\r") e.In.WriteString("y\r")
e.Run(t, "neo-go", "wallet", "nep17", "remove", e.Run(t, "neo-go", "wallet", "nep17", "remove",
"--wallet", walletPath, "--token", neoContractHash.StringLE()) "--wallet", walletPath, "--token", neoContractHash.StringLE())

View file

@ -23,9 +23,9 @@ const RPCEndpointFlag = "rpc-endpoint"
// Network is a set of flags for choosing the network to operate on // Network is a set of flags for choosing the network to operate on
// (privnet/mainnet/testnet). // (privnet/mainnet/testnet).
var Network = []cli.Flag{ var Network = []cli.Flag{
cli.BoolFlag{Name: "privnet, p"}, cli.BoolFlag{Name: "privnet, p", Usage: "use private network configuration"},
cli.BoolFlag{Name: "mainnet, m"}, cli.BoolFlag{Name: "mainnet, m", Usage: "use mainnet network configuration"},
cli.BoolFlag{Name: "testnet, t"}, cli.BoolFlag{Name: "testnet, t", Usage: "use testnet network configuration"},
cli.BoolFlag{Name: "unittest", Hidden: true}, cli.BoolFlag{Name: "unittest", Hidden: true},
} }

View file

@ -10,6 +10,7 @@ import (
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
@ -39,35 +40,39 @@ func NewCommands() []cli.Command {
Usage: "Query data from RPC node", Usage: "Query data from RPC node",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Name: "candidates", Name: "candidates",
Usage: "Get candidates and votes", Usage: "Get candidates and votes",
Action: queryCandidates, UsageText: "neo-go query candidates -r endpoint [-s timeout]",
Flags: options.RPC, Action: queryCandidates,
Flags: options.RPC,
}, },
{ {
Name: "committee", Name: "committee",
Usage: "Get committee list", Usage: "Get committee list",
Action: queryCommittee, UsageText: "neo-go query committee -r endpoint [-s timeout]",
Flags: options.RPC, Action: queryCommittee,
Flags: options.RPC,
}, },
{ {
Name: "height", Name: "height",
Usage: "Get node height", Usage: "Get node height",
Action: queryHeight, UsageText: "neo-go query height -r endpoint [-s timeout]",
Flags: options.RPC, Action: queryHeight,
Flags: options.RPC,
}, },
{ {
Name: "tx", Name: "tx",
Usage: "Query transaction status", Usage: "Query transaction status",
UsageText: "neo-go query tx <hash> -r endpoint [-v]", UsageText: "neo-go query tx <hash> -r endpoint [-s timeout] [-v]",
Action: queryTx, Action: queryTx,
Flags: queryTxFlags, Flags: queryTxFlags,
}, },
{ {
Name: "voter", Name: "voter",
Usage: "Print NEO holder account state", Usage: "Print NEO holder account state",
Action: queryVoter, UsageText: "neo-go query voter <address> -r endpoint [-s timeout]",
Flags: options.RPC, Action: queryVoter,
Flags: options.RPC,
}, },
}, },
}} }}
@ -77,6 +82,8 @@ func queryTx(ctx *cli.Context) error {
args := ctx.Args() args := ctx.Args()
if len(args) == 0 { if len(args) == 0 {
return cli.NewExitError("Transaction hash is missing", 1) return cli.NewExitError("Transaction hash is missing", 1)
} else if len(args) > 1 {
return cli.NewExitError("only one transaction hash is accepted", 1)
} }
txHash, err := util.Uint256DecodeStringLE(strings.TrimPrefix(args[0], "0x")) txHash, err := util.Uint256DecodeStringLE(strings.TrimPrefix(args[0], "0x"))
@ -160,6 +167,10 @@ func DumpApplicationLog(
func queryCandidates(ctx *cli.Context) error { func queryCandidates(ctx *cli.Context) error {
var err error var err error
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
gctx, cancel := options.GetTimeoutContext(ctx) gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel() defer cancel()
@ -200,6 +211,10 @@ func queryCandidates(ctx *cli.Context) error {
func queryCommittee(ctx *cli.Context) error { func queryCommittee(ctx *cli.Context) error {
var err error var err error
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
gctx, cancel := options.GetTimeoutContext(ctx) gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel() defer cancel()
@ -222,6 +237,10 @@ func queryCommittee(ctx *cli.Context) error {
func queryHeight(ctx *cli.Context) error { func queryHeight(ctx *cli.Context) error {
var err error var err error
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
gctx, cancel := options.GetTimeoutContext(ctx) gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel() defer cancel()
@ -250,6 +269,8 @@ func queryVoter(ctx *cli.Context) error {
args := ctx.Args() args := ctx.Args()
if len(args) == 0 { if len(args) == 0 {
return cli.NewExitError("No address specified", 1) return cli.NewExitError("No address specified", 1)
} else if len(args) > 1 {
return cli.NewExitError("this command only accepts one address", 1)
} }
addr, err := flags.ParseAddress(args[0]) addr, err := flags.ParseAddress(args[0])

View file

@ -101,6 +101,9 @@ func TestQueryTx(t *testing.T) {
t.Run("missing tx argument", func(t *testing.T) { t.Run("missing tx argument", func(t *testing.T) {
e.RunWithError(t, args...) e.RunWithError(t, args...)
}) })
t.Run("excessive arguments", func(t *testing.T) {
e.RunWithError(t, append(args, txHash.StringLE(), txHash.StringLE())...)
})
t.Run("invalid hash", func(t *testing.T) { t.Run("invalid hash", func(t *testing.T) {
e.RunWithError(t, append(args, "notahash")...) e.RunWithError(t, append(args, "notahash")...)
}) })
@ -142,8 +145,12 @@ func (e *executor) compareQueryTxVerbose(t *testing.T, tx *transaction.Transacti
func TestQueryHeight(t *testing.T) { func TestQueryHeight(t *testing.T) {
e := newExecutor(t, true) e := newExecutor(t, true)
e.Run(t, "neo-go", "query", "height", "--rpc-endpoint", "http://"+e.RPC.Addr) args := []string{"neo-go", "query", "height", "--rpc-endpoint", "http://" + e.RPC.Addr}
e.Run(t, args...)
e.checkNextLine(t, `^Latest block: [0-9]+$`) e.checkNextLine(t, `^Latest block: [0-9]+$`)
e.checkNextLine(t, `^Validated state: [0-9]+$`) e.checkNextLine(t, `^Validated state: [0-9]+$`)
e.checkEOF(t) e.checkEOF(t)
t.Run("excessive arguments", func(t *testing.T) {
e.RunWithError(t, append(args, "something")...)
})
} }

View file

@ -10,6 +10,7 @@ import (
"runtime" "runtime"
"time" "time"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/config/netmode"
@ -42,12 +43,13 @@ var (
// NewCommands returns 'node' command. // NewCommands returns 'node' command.
func NewCommands() []cli.Command { func NewCommands() []cli.Command {
var cfgFlags = []cli.Flag{ var cfgFlags = []cli.Flag{
cli.StringFlag{Name: "config-path"}, cli.StringFlag{Name: "config-path", Usage: "path to directory with configuration files"},
cli.BoolFlag{Name: "debug, d"},
} }
cfgFlags = append(cfgFlags, options.Network...) cfgFlags = append(cfgFlags, options.Network...)
var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags)) var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags))
copy(cfgWithCountFlags, cfgFlags) copy(cfgWithCountFlags, cfgFlags)
cfgFlags = append(cfgFlags, cli.BoolFlag{Name: "debug, d", Usage: "enable debug logging (LOTS of output)"})
cfgWithCountFlags = append(cfgWithCountFlags, cfgWithCountFlags = append(cfgWithCountFlags,
cli.UintFlag{ cli.UintFlag{
Name: "count, c", Name: "count, c",
@ -84,26 +86,29 @@ func NewCommands() []cli.Command {
) )
return []cli.Command{ return []cli.Command{
{ {
Name: "node", Name: "node",
Usage: "start a NEO node", Usage: "start a NEO node",
Action: startServer, UsageText: "neo-go node [--config-path path] [-d] [-p/-m/-t]",
Flags: cfgFlags, Action: startServer,
Flags: cfgFlags,
}, },
{ {
Name: "db", Name: "db",
Usage: "database manipulations", Usage: "database manipulations",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Name: "dump", Name: "dump",
Usage: "dump blocks (starting with block #1) to the file", Usage: "dump blocks (starting with block #1) to the file",
Action: dumpDB, UsageText: "neo-go db dump -o file [-s start] [-c count] [--config-path path] [-p/-m/-t]",
Flags: cfgCountOutFlags, Action: dumpDB,
Flags: cfgCountOutFlags,
}, },
{ {
Name: "restore", Name: "restore",
Usage: "restore blocks from the file", Usage: "restore blocks from the file",
Action: restoreDB, UsageText: "neo-go db restore -i file [--dump] [-n] [-c count] [--config-path path] [-p/-m/-t]",
Flags: cfgCountInFlags, Action: restoreDB,
Flags: cfgCountInFlags,
}, },
}, },
}, },
@ -223,6 +228,9 @@ func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *m
} }
func dumpDB(ctx *cli.Context) error { func dumpDB(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
cfg, err := getConfigFromContext(ctx) cfg, err := getConfigFromContext(ctx)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -273,6 +281,9 @@ func dumpDB(ctx *cli.Context) error {
} }
func restoreDB(ctx *cli.Context) error { func restoreDB(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
cfg, err := getConfigFromContext(ctx) cfg, err := getConfigFromContext(ctx)
if err != nil { if err != nil {
return err return err
@ -455,6 +466,10 @@ func mkP2PNotary(config config.P2PNotary, chain *core.Blockchain, serv *network.
} }
func startServer(ctx *cli.Context) error { func startServer(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
cfg, err := getConfigFromContext(ctx) cfg, err := getConfigFromContext(ctx)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)

View file

@ -98,9 +98,11 @@ func TestServerStart(t *testing.T) {
// We can't properly shutdown server on windows and release the resources. // We can't properly shutdown server on windows and release the resources.
// Also, windows doesn't support SIGHUP and SIGINT. // Also, windows doesn't support SIGHUP and SIGINT.
if runtime.GOOS != "windows" { if runtime.GOOS != "windows" {
saveCfg(t, func(cfg *config.Config) {})
t.Run("excessive parameters", func(t *testing.T) {
e.RunWithError(t, append(baseCmd, "something")...)
})
t.Run("good", func(t *testing.T) { t.Run("good", func(t *testing.T) {
saveCfg(t, func(cfg *config.Config) {})
go func() { go func() {
e.Run(t, baseCmd...) e.Run(t, baseCmd...)
}() }()

View file

@ -5,6 +5,7 @@ import (
"os" "os"
"strings" "strings"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/binding" "github.com/nspcc-dev/neo-go/pkg/smartcontract/binding"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/urfave/cli" "github.com/urfave/cli"
@ -39,6 +40,9 @@ var generateWrapperCmd = cli.Command{
// contractGenerateWrapper deploys contract. // contractGenerateWrapper deploys contract.
func contractGenerateWrapper(ctx *cli.Context) error { func contractGenerateWrapper(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
m, _, err := readManifest(ctx.String("manifest")) m, _, err := readManifest(ctx.String("manifest"))
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("can't read contract manifest: %w", err), 1) return cli.NewExitError(fmt.Errorf("can't read contract manifest: %w", err), 1)

View file

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
@ -14,6 +15,9 @@ import (
) )
func manifestAddGroup(ctx *cli.Context) error { func manifestAddGroup(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
sender, err := flags.ParseAddress(ctx.String("sender")) sender, err := flags.ParseAddress(ctx.String("sender"))
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("invalid sender: %w", err), 1) return cli.NewExitError(fmt.Errorf("invalid sender: %w", err), 1)

View file

@ -136,9 +136,10 @@ func NewCommands() []cli.Command {
Usage: "compile - debug - deploy smart contracts", Usage: "compile - debug - deploy smart contracts",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Name: "compile", Name: "compile",
Usage: "compile a smart contract to a .nef file", Usage: "compile a smart contract to a .nef file",
Action: contractCompile, UsageText: "neo-go contract compile -i path [-o nef] [-v] [-d] [-m manifest] [-c yaml] [--bindings file] [--no-standards] [--no-events] [--no-permissions]",
Action: contractCompile,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "in, i", Name: "in, i",
@ -340,9 +341,10 @@ func NewCommands() []cli.Command {
Flags: testInvokeScriptFlags, Flags: testInvokeScriptFlags,
}, },
{ {
Name: "init", Name: "init",
Usage: "initialize a new smart-contract in a directory with boiler plate code", Usage: "initialize a new smart-contract in a directory with boiler plate code",
Action: initSmartContract, UsageText: "neo-go contract init -n name [--skip-details]",
Action: initSmartContract,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "name, n", Name: "name, n",
@ -355,9 +357,10 @@ func NewCommands() []cli.Command {
}, },
}, },
{ {
Name: "inspect", Name: "inspect",
Usage: "creates a user readable dump of the program instructions", Usage: "creates a user readable dump of the program instructions",
Action: inspect, UsageText: "neo-go contract inspect -i file [-c]",
Action: inspect,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ cli.BoolFlag{
Name: "compile, c", Name: "compile, c",
@ -370,9 +373,10 @@ func NewCommands() []cli.Command {
}, },
}, },
{ {
Name: "calc-hash", Name: "calc-hash",
Usage: "calculates hash of a contract after deployment", Usage: "calculates hash of a contract after deployment",
Action: calcHash, UsageText: "neo-go contract calc-hash -i nef -m manifest -s address",
Action: calcHash,
Flags: []cli.Flag{ Flags: []cli.Flag{
flags.AddressFlag{ flags.AddressFlag{
Name: "sender, s", Name: "sender, s",
@ -393,9 +397,10 @@ func NewCommands() []cli.Command {
Usage: "manifest-related commands", Usage: "manifest-related commands",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Name: "add-group", Name: "add-group",
Usage: "adds group to the manifest", Usage: "adds group to the manifest",
Action: manifestAddGroup, UsageText: "neo-go contract manifest add-group -w wallet [--wallet-config path] -n nef -m manifest -a address -s address",
Action: manifestAddGroup,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletFlag, walletFlag,
walletConfigFlag, walletConfigFlag,
@ -425,6 +430,9 @@ func NewCommands() []cli.Command {
// initSmartContract initializes a given directory with some boiler plate code. // initSmartContract initializes a given directory with some boiler plate code.
func initSmartContract(ctx *cli.Context) error { func initSmartContract(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
contractName := ctx.String("name") contractName := ctx.String("name")
if contractName == "" { if contractName == "" {
return cli.NewExitError(errNoSmartContractName, 1) return cli.NewExitError(errNoSmartContractName, 1)
@ -494,6 +502,9 @@ require (
} }
func contractCompile(ctx *cli.Context) error { func contractCompile(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
src := ctx.String("in") src := ctx.String("in")
if len(src) == 0 { if len(src) == 0 {
return cli.NewExitError(errNoInput, 1) return cli.NewExitError(errNoInput, 1)
@ -546,6 +557,9 @@ func contractCompile(ctx *cli.Context) error {
} }
func calcHash(ctx *cli.Context) error { func calcHash(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
sender := ctx.Generic("sender").(*flags.Address) sender := ctx.Generic("sender").(*flags.Address)
if !sender.IsSet { if !sender.IsSet {
return cli.NewExitError("sender is not set", 1) return cli.NewExitError("sender is not set", 1)
@ -798,6 +812,9 @@ type ProjectConfig struct {
} }
func inspect(ctx *cli.Context) error { func inspect(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
in := ctx.String("in") in := ctx.String("in")
compile := ctx.Bool("compile") compile := ctx.Bool("compile")
if len(in) == 0 { if len(in) == 0 {

View file

@ -12,11 +12,14 @@ import (
) )
func txDump(ctx *cli.Context) error { func txDump(ctx *cli.Context) error {
if len(ctx.Args()) == 0 { args := ctx.Args()
if len(args) == 0 {
return cli.NewExitError("missing input file", 1) return cli.NewExitError("missing input file", 1)
} else if len(args) > 1 {
return cli.NewExitError("only one input file is accepted", 1)
} }
c, err := paramcontext.Read(ctx.Args()[0]) c, err := paramcontext.Read(args[0])
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }

View file

@ -4,6 +4,7 @@ import (
"os" "os"
"github.com/chzyer/readline" "github.com/chzyer/readline"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
vmcli "github.com/nspcc-dev/neo-go/pkg/vm/cli" vmcli "github.com/nspcc-dev/neo-go/pkg/vm/cli"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -21,6 +22,9 @@ func NewCommands() []cli.Command {
} }
func startVMPrompt(ctx *cli.Context) error { func startVMPrompt(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
p := vmcli.NewWithConfig(true, os.Exit, &readline.Config{}) p := vmcli.NewWithConfig(true, os.Exit, &readline.Config{})
return p.Run() return p.Run()
} }

View file

@ -3,6 +3,7 @@ package wallet
import ( import (
"fmt" "fmt"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/paramcontext" "github.com/nspcc-dev/neo-go/cli/paramcontext"
@ -12,6 +13,9 @@ import (
) )
func signStoredTransaction(ctx *cli.Context) error { func signStoredTransaction(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, pass, err := readWallet(ctx) wall, pass, err := readWallet(ctx)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)

View file

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input" "github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
@ -47,21 +48,21 @@ func newNEP11Commands() []cli.Command {
{ {
Name: "balance", Name: "balance",
Usage: "get address balance", Usage: "get address balance",
UsageText: "balance --wallet <path> --rpc-endpoint <node> [--timeout <time>] [--address <address>] --token <hash-or-name> [--id <token-id>]", UsageText: "balance -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] [--address <address>] --token <hash-or-name> [--id <token-id>]",
Action: getNEP11Balance, Action: getNEP11Balance,
Flags: balanceFlags, Flags: balanceFlags,
}, },
{ {
Name: "import", Name: "import",
Usage: "import NEP-11 token to a wallet", Usage: "import NEP-11 token to a wallet",
UsageText: "import --wallet <path> --rpc-endpoint <node> --timeout <time> --token <hash>", UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --token <hash>",
Action: importNEP11Token, Action: importNEP11Token,
Flags: importFlags, Flags: importFlags,
}, },
{ {
Name: "info", Name: "info",
Usage: "print imported NEP-11 token info", Usage: "print imported NEP-11 token info",
UsageText: "print --wallet <path> [--token <hash-or-name>]", UsageText: "print -w wallet [--wallet-config path] [--token <hash-or-name>]",
Action: printNEP11Info, Action: printNEP11Info,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
@ -72,7 +73,7 @@ func newNEP11Commands() []cli.Command {
{ {
Name: "remove", Name: "remove",
Usage: "remove NEP-11 token from the wallet", Usage: "remove NEP-11 token from the wallet",
UsageText: "remove --wallet <path> --token <hash-or-name>", UsageText: "remove -w wallet [--wallet-config path] --token <hash-or-name>",
Action: removeNEP11Token, Action: removeNEP11Token,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
@ -84,7 +85,7 @@ func newNEP11Commands() []cli.Command {
{ {
Name: "transfer", Name: "transfer",
Usage: "transfer NEP-11 tokens", Usage: "transfer NEP-11 tokens",
UsageText: "transfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]", UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
Action: transferNEP11, Action: transferNEP11,
Flags: transferFlags, Flags: transferFlags,
Description: `Transfers specified NEP-11 token with optional cosigners list attached to Description: `Transfers specified NEP-11 token with optional cosigners list attached to
@ -163,6 +164,10 @@ func removeNEP11Token(ctx *cli.Context) error {
func getNEP11Balance(ctx *cli.Context) error { func getNEP11Balance(ctx *cli.Context) error {
var accounts []*wallet.Account var accounts []*wallet.Account
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, _, err := readWallet(ctx) wall, _, err := readWallet(ctx)
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("bad wallet: %w", err), 1) return cli.NewExitError(fmt.Errorf("bad wallet: %w", err), 1)
@ -309,6 +314,9 @@ func printNEP11DOwner(ctx *cli.Context) error {
func printNEP11Owner(ctx *cli.Context, divisible bool) error { func printNEP11Owner(ctx *cli.Context, divisible bool) error {
var err error var err error
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
tokenHash := ctx.Generic("token").(*flags.Address) tokenHash := ctx.Generic("token").(*flags.Address)
if !tokenHash.IsSet { if !tokenHash.IsSet {
return cli.NewExitError("token contract hash was not set", 1) return cli.NewExitError("token contract hash was not set", 1)
@ -383,6 +391,9 @@ func printNEP11TokensOf(ctx *cli.Context) error {
func printNEP11Tokens(ctx *cli.Context) error { func printNEP11Tokens(ctx *cli.Context) error {
var err error var err error
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
tokenHash := ctx.Generic("token").(*flags.Address) tokenHash := ctx.Generic("token").(*flags.Address)
if !tokenHash.IsSet { if !tokenHash.IsSet {
return cli.NewExitError("token contract hash was not set", 1) return cli.NewExitError("token contract hash was not set", 1)
@ -409,6 +420,9 @@ func printNEP11Tokens(ctx *cli.Context) error {
func printNEP11Properties(ctx *cli.Context) error { func printNEP11Properties(ctx *cli.Context) error {
var err error var err error
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
tokenHash := ctx.Generic("token").(*flags.Address) tokenHash := ctx.Generic("token").(*flags.Address)
if !tokenHash.IsSet { if !tokenHash.IsSet {
return cli.NewExitError("token contract hash was not set", 1) return cli.NewExitError("token contract hash was not set", 1)

View file

@ -90,21 +90,21 @@ func newNEP17Commands() []cli.Command {
{ {
Name: "balance", Name: "balance",
Usage: "get address balance", Usage: "get address balance",
UsageText: "balance --wallet <path> --rpc-endpoint <node> [--timeout <time>] [--address <address>] [--token <hash-or-name>]", UsageText: "balance -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] [--address <address>] [--token <hash-or-name>]",
Action: getNEP17Balance, Action: getNEP17Balance,
Flags: balanceFlags, Flags: balanceFlags,
}, },
{ {
Name: "import", Name: "import",
Usage: "import NEP-17 token to a wallet", Usage: "import NEP-17 token to a wallet",
UsageText: "import --wallet <path> --rpc-endpoint <node> --timeout <time> --token <hash>", UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --token <hash>",
Action: importNEP17Token, Action: importNEP17Token,
Flags: importFlags, Flags: importFlags,
}, },
{ {
Name: "info", Name: "info",
Usage: "print imported NEP-17 token info", Usage: "print imported NEP-17 token info",
UsageText: "print --wallet <path> [--token <hash-or-name>]", UsageText: "print -w wallet [--wallet-config path] [--token <hash-or-name>]",
Action: printNEP17Info, Action: printNEP17Info,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
@ -115,7 +115,7 @@ func newNEP17Commands() []cli.Command {
{ {
Name: "remove", Name: "remove",
Usage: "remove NEP-17 token from the wallet", Usage: "remove NEP-17 token from the wallet",
UsageText: "remove --wallet <path> --token <hash-or-name>", UsageText: "remove -w wallet [--wallet-config path] --token <hash-or-name>",
Action: removeNEP17Token, Action: removeNEP17Token,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
@ -127,7 +127,7 @@ func newNEP17Commands() []cli.Command {
{ {
Name: "transfer", Name: "transfer",
Usage: "transfer NEP-17 tokens", Usage: "transfer NEP-17 tokens",
UsageText: "transfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]", UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
Action: transferNEP17, Action: transferNEP17,
Flags: transferFlags, Flags: transferFlags,
Description: `Transfers specified NEP-17 token amount with optional 'data' parameter and cosigners Description: `Transfers specified NEP-17 token amount with optional 'data' parameter and cosigners
@ -140,7 +140,7 @@ func newNEP17Commands() []cli.Command {
{ {
Name: "multitransfer", Name: "multitransfer",
Usage: "transfer NEP-17 tokens to multiple recipients", Usage: "transfer NEP-17 tokens to multiple recipients",
UsageText: `multitransfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr>` + UsageText: `multitransfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr>` +
` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]] [-- <cosigner1:Scope> [<cosigner2> [...]]]`, ` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]] [-- <cosigner1:Scope> [<cosigner2> [...]]]`,
Action: multiTransferNEP17, Action: multiTransferNEP17,
Flags: multiTransferFlags, Flags: multiTransferFlags,
@ -151,6 +151,9 @@ func newNEP17Commands() []cli.Command {
func getNEP17Balance(ctx *cli.Context) error { func getNEP17Balance(ctx *cli.Context) error {
var accounts []*wallet.Account var accounts []*wallet.Account
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, _, err := readWallet(ctx) wall, _, err := readWallet(ctx)
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("bad wallet: %w", err), 1) return cli.NewExitError(fmt.Errorf("bad wallet: %w", err), 1)
@ -349,6 +352,9 @@ func importNEP17Token(ctx *cli.Context) error {
} }
func importNEPToken(ctx *cli.Context, standard string) error { func importNEPToken(ctx *cli.Context, standard string) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, _, err := openWallet(ctx, true) wall, _, err := openWallet(ctx, true)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -411,6 +417,9 @@ func printNEP17Info(ctx *cli.Context) error {
} }
func printNEPInfo(ctx *cli.Context, standard string) error { func printNEPInfo(ctx *cli.Context, standard string) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, _, err := readWallet(ctx) wall, _, err := readWallet(ctx)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -443,6 +452,9 @@ func removeNEP17Token(ctx *cli.Context) error {
} }
func removeNEPToken(ctx *cli.Context, standard string) error { func removeNEPToken(ctx *cli.Context, standard string) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, _, err := openWallet(ctx, true) wall, _, err := openWallet(ctx, true)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)

View file

@ -3,6 +3,7 @@ package wallet
import ( import (
"fmt" "fmt"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input" "github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
@ -83,6 +84,9 @@ func handleUnregister(ctx *cli.Context) error {
} }
func handleCandidate(ctx *cli.Context, method string, sysGas int64) error { func handleCandidate(ctx *cli.Context, method string, sysGas int64) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, pass, err := readWallet(ctx) wall, pass, err := readWallet(ctx)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -138,6 +142,9 @@ func handleCandidate(ctx *cli.Context, method string, sysGas int64) error {
} }
func handleVote(ctx *cli.Context) error { func handleVote(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, pass, err := readWallet(ctx) wall, pass, err := readWallet(ctx)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)

View file

@ -9,6 +9,7 @@ import (
"os" "os"
"strings" "strings"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input" "github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
@ -109,15 +110,17 @@ func NewCommands() []cli.Command {
Usage: "create, open and manage a NEO wallet", Usage: "create, open and manage a NEO wallet",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Name: "claim", Name: "claim",
Usage: "claim GAS", Usage: "claim GAS",
Action: claimGas, UsageText: "neo-go wallet claim -w wallet [--wallet-config path] -a address -r endpoint [-s timeout]",
Flags: claimFlags, Action: claimGas,
Flags: claimFlags,
}, },
{ {
Name: "init", Name: "init",
Usage: "create a new wallet", Usage: "create a new wallet",
Action: createWallet, UsageText: "neo-go wallet init -w wallet [--wallet-config path] [-a]",
Action: createWallet,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
walletConfigFlag, walletConfigFlag,
@ -128,9 +131,10 @@ func NewCommands() []cli.Command {
}, },
}, },
{ {
Name: "change-password", Name: "change-password",
Usage: "change password for accounts", Usage: "change password for accounts",
Action: changePassword, UsageText: "neo-go wallet change-password -w wallet -a address",
Action: changePassword,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
flags.AddressFlag{ flags.AddressFlag{
@ -140,9 +144,10 @@ func NewCommands() []cli.Command {
}, },
}, },
{ {
Name: "convert", Name: "convert",
Usage: "convert addresses from existing NEO2 NEP6-wallet to NEO3 format", Usage: "convert addresses from existing NEO2 NEP6-wallet to NEO3 format",
Action: convertWallet, UsageText: "neo-go wallet convert -w legacywallet [--wallet-config path] -o n3wallet",
Action: convertWallet,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
walletConfigFlag, walletConfigFlag,
@ -153,18 +158,20 @@ func NewCommands() []cli.Command {
}, },
}, },
{ {
Name: "create", Name: "create",
Usage: "add an account to the existing wallet", Usage: "add an account to the existing wallet",
Action: addAccount, UsageText: "neo-go wallet create -w wallet [--wallet-config path]",
Action: addAccount,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
walletConfigFlag, walletConfigFlag,
}, },
}, },
{ {
Name: "dump", Name: "dump",
Usage: "check and dump an existing NEO wallet", Usage: "check and dump an existing NEO wallet",
Action: dumpWallet, UsageText: "neo-go wallet dump -w wallet [--wallet-config path] [-d]",
Action: dumpWallet,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
walletConfigFlag, walletConfigFlag,
@ -172,9 +179,10 @@ func NewCommands() []cli.Command {
}, },
}, },
{ {
Name: "dump-keys", Name: "dump-keys",
Usage: "dump public keys for account", Usage: "dump public keys for account",
Action: dumpKeys, UsageText: "neo-go wallet dump-keys -w wallet [--wallet-config path] [-a address]",
Action: dumpKeys,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
walletConfigFlag, walletConfigFlag,
@ -187,7 +195,7 @@ func NewCommands() []cli.Command {
{ {
Name: "export", Name: "export",
Usage: "export keys for address", Usage: "export keys for address",
UsageText: "export --wallet <path> [--decrypt] [<address>]", UsageText: "export -w wallet [--wallet-config path] [--decrypt] [<address>]",
Action: exportKeys, Action: exportKeys,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
@ -198,7 +206,7 @@ func NewCommands() []cli.Command {
{ {
Name: "import", Name: "import",
Usage: "import WIF of a standard signature contract", Usage: "import WIF of a standard signature contract",
UsageText: "import --wallet <path> --wif <wif> [--name <account_name>]", UsageText: "import -w wallet [--wallet-config path] --wif <wif> [--name <account_name>]",
Action: importWallet, Action: importWallet,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
@ -217,7 +225,7 @@ func NewCommands() []cli.Command {
{ {
Name: "import-multisig", Name: "import-multisig",
Usage: "import multisig contract", Usage: "import multisig contract",
UsageText: "import-multisig --wallet <path> --wif <wif> [--name <account_name>] --min <n>" + UsageText: "import-multisig -w wallet [--wallet-config path] --wif <wif> [--name <account_name>] --min <n>" +
" [<pubkey1> [<pubkey2> [...]]]", " [<pubkey1> [<pubkey2> [...]]]",
Action: importMultisig, Action: importMultisig,
Flags: []cli.Flag{ Flags: []cli.Flag{
@ -237,7 +245,7 @@ func NewCommands() []cli.Command {
{ {
Name: "import-deployed", Name: "import-deployed",
Usage: "import deployed contract", Usage: "import deployed contract",
UsageText: "import-deployed --wallet <path> --wif <wif> --contract <hash> [--name <account_name>]", UsageText: "import-deployed -w wallet [--wallet-config path] --wif <wif> --contract <hash> [--name <account_name>]",
Action: importDeployed, Action: importDeployed,
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
walletPathFlag, walletPathFlag,
@ -256,7 +264,7 @@ func NewCommands() []cli.Command {
{ {
Name: "remove", Name: "remove",
Usage: "remove an account from the wallet", Usage: "remove an account from the wallet",
UsageText: "remove --wallet <path> [--force] --address <addr>", UsageText: "remove -w wallet [--wallet-config path] [--force] --address <addr>",
Action: removeAccount, Action: removeAccount,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
@ -271,7 +279,7 @@ func NewCommands() []cli.Command {
{ {
Name: "sign", Name: "sign",
Usage: "cosign transaction with multisig/contract/additional account", Usage: "cosign transaction with multisig/contract/additional account",
UsageText: "sign --wallet <path> --address <address> --in <file.in> --out <file.out> [-r <endpoint>]", UsageText: "sign -w wallet [--wallet-config path] --address <address> --in <file.in> --out <file.out> [-r <endpoint>]",
Action: signStoredTransaction, Action: signStoredTransaction,
Flags: signFlags, Flags: signFlags,
}, },
@ -295,6 +303,9 @@ func NewCommands() []cli.Command {
} }
func claimGas(ctx *cli.Context) error { func claimGas(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, pass, err := readWallet(ctx) wall, pass, err := readWallet(ctx)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -332,6 +343,9 @@ func claimGas(ctx *cli.Context) error {
} }
func changePassword(ctx *cli.Context) error { func changePassword(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, _, err := openWallet(ctx, false) wall, _, err := openWallet(ctx, false)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -384,6 +398,9 @@ func changePassword(ctx *cli.Context) error {
} }
func convertWallet(ctx *cli.Context) error { func convertWallet(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, pass, err := newWalletV2FromFile(ctx.String("wallet"), ctx.String("wallet-config")) wall, pass, err := newWalletV2FromFile(ctx.String("wallet"), ctx.String("wallet-config"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -421,6 +438,9 @@ func convertWallet(ctx *cli.Context) error {
} }
func addAccount(ctx *cli.Context) error { func addAccount(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, pass, err := openWallet(ctx, true) wall, pass, err := openWallet(ctx, true)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -535,6 +555,9 @@ func importMultisig(ctx *cli.Context) error {
} }
func importDeployed(ctx *cli.Context) error { func importDeployed(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, _, err := openWallet(ctx, true) wall, _, err := openWallet(ctx, true)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -588,6 +611,9 @@ func importDeployed(ctx *cli.Context) error {
} }
func importWallet(ctx *cli.Context) error { func importWallet(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, _, err := openWallet(ctx, true) wall, _, err := openWallet(ctx, true)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -617,6 +643,9 @@ func importWallet(ctx *cli.Context) error {
} }
func removeAccount(ctx *cli.Context) error { func removeAccount(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, _, err := openWallet(ctx, true) wall, _, err := openWallet(ctx, true)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -660,6 +689,9 @@ func askForConsent(w io.Writer) bool {
} }
func dumpWallet(ctx *cli.Context) error { func dumpWallet(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, pass, err := readWallet(ctx) wall, pass, err := readWallet(ctx)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -685,6 +717,9 @@ func dumpWallet(ctx *cli.Context) error {
} }
func dumpKeys(ctx *cli.Context) error { func dumpKeys(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
wall, _, err := readWallet(ctx) wall, _, err := readWallet(ctx)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -732,6 +767,9 @@ func dumpKeys(ctx *cli.Context) error {
} }
func createWallet(ctx *cli.Context) error { func createWallet(ctx *cli.Context) error {
if err := cmdargs.EnsureNone(ctx); err != nil {
return err
}
path := ctx.String("wallet") path := ctx.String("wallet")
configPath := ctx.String("wallet-config") configPath := ctx.String("wallet-config")