From acde7bd0de09d8743f1d68da5419a746293b91e9 Mon Sep 17 00:00:00 2001 From: Ekaterina Pavlova Date: Tue, 9 Jul 2024 21:24:39 +0300 Subject: [PATCH] cli: upgrade urfave lib to v2 Close #3097 Signed-off-by: Ekaterina Pavlova --- cli/app/app.go | 2 +- cli/cmdargs/parser.go | 24 +- cli/flags/address.go | 72 ++++-- cli/flags/address_test.go | 91 +++++++- cli/flags/fixed8.go | 76 ++++-- cli/flags/fixed8_test.go | 70 +++++- cli/flags/util.go | 11 - cli/flags/util_test.go | 17 -- cli/nep_test/nep17_test.go | 3 +- cli/options/cli_options_test.go | 2 +- cli/options/options.go | 82 ++++--- cli/options/options_test.go | 2 +- cli/query/query.go | 61 ++--- cli/server/server.go | 109 ++++----- cli/server/server_test.go | 2 +- cli/smartcontract/generate.go | 37 +-- cli/smartcontract/generate_test.go | 10 +- cli/smartcontract/manifest.go | 14 +- cli/smartcontract/smart_contract.go | 279 ++++++++++++----------- cli/smartcontract/smart_contract_test.go | 2 +- cli/txctx/tx.go | 30 +-- cli/util/cancel.go | 28 +-- cli/util/convert.go | 42 ++-- cli/util/dump.go | 20 +- cli/util/send.go | 18 +- cli/vm/cli.go | 63 ++--- cli/vm/cli_test.go | 6 +- cli/vm/vm.go | 10 +- cli/wallet/multisig.go | 28 +-- cli/wallet/nep11.go | 42 ++-- cli/wallet/nep17.go | 99 ++++---- cli/wallet/validator.go | 44 ++-- cli/wallet/wallet.go | 242 +++++++++++--------- cli/wallet/wallet_test.go | 2 +- go.mod | 5 +- go.sum | 15 +- internal/testcli/executor.go | 2 +- scripts/compare-dumps/compare-dumps.go | 2 +- scripts/compare-states/compare-states.go | 9 +- 39 files changed, 980 insertions(+), 693 deletions(-) delete mode 100644 cli/flags/util.go delete mode 100644 cli/flags/util_test.go diff --git a/cli/app/app.go b/cli/app/app.go index c62b5e42d..aaee0d0e4 100644 --- a/cli/app/app.go +++ b/cli/app/app.go @@ -12,7 +12,7 @@ import ( "github.com/nspcc-dev/neo-go/cli/vm" "github.com/nspcc-dev/neo-go/cli/wallet" "github.com/nspcc-dev/neo-go/pkg/config" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func versionPrinter(c *cli.Context) { diff --git a/cli/cmdargs/parser.go b/cli/cmdargs/parser.go index cb46971dd..83e41c7ac 100644 --- a/cli/cmdargs/parser.go +++ b/cli/cmdargs/parser.go @@ -12,7 +12,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/wallet" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) const ( @@ -138,16 +138,16 @@ const ( // GetSignersFromContext returns signers parsed from context args starting // from the specified offset. -func GetSignersFromContext(ctx *cli.Context, offset int) ([]transaction.Signer, *cli.ExitError) { +func GetSignersFromContext(ctx *cli.Context, offset int) ([]transaction.Signer, cli.ExitCoder) { args := ctx.Args() var ( signers []transaction.Signer err error ) - if args.Present() && len(args) > offset { - signers, err = ParseSigners(args[offset:]) + if args.Present() && args.Len() > offset { + signers, err = ParseSigners(args.Slice()[offset:]) if err != nil { - return nil, cli.NewExitError(err, 1) + return nil, cli.Exit(err, 1) } } return signers, nil @@ -230,7 +230,7 @@ func parseCosigner(c string) (transaction.Signer, error) { } // GetDataFromContext returns data parameter from context args. -func GetDataFromContext(ctx *cli.Context) (int, any, *cli.ExitError) { +func GetDataFromContext(ctx *cli.Context) (int, any, cli.ExitCoder) { var ( data any offset int @@ -239,17 +239,17 @@ func GetDataFromContext(ctx *cli.Context) (int, any, *cli.ExitError) { ) args := ctx.Args() if args.Present() { - offset, params, err = ParseParams(args, true) + offset, params, err = ParseParams(args.Slice(), true) if err != nil { - return offset, nil, cli.NewExitError(fmt.Errorf("unable to parse 'data' parameter: %w", err), 1) + return offset, nil, cli.Exit(fmt.Errorf("unable to parse 'data' parameter: %w", err), 1) } if len(params) > 1 { - return offset, nil, cli.NewExitError("'data' should be represented as a single parameter", 1) + return offset, nil, cli.Exit("'data' should be represented as a single parameter", 1) } if len(params) != 0 { data, err = smartcontract.ExpandParameterToEmitable(params[0]) if err != nil { - return offset, nil, cli.NewExitError(fmt.Sprintf("failed to convert 'data' to emitable type: %s", err.Error()), 1) + return offset, nil, cli.Exit(fmt.Sprintf("failed to convert 'data' to emitable type: %s", err.Error()), 1) } } } @@ -258,9 +258,9 @@ func GetDataFromContext(ctx *cli.Context) (int, any, *cli.ExitError) { // 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 { +func EnsureNone(ctx *cli.Context) cli.ExitCoder { if ctx.Args().Present() { - return cli.NewExitError("additional arguments given while this command expects none", 1) + return cli.Exit(fmt.Errorf("additional arguments given while this command expects none"), 1) } return nil } diff --git a/cli/flags/address.go b/cli/flags/address.go index f20e9948f..dc62cf088 100644 --- a/cli/flags/address.go +++ b/cli/flags/address.go @@ -7,7 +7,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // Address is a wrapper for a Uint160 with flag.Value methods. @@ -16,11 +16,15 @@ type Address struct { Value util.Uint160 } -// AddressFlag is a flag with type string. +// AddressFlag is a flag with type Uint160. type AddressFlag struct { - Name string - Usage string - Value Address + Name string + Usage string + Value Address + Aliases []string + Required bool + Hidden bool + Action func(*cli.Context, string) error } var ( @@ -37,7 +41,7 @@ func (a Address) String() string { func (a *Address) Set(s string) error { addr, err := ParseAddress(s) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } a.IsSet = true a.Value = addr @@ -63,9 +67,9 @@ func (f AddressFlag) IsSet() bool { // (for usage defaults). func (f AddressFlag) String() string { var names []string - eachName(f.Name, func(name string) { + for _, name := range f.Names() { names = append(names, getNameHelp(name)) - }) + } return strings.Join(names, ", ") + "\t" + f.Usage } @@ -77,17 +81,57 @@ func getNameHelp(name string) string { return fmt.Sprintf("--%s value", name) } -// GetName returns the name of the flag. -func (f AddressFlag) GetName() string { - return f.Name +// Names returns the names of the flag. +func (f AddressFlag) Names() []string { + return cli.FlagNames(f.Name, f.Aliases) +} + +// IsRequired returns whether the flag is required. +func (f AddressFlag) IsRequired() bool { + return f.Required +} + +// IsVisible returns true if the flag is not hidden, otherwise false. +func (f AddressFlag) IsVisible() bool { + return !f.Hidden +} + +// TakesValue returns true of the flag takes a value, otherwise false. +func (f AddressFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag. +func (f AddressFlag) GetUsage() string { + return f.Usage } // Apply populates the flag given the flag set and environment. // Ignores errors. -func (f AddressFlag) Apply(set *flag.FlagSet) { - eachName(f.Name, func(name string) { +func (f AddressFlag) Apply(set *flag.FlagSet) error { + for _, name := range f.Names() { set.Var(&f.Value, name, f.Usage) - }) + } + return nil +} + +// RunAction executes flag action if set. +func (f AddressFlag) RunAction(c *cli.Context) error { + if f.Action != nil { + return f.Action(c, address.Uint160ToString(f.Value.Value)) + } + return nil +} + +// GetValue returns the flags value as string representation. +func (f AddressFlag) GetValue() string { + return address.Uint160ToString(f.Value.Value) +} + +// Get returns the flag’s value in the given Context. +func (f AddressFlag) Get(ctx *cli.Context) Address { + adr := ctx.Generic(f.Name).(*Address) + return *adr } // ParseAddress parses a Uint160 from either an LE string or an address. diff --git a/cli/flags/address_test.go b/cli/flags/address_test.go index 1409720b9..349c74df2 100644 --- a/cli/flags/address_test.go +++ b/cli/flags/address_test.go @@ -9,6 +9,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/stretchr/testify/require" + "github.com/urfave/cli/v2" ) func TestParseAddress(t *testing.T) { @@ -109,22 +110,102 @@ func TestAddress_getNameHelp(t *testing.T) { require.Equal(t, "--flag value", getNameHelp("flag")) } -func TestAddressFlag_GetName(t *testing.T) { +func TestAddressFlag_Names(t *testing.T) { flag := AddressFlag{ - Name: "my flag", + Name: "flag", + Aliases: []string{"my"}, } - require.Equal(t, "my flag", flag.GetName()) + require.Equal(t, []string{"flag", "my"}, flag.Names()) } func TestAddress(t *testing.T) { f := flag.NewFlagSet("", flag.ContinueOnError) f.SetOutput(io.Discard) // don't pollute test output - addr := AddressFlag{Name: "addr, a"} - addr.Apply(f) + addr := AddressFlag{Name: "addr", Aliases: []string{"a"}} + err := addr.Apply(f) + require.NoError(t, err) require.NoError(t, f.Parse([]string{"--addr", "NRHkiY2hLy5ypD32CKZtL6pNwhbFMqDEhR"})) require.Equal(t, "NRHkiY2hLy5ypD32CKZtL6pNwhbFMqDEhR", f.Lookup("a").Value.String()) require.NoError(t, f.Parse([]string{"-a", "NRHkiY2hLy5ypD32CKZtL6pNwhbFMqDEhR"})) require.Equal(t, "NRHkiY2hLy5ypD32CKZtL6pNwhbFMqDEhR", f.Lookup("a").Value.String()) require.Error(t, f.Parse([]string{"--addr", "kek"})) } + +func TestAddressFlag_IsRequired(t *testing.T) { + flag := AddressFlag{Required: true} + require.True(t, flag.IsRequired()) + + flag.Required = false + require.False(t, flag.IsRequired()) +} + +func TestAddressFlag_IsVisible(t *testing.T) { + flag := AddressFlag{Hidden: false} + require.True(t, flag.IsVisible()) + + flag.Hidden = true + require.False(t, flag.IsVisible()) +} + +func TestAddressFlag_TakesValue(t *testing.T) { + flag := AddressFlag{} + require.True(t, flag.TakesValue()) +} + +func TestAddressFlag_GetUsage(t *testing.T) { + flag := AddressFlag{Usage: "Specify the address"} + require.Equal(t, "Specify the address", flag.GetUsage()) +} + +func TestAddressFlag_GetValue(t *testing.T) { + addrValue := util.Uint160{1, 2, 3} + flag := AddressFlag{Value: Address{IsSet: true, Value: addrValue}} + expectedStr := address.Uint160ToString(addrValue) + require.Equal(t, expectedStr, flag.GetValue()) +} + +func TestAddressFlag_Get(t *testing.T) { + app := cli.NewApp() + set := flag.NewFlagSet("test", flag.ContinueOnError) + ctx := cli.NewContext(app, set, nil) + + flag := AddressFlag{ + Name: "testAddress", + Value: Address{Value: util.Uint160{1, 2, 3}, IsSet: false}, + } + + set.Var(&flag.Value, "testAddress", "test usage") + require.NoError(t, set.Set("testAddress", address.Uint160ToString(util.Uint160{3, 2, 1}))) + + expected := flag.Get(ctx) + require.True(t, expected.IsSet) + require.Equal(t, util.Uint160{3, 2, 1}, expected.Value) +} + +func TestAddressFlag_RunAction(t *testing.T) { + called := false + action := func(ctx *cli.Context, s string) error { + called = true + require.Equal(t, address.Uint160ToString(util.Uint160{1, 2, 3}), s) + return nil + } + + app := cli.NewApp() + set := flag.NewFlagSet("test", flag.ContinueOnError) + ctx := cli.NewContext(app, set, nil) + + flag := AddressFlag{ + Action: action, + Value: Address{IsSet: true, Value: util.Uint160{4, 5, 6}}, + } + + expected := address.Uint160ToString(util.Uint160{1, 2, 3}) + set.Var(&flag.Value, "testAddress", "test usage") + require.NoError(t, set.Set("testAddress", expected)) + require.Equal(t, expected, flag.GetValue()) + + err := flag.RunAction(ctx) + require.NoError(t, err) + require.True(t, called) +} diff --git a/cli/flags/fixed8.go b/cli/flags/fixed8.go index fcb07dea5..7b7fd3899 100644 --- a/cli/flags/fixed8.go +++ b/cli/flags/fixed8.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // Fixed8 is a wrapper for a Uint160 with flag.Value methods. @@ -15,9 +15,13 @@ type Fixed8 struct { // Fixed8Flag is a flag with type string. type Fixed8Flag struct { - Name string - Usage string - Value Fixed8 + Name string + Usage string + Value Fixed8 + Aliases []string + Required bool + Hidden bool + Action func(*cli.Context, string) error } var ( @@ -34,7 +38,7 @@ func (a Fixed8) String() string { func (a *Fixed8) Set(s string) error { f, err := fixedn.Fixed8FromString(s) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } a.Value = f return nil @@ -45,31 +49,75 @@ func (a *Fixed8) Fixed8() fixedn.Fixed8 { return a.Value } +// IsSet checks if flag was set to a non-default value. +func (f Fixed8Flag) IsSet() bool { + return f.Value.Value != 0 +} + // String returns a readable representation of this value // (for usage defaults). func (f Fixed8Flag) String() string { var names []string - eachName(f.Name, func(name string) { + for _, name := range f.Names() { names = append(names, getNameHelp(name)) - }) - + } return strings.Join(names, ", ") + "\t" + f.Usage } -// GetName returns the name of the flag. -func (f Fixed8Flag) GetName() string { - return f.Name +// Names returns the names of the flag. +func (f Fixed8Flag) Names() []string { + return cli.FlagNames(f.Name, f.Aliases) +} + +// IsRequired returns whether the flag is required. +func (f Fixed8Flag) IsRequired() bool { + return f.Required +} + +// IsVisible returns true if the flag is not hidden, otherwise false. +func (f Fixed8Flag) IsVisible() bool { + return !f.Hidden +} + +// TakesValue returns true if the flag takes a value, otherwise false. +func (f Fixed8Flag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag. +func (f Fixed8Flag) GetUsage() string { + return f.Usage } // Apply populates the flag given the flag set and environment. // Ignores errors. -func (f Fixed8Flag) Apply(set *flag.FlagSet) { - eachName(f.Name, func(name string) { +func (f Fixed8Flag) Apply(set *flag.FlagSet) error { + for _, name := range f.Names() { set.Var(&f.Value, name, f.Usage) - }) + } + return nil } // Fixed8FromContext returns a parsed util.Fixed8 value provided flag name. func Fixed8FromContext(ctx *cli.Context, name string) fixedn.Fixed8 { return ctx.Generic(name).(*Fixed8).Value } + +// RunAction executes flag action if set. +func (f Fixed8Flag) RunAction(c *cli.Context) error { + if f.Action != nil { + return f.Action(c, f.Value.Value.String()) + } + return nil +} + +// GetValue returns the flags value as string representation. +func (f Fixed8Flag) GetValue() string { + return f.Value.Value.String() +} + +// Get returns the flag’s value in the given Context. +func (f Fixed8Flag) Get(ctx *cli.Context) Fixed8 { + adr := ctx.Generic(f.Name).(*Fixed8) + return *adr +} diff --git a/cli/flags/fixed8_test.go b/cli/flags/fixed8_test.go index 1630696ef..d42a82b38 100644 --- a/cli/flags/fixed8_test.go +++ b/cli/flags/fixed8_test.go @@ -7,6 +7,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/stretchr/testify/require" + "github.com/urfave/cli/v2" ) func TestFixed8_String(t *testing.T) { @@ -45,22 +46,83 @@ func TestFixed8Flag_String(t *testing.T) { require.Equal(t, "--myFlag value\tGas amount", flag.String()) } -func TestFixed8Flag_GetName(t *testing.T) { +func TestFixed8Flag_Names(t *testing.T) { flag := Fixed8Flag{ Name: "myFlag", } - require.Equal(t, "myFlag", flag.GetName()) + require.Equal(t, []string{"myFlag"}, flag.Names()) } func TestFixed8(t *testing.T) { f := flag.NewFlagSet("", flag.ContinueOnError) f.SetOutput(io.Discard) // don't pollute test output - gas := Fixed8Flag{Name: "gas, g"} - gas.Apply(f) + gas := Fixed8Flag{Name: "gas", Aliases: []string{"g"}, Usage: "Gas amount", Value: Fixed8{Value: 0}, Required: true, Hidden: false, Action: nil} + err := gas.Apply(f) + require.NoError(t, err) require.NoError(t, f.Parse([]string{"--gas", "0.123"})) require.Equal(t, "0.123", f.Lookup("g").Value.String()) require.NoError(t, f.Parse([]string{"-g", "0.456"})) require.Equal(t, "0.456", f.Lookup("g").Value.String()) require.Error(t, f.Parse([]string{"--gas", "kek"})) } + +func TestFixed8Flag_Get(t *testing.T) { + app := cli.NewApp() + set := flag.NewFlagSet("test", flag.ContinueOnError) + ctx := cli.NewContext(app, set, nil) + flag := Fixed8Flag{ + Name: "testFlag", + } + fixedFlag := Fixed8{Value: fixedn.Fixed8(123)} + set.Var(&fixedFlag, "testFlag", "test usage") + require.NoError(t, set.Set("testFlag", "0.00000321")) + expected := flag.Get(ctx) + require.Equal(t, fixedn.Fixed8(321), expected.Value) +} + +func TestFixed8Flag_GetValue(t *testing.T) { + f := Fixed8Flag{Value: Fixed8{Value: fixedn.Fixed8(123)}} + require.Equal(t, "0.00000123", f.GetValue()) + require.True(t, f.TakesValue()) +} + +func TestFixed8Flag_RunAction(t *testing.T) { + called := false + action := func(ctx *cli.Context, s string) error { + called = true + require.Equal(t, "0.00000123", s) + return nil + } + app := cli.NewApp() + set := flag.NewFlagSet("test", flag.ContinueOnError) + ctx := cli.NewContext(app, set, nil) + f := Fixed8Flag{ + Action: action, + Value: Fixed8{Value: fixedn.Fixed8(123)}, + } + err := f.RunAction(ctx) + require.NoError(t, err) + require.True(t, called) +} + +func TestFixed8Flag_GetUsage(t *testing.T) { + f := Fixed8Flag{Usage: "Use this flag to specify gas amount"} + require.Equal(t, "Use this flag to specify gas amount", f.GetUsage()) +} + +func TestFixed8Flag_IsVisible(t *testing.T) { + f := Fixed8Flag{Hidden: false} + require.True(t, f.IsVisible()) + + f.Hidden = true + require.False(t, f.IsVisible()) +} + +func TestFixed8Flag_IsRequired(t *testing.T) { + f := Fixed8Flag{Required: false} + require.False(t, f.IsRequired()) + + f.Required = true + require.True(t, f.IsRequired()) +} diff --git a/cli/flags/util.go b/cli/flags/util.go deleted file mode 100644 index 6b215b5e2..000000000 --- a/cli/flags/util.go +++ /dev/null @@ -1,11 +0,0 @@ -package flags - -import "strings" - -func eachName(longName string, fn func(string)) { - parts := strings.Split(longName, ",") - for _, name := range parts { - name = strings.Trim(name, " ") - fn(name) - } -} diff --git a/cli/flags/util_test.go b/cli/flags/util_test.go deleted file mode 100644 index fb47b697f..000000000 --- a/cli/flags/util_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package flags - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestEachName(t *testing.T) { - expected := "*one*two*three" - actual := "" - - eachName(" one,two ,three", func(s string) { - actual += "*" + s - }) - require.Equal(t, expected, actual) -} diff --git a/cli/nep_test/nep17_test.go b/cli/nep_test/nep17_test.go index f934c5d8d..a7f037190 100644 --- a/cli/nep_test/nep17_test.go +++ b/cli/nep_test/nep17_test.go @@ -21,14 +21,13 @@ func TestNEP17Balance(t *testing.T) { e := testcli.NewExecutor(t, true) args := []string{ - "neo-go", "wallet", "nep17", "multitransfer", + "neo-go", "wallet", "nep17", "multitransfer", "--force", "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--from", testcli.ValidatorAddr, "GAS:" + testcli.TestWalletMultiAccount1 + ":1", "NEO:" + testcli.TestWalletMultiAccount1 + ":10", "GAS:" + testcli.TestWalletMultiAccount3 + ":3", - "--force", } e.In.WriteString("one\r") e.Run(t, args...) diff --git a/cli/options/cli_options_test.go b/cli/options/cli_options_test.go index 5ba67a24d..4cf9977a5 100644 --- a/cli/options/cli_options_test.go +++ b/cli/options/cli_options_test.go @@ -8,7 +8,7 @@ import ( "github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/internal/testcli" "github.com/stretchr/testify/require" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func TestGetRPCClient(t *testing.T) { diff --git a/cli/options/options.go b/cli/options/options.go index 57856d059..e20365f4a 100644 --- a/cli/options/options.go +++ b/cli/options/options.go @@ -26,7 +26,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/wallet" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" "go.uber.org/zap" "go.uber.org/zap/zapcore" "golang.org/x/term" @@ -47,66 +47,88 @@ const ( const RPCEndpointFlag = "rpc-endpoint" // Wallet is a set of flags used for wallet operations. -var Wallet = []cli.Flag{cli.StringFlag{ - Name: "wallet, w", - Usage: "Wallet to use to get the key for transaction signing; conflicts with --wallet-config flag", -}, cli.StringFlag{ - Name: "wallet-config", - Usage: "Path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag"}, +var Wallet = []cli.Flag{ + &cli.StringFlag{ + Name: "wallet", + Aliases: []string{"w"}, + Usage: "Wallet to use to get the key for transaction signing; conflicts with --wallet-config flag", + }, + &cli.StringFlag{ + Name: "wallet-config", + Usage: "Path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag", + }, } // Network is a set of flags for choosing the network to operate on // (privnet/mainnet/testnet). var Network = []cli.Flag{ - cli.BoolFlag{Name: "privnet, p", Usage: "Use private network configuration (if --config-file option is not specified)"}, - cli.BoolFlag{Name: "mainnet, m", Usage: "Use mainnet network configuration (if --config-file option is not specified)"}, - cli.BoolFlag{Name: "testnet, t", Usage: "Use testnet network configuration (if --config-file option is not specified)"}, - cli.BoolFlag{Name: "unittest", Hidden: true}, + &cli.BoolFlag{ + Name: "privnet", + Aliases: []string{"p"}, + Usage: "Use private network configuration (if --config-file option is not specified)", + }, + &cli.BoolFlag{ + Name: "mainnet", + Aliases: []string{"m"}, + Usage: "Use mainnet network configuration (if --config-file option is not specified)", + }, + &cli.BoolFlag{ + Name: "testnet", + Aliases: []string{"t"}, + Usage: "Use testnet network configuration (if --config-file option is not specified)", + }, + &cli.BoolFlag{ + Name: "unittest", + Hidden: true, + }, } // RPC is a set of flags used for RPC connections (endpoint and timeout). var RPC = []cli.Flag{ - cli.StringFlag{ - Name: RPCEndpointFlag + ", r", - Usage: "RPC node address", + &cli.StringFlag{ + Name: RPCEndpointFlag, + Aliases: []string{"r"}, + Usage: "RPC node address", }, - cli.DurationFlag{ - Name: "timeout, s", - Value: DefaultTimeout, - Usage: "Timeout for the operation", + &cli.DurationFlag{ + Name: "timeout", + Aliases: []string{"s"}, + Value: DefaultTimeout, + Usage: "Timeout for the operation", }, } // Historic is a flag for commands that can perform historic invocations. -var Historic = cli.StringFlag{ +var Historic = &cli.StringFlag{ Name: "historic", Usage: "Use historic state (height, block hash or state root hash)", } // Config is a flag for commands that use node configuration. -var Config = cli.StringFlag{ +var Config = &cli.StringFlag{ Name: "config-path", Usage: "Path to directory with per-network configuration files (may be overridden by --config-file option for the configuration file)", } // ConfigFile is a flag for commands that use node configuration and provide // path to the specific config file instead of config path. -var ConfigFile = cli.StringFlag{ +var ConfigFile = &cli.StringFlag{ Name: "config-file", Usage: "Path to the node configuration file (overrides --config-path option)", } // RelativePath is a flag for commands that use node configuration and provide // a prefix to all relative paths in config files. -var RelativePath = cli.StringFlag{ +var RelativePath = &cli.StringFlag{ Name: "relative-path", Usage: "Prefix to all relative paths in the node configuration file", } // Debug is a flag for commands that allow node in debug mode usage. -var Debug = cli.BoolFlag{ - Name: "debug, d", - Usage: "Enable debug logging (LOTS of output, overrides configuration)", +var Debug = &cli.BoolFlag{ + Name: "debug", + Aliases: []string{"d"}, + Usage: "Enable debug logging (LOTS of output, overrides configuration)", } var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'") @@ -146,15 +168,15 @@ func GetTimeoutContext(ctx *cli.Context) (context.Context, func()) { func GetRPCClient(gctx context.Context, ctx *cli.Context) (*rpcclient.Client, cli.ExitCoder) { endpoint := ctx.String(RPCEndpointFlag) if len(endpoint) == 0 { - return nil, cli.NewExitError(errNoEndpoint, 1) + return nil, cli.Exit(errNoEndpoint, 1) } c, err := rpcclient.New(gctx, endpoint, rpcclient.Options{}) if err != nil { - return nil, cli.NewExitError(err, 1) + return nil, cli.Exit(err, 1) } err = c.Init() if err != nil { - return nil, cli.NewExitError(err, 1) + return nil, cli.Exit(err, 1) } return c, nil } @@ -173,7 +195,7 @@ func GetInvoker(c *rpcclient.Client, ctx *cli.Context, signers []transaction.Sig // Might as well be a block hash, but it makes no practical difference. return invoker.NewHistoricWithState(u256, c, signers), nil } - return nil, cli.NewExitError(errInvalidHistoric, 1) + return nil, cli.Exit(errInvalidHistoric, 1) } // GetRPCWithInvoker combines GetRPCClient with GetInvoker for cases where it's @@ -314,7 +336,7 @@ func GetRPCWithActor(gctx context.Context, ctx *cli.Context, signers []actor.Sig a, actorErr := actor.New(c, signers) if actorErr != nil { c.Close() - return nil, nil, cli.NewExitError(fmt.Errorf("failed to create Actor: %w", actorErr), 1) + return nil, nil, cli.Exit(fmt.Errorf("failed to create Actor: %w", actorErr), 1) } return c, a, nil } diff --git a/cli/options/options_test.go b/cli/options/options_test.go index 22ded55d6..649d9b26e 100644 --- a/cli/options/options_test.go +++ b/cli/options/options_test.go @@ -8,7 +8,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/stretchr/testify/require" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func TestGetNetwork(t *testing.T) { diff --git a/cli/query/query.go b/cli/query/query.go index 5a63ebf32..50787b782 100644 --- a/cli/query/query.go +++ b/cli/query/query.go @@ -22,21 +22,22 @@ import ( "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm/vmstate" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // NewCommands returns 'query' command. -func NewCommands() []cli.Command { +func NewCommands() []*cli.Command { queryTxFlags := append([]cli.Flag{ - cli.BoolFlag{ - Name: "verbose, v", - Usage: "Output full tx info and execution logs", + &cli.BoolFlag{ + Name: "verbose", + Aliases: []string{"v"}, + Usage: "Output full tx info and execution logs", }, }, options.RPC...) - return []cli.Command{{ + return []*cli.Command{{ Name: "query", Usage: "Query data from RPC node", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "candidates", Usage: "Get candidates and votes", @@ -61,14 +62,14 @@ func NewCommands() []cli.Command { { Name: "tx", Usage: "Query transaction status", - UsageText: "neo-go query tx -r endpoint [-s timeout] [-v]", + UsageText: "neo-go query tx -r endpoint [-s timeout] [-v] ", Action: queryTx, Flags: queryTxFlags, }, { Name: "voter", Usage: "Print NEO holder account state", - UsageText: "neo-go query voter
-r endpoint [-s timeout]", + UsageText: "neo-go query voter -r endpoint [-s timeout]
", Action: queryVoter, Flags: options.RPC, }, @@ -77,16 +78,16 @@ func NewCommands() []cli.Command { } func queryTx(ctx *cli.Context) error { - args := ctx.Args() + args := ctx.Args().Slice() if len(args) == 0 { - return cli.NewExitError("Transaction hash is missing", 1) + return cli.Exit("Transaction hash is missing", 1) } else if len(args) > 1 { - return cli.NewExitError("only one transaction hash is accepted", 1) + return cli.Exit("only one transaction hash is accepted", 1) } txHash, err := util.Uint256DecodeStringLE(strings.TrimPrefix(args[0], "0x")) if err != nil { - return cli.NewExitError(fmt.Sprintf("Invalid tx hash: %s", args[0]), 1) + return cli.Exit(fmt.Sprintf("Invalid tx hash: %s", args[0]), 1) } gctx, cancel := options.GetTimeoutContext(ctx) @@ -94,25 +95,25 @@ func queryTx(ctx *cli.Context) error { c, err := options.GetRPCClient(gctx, ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } txOut, err := c.GetRawTransactionVerbose(txHash) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } var res *result.ApplicationLog if !txOut.Blockhash.Equals(util.Uint256{}) { res, err = c.GetApplicationLog(txHash, nil) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } } err = DumpApplicationLog(ctx, res, &txOut.Transaction, &txOut.TransactionMetadata, ctx.Bool("verbose")) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } return nil } @@ -179,16 +180,16 @@ func queryCandidates(ctx *cli.Context) error { c, err := options.GetRPCClient(gctx, ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } vals, err := c.GetCandidates() if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } comm, err := c.GetCommittee() if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } sort.Slice(vals, func(i, j int) bool { @@ -225,12 +226,12 @@ func queryCommittee(ctx *cli.Context) error { c, err := options.GetRPCClient(gctx, ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } comm, err := c.GetCommittee() if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } for _, k := range comm { @@ -251,12 +252,12 @@ func queryHeight(ctx *cli.Context) error { c, err := options.GetRPCClient(gctx, ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } blockCount, err := c.GetBlockCount() if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } blockHeight := blockCount - 1 // GetBlockCount returns block count (including 0), not the highest block index. @@ -271,16 +272,16 @@ func queryHeight(ctx *cli.Context) error { } func queryVoter(ctx *cli.Context) error { - args := ctx.Args() + args := ctx.Args().Slice() if len(args) == 0 { - return cli.NewExitError("No address specified", 1) + return cli.Exit("No address specified", 1) } else if len(args) > 1 { - return cli.NewExitError("this command only accepts one address", 1) + return cli.Exit("this command only accepts one address", 1) } addr, err := flags.ParseAddress(args[0]) if err != nil { - return cli.NewExitError(fmt.Sprintf("wrong address: %s", args[0]), 1) + return cli.Exit(fmt.Sprintf("wrong address: %s", args[0]), 1) } gctx, cancel := options.GetTimeoutContext(ctx) @@ -294,14 +295,14 @@ func queryVoter(ctx *cli.Context) error { st, err := neoToken.GetAccountState(addr) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if st == nil { st = new(state.NEOBalance) } dec, err := neoToken.Decimals() if err != nil { - return cli.NewExitError(fmt.Errorf("failed to get decimals: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to get decimals: %w", err), 1) } voted := "null" if st.VoteTo != nil { diff --git a/cli/server/server.go b/cli/server/server.go index 382e25e13..5d2a50ae9 100644 --- a/cli/server/server.go +++ b/cli/server/server.go @@ -27,13 +27,13 @@ import ( "github.com/nspcc-dev/neo-go/pkg/services/oracle" "github.com/nspcc-dev/neo-go/pkg/services/rpcsrv" "github.com/nspcc-dev/neo-go/pkg/services/stateroot" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) // NewCommands returns 'node' command. -func NewCommands() []cli.Command { +func NewCommands() []*cli.Command { cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath} cfgFlags = append(cfgFlags, options.Network...) var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags)) @@ -41,47 +41,52 @@ func NewCommands() []cli.Command { cfgFlags = append(cfgFlags, options.Debug) cfgWithCountFlags = append(cfgWithCountFlags, - cli.UintFlag{ - Name: "count, c", - Usage: "Number of blocks to be processed (default or 0: all chain)", + &cli.UintFlag{ + Name: "count", + Aliases: []string{"c"}, + Usage: "Number of blocks to be processed (default or 0: all chain)", }, ) var cfgCountOutFlags = make([]cli.Flag, len(cfgWithCountFlags)) copy(cfgCountOutFlags, cfgWithCountFlags) cfgCountOutFlags = append(cfgCountOutFlags, - cli.UintFlag{ - Name: "start, s", - Usage: "Block number to start from (default: 0)", + &cli.UintFlag{ + Name: "start", + Aliases: []string{"s"}, + Usage: "Block number to start from", }, - cli.StringFlag{ - Name: "out, o", - Usage: "Output file (stdout if not given)", + &cli.StringFlag{ + Name: "out", + Aliases: []string{"o"}, + Usage: "Output file (stdout if not given)", }, ) var cfgCountInFlags = make([]cli.Flag, len(cfgWithCountFlags)) copy(cfgCountInFlags, cfgWithCountFlags) cfgCountInFlags = append(cfgCountInFlags, - cli.StringFlag{ - Name: "in, i", - Usage: "Input file (stdin if not given)", + &cli.StringFlag{ + Name: "in", + Aliases: []string{"i"}, + Usage: "Input file (stdin if not given)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "dump", Usage: "Directory for storing JSON dumps", }, - cli.BoolFlag{ - Name: "incremental, n", - Usage: "Use if dump is incremental", + &cli.BoolFlag{ + Name: "incremental", + Aliases: []string{"n"}, + Usage: "Use if dump is incremental", }, ) var cfgHeightFlags = make([]cli.Flag, len(cfgFlags)+1) copy(cfgHeightFlags, cfgFlags) - cfgHeightFlags[len(cfgHeightFlags)-1] = cli.UintFlag{ + cfgHeightFlags[len(cfgHeightFlags)-1] = &cli.UintFlag{ Name: "height", Usage: "Height of the state to reset DB to", Required: true, } - return []cli.Command{ + return []*cli.Command{ { Name: "node", Usage: "Start a NeoGo node", @@ -92,7 +97,7 @@ func NewCommands() []cli.Command { { Name: "db", Usage: "Database manipulations", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "dump", Usage: "Dump blocks (starting with block #1) to the file", @@ -134,7 +139,7 @@ func newGraceContext() context.Context { func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *metrics.Service, *metrics.Service, error) { chain, _, err := initBlockChain(cfg, log) if err != nil { - return nil, nil, nil, cli.NewExitError(err, 1) + return nil, nil, nil, cli.Exit(err, 1) } prometheus := metrics.NewPrometheusService(cfg.ApplicationConfiguration.Prometheus, log) pprof := metrics.NewPprofService(cfg.ApplicationConfiguration.Pprof, log) @@ -142,11 +147,11 @@ func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *m go chain.Run() err = prometheus.Start() if err != nil { - return nil, nil, nil, cli.NewExitError(fmt.Errorf("failed to start Prometheus service: %w", err), 1) + return nil, nil, nil, cli.Exit(fmt.Errorf("failed to start Prometheus service: %w", err), 1) } err = pprof.Start() if err != nil { - return nil, nil, nil, cli.NewExitError(fmt.Errorf("failed to start Pprof service: %w", err), 1) + return nil, nil, nil, cli.Exit(fmt.Errorf("failed to start Pprof service: %w", err), 1) } return chain, prometheus, pprof, nil @@ -158,11 +163,11 @@ func dumpDB(ctx *cli.Context) error { } cfg, err := options.GetConfigFromContext(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if logCloser != nil { defer func() { _ = logCloser() }() @@ -174,7 +179,7 @@ func dumpDB(ctx *cli.Context) error { if out := ctx.String("out"); out != "" { outStream, err = os.Create(out) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } } defer outStream.Close() @@ -192,7 +197,7 @@ func dumpDB(ctx *cli.Context) error { chainCount := chain.BlockHeight() + 1 if start+count > chainCount { - return cli.NewExitError(fmt.Errorf("chain is not that high (%d) to dump %d blocks starting from %d", chainCount-1, count, start), 1) + return cli.Exit(fmt.Errorf("chain is not that high (%d) to dump %d blocks starting from %d", chainCount-1, count, start), 1) } if count == 0 { count = chainCount - start @@ -203,7 +208,7 @@ func dumpDB(ctx *cli.Context) error { writer.WriteU32LE(count) err = chaindump.Dump(chain, writer, start, count) if err != nil { - return cli.NewExitError(err.Error(), 1) + return cli.Exit(err.Error(), 1) } return nil } @@ -218,7 +223,7 @@ func restoreDB(ctx *cli.Context) error { } log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if logCloser != nil { defer func() { _ = logCloser() }() @@ -229,7 +234,7 @@ func restoreDB(ctx *cli.Context) error { if in := ctx.String("in"); in != "" { inStream, err = os.Open(in) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } } defer inStream.Close() @@ -254,7 +259,7 @@ func restoreDB(ctx *cli.Context) error { if ctx.Bool("incremental") { start = reader.ReadU32LE() if chain.BlockHeight()+1 < start { - return cli.NewExitError(fmt.Errorf("expected height: %d, dump starts at %d", + return cli.Exit(fmt.Errorf("expected height: %d, dump starts at %d", chain.BlockHeight()+1, start), 1) } } @@ -266,10 +271,10 @@ func restoreDB(ctx *cli.Context) error { var allBlocks = reader.ReadU32LE() if reader.Err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if skip+count > allBlocks { - return cli.NewExitError(fmt.Errorf("input file has only %d blocks, can't read %d starting from %d", allBlocks, count, skip), 1) + return cli.Exit(fmt.Errorf("input file has only %d blocks, can't read %d starting from %d", allBlocks, count, skip), 1) } if count == 0 { count = allBlocks - skip @@ -320,7 +325,7 @@ func restoreDB(ctx *cli.Context) error { err = chaindump.Restore(chain, reader, skip, count, f) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } return nil } @@ -331,29 +336,29 @@ func resetDB(ctx *cli.Context) error { } cfg, err := options.GetConfigFromContext(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } h := uint32(ctx.Uint("height")) log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if logCloser != nil { defer func() { _ = logCloser() }() } chain, store, err := initBlockChain(cfg, log) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to create Blockchain instance: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to create Blockchain instance: %w", err), 1) } err = chain.Reset(h) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to reset chain state to height %d: %w", h, err), 1) + return cli.Exit(fmt.Errorf("failed to reset chain state to height %d: %w", h, err), 1) } err = store.Close() if err != nil { - return cli.NewExitError(fmt.Errorf("failed to close the DB: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to close the DB: %w", err), 1) } return nil } @@ -442,12 +447,12 @@ func startServer(ctx *cli.Context) error { cfg, err := options.GetConfigFromContext(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } var logDebug = ctx.Bool("debug") log, logLevel, logCloser, err := options.HandleLoggingParams(logDebug, cfg.ApplicationConfiguration) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if logCloser != nil { defer func() { _ = logCloser() }() @@ -458,12 +463,12 @@ func startServer(ctx *cli.Context) error { serverConfig, err := network.NewServerConfig(cfg) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } chain, prometheus, pprof, err := initBCWithMetrics(cfg, log) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer func() { pprof.ShutDown() @@ -473,26 +478,26 @@ func startServer(ctx *cli.Context) error { serv, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), log) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to create network server: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to create network server: %w", err), 1) } srMod := chain.GetStateModule().(*corestate.Module) // Take full responsibility here. sr, err := stateroot.New(serverConfig.StateRootCfg, srMod, log, chain, serv.BroadcastExtensible) if err != nil { - return cli.NewExitError(fmt.Errorf("can't initialize StateRoot service: %w", err), 1) + return cli.Exit(fmt.Errorf("can't initialize StateRoot service: %w", err), 1) } serv.AddExtensibleService(sr, stateroot.Category, sr.OnPayload) oracleSrv, err := mkOracle(cfg.ApplicationConfiguration.Oracle, cfg.ProtocolConfiguration.Magic, chain, serv, log) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } dbftSrv, err := mkConsensus(cfg.ApplicationConfiguration.Consensus, serverConfig.TimePerBlock, chain, serv, log) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } p2pNotary, err := mkP2PNotary(cfg.ApplicationConfiguration.P2PNotary, chain, serv, log) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } errChan := make(chan error) rpcServer := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan) @@ -640,7 +645,7 @@ Main: } if shutdownErr != nil { - return cli.NewExitError(shutdownErr, 1) + return cli.Exit(shutdownErr, 1) } return nil @@ -650,7 +655,7 @@ Main: func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, storage.Store, error) { store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration) if err != nil { - return nil, nil, cli.NewExitError(fmt.Errorf("could not initialize storage: %w", err), 1) + return nil, nil, cli.Exit(fmt.Errorf("could not initialize storage: %w", err), 1) } chain, err := core.NewBlockchain(store, cfg.Blockchain(), log) @@ -663,7 +668,7 @@ func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, stora errArgs = append(errArgs, closeErr) } - return nil, nil, cli.NewExitError(fmt.Errorf(errText, errArgs...), 1) + return nil, nil, cli.Exit(fmt.Errorf(errText, errArgs...), 1) } return chain, store, nil } diff --git a/cli/server/server_test.go b/cli/server/server_test.go index f9084345d..8eb1de819 100644 --- a/cli/server/server_test.go +++ b/cli/server/server_test.go @@ -15,7 +15,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig" "github.com/stretchr/testify/require" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" "gopkg.in/yaml.v3" ) diff --git a/cli/smartcontract/generate.go b/cli/smartcontract/generate.go index cb8d20722..7fdf115d4 100644 --- a/cli/smartcontract/generate.go +++ b/cli/smartcontract/generate.go @@ -9,32 +9,35 @@ import ( "github.com/nspcc-dev/neo-go/pkg/smartcontract/binding" "github.com/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding" "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" "gopkg.in/yaml.v3" ) var generatorFlags = []cli.Flag{ - cli.StringFlag{ - Name: "config, c", - Usage: "Configuration file to use", + &cli.StringFlag{ + Name: "config", + Aliases: []string{"c"}, + Usage: "Configuration file to use", }, - cli.StringFlag{ - Name: "manifest, m", + &cli.StringFlag{ + Name: "manifest", + Aliases: []string{"m"}, Required: true, Usage: "Read contract manifest (*.manifest.json) file", }, - cli.StringFlag{ - Name: "out, o", + &cli.StringFlag{ + Name: "out", + Aliases: []string{"o"}, Required: true, Usage: "Output of the compiled wrapper", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "hash", Usage: "Smart-contract hash. If not passed, the wrapper will be designed for dynamic hash usage", }, } -var generateWrapperCmd = cli.Command{ +var generateWrapperCmd = &cli.Command{ Name: "generate-wrapper", Usage: "Generate wrapper to use in other contracts", UsageText: "neo-go contract generate-wrapper --manifest --out [--hash ] [--config ]", @@ -48,7 +51,7 @@ var generateWrapperCmd = cli.Command{ Flags: generatorFlags, } -var generateRPCWrapperCmd = cli.Command{ +var generateRPCWrapperCmd = &cli.Command{ Name: "generate-rpcwrapper", Usage: "Generate RPC wrapper to use for data reads", UsageText: "neo-go contract generate-rpcwrapper --manifest --out [--hash ] [--config ]", @@ -76,23 +79,23 @@ func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error) if hStr := ctx.String("hash"); len(hStr) != 0 { h, err = util.Uint160DecodeStringLE(strings.TrimPrefix(hStr, "0x")) if err != nil { - return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1) + return cli.Exit(fmt.Errorf("invalid contract hash: %w", err), 1) } } m, _, err := readManifest(ctx.String("manifest"), h) if err != nil { - return cli.NewExitError(fmt.Errorf("can't read contract manifest: %w", err), 1) + return cli.Exit(fmt.Errorf("can't read contract manifest: %w", err), 1) } cfg := binding.NewConfig() if cfgPath := ctx.String("config"); cfgPath != "" { bs, err := os.ReadFile(cfgPath) if err != nil { - return cli.NewExitError(fmt.Errorf("can't read config file: %w", err), 1) + return cli.Exit(fmt.Errorf("can't read config file: %w", err), 1) } err = yaml.Unmarshal(bs, &cfg) if err != nil { - return cli.NewExitError(fmt.Errorf("can't parse config file: %w", err), 1) + return cli.Exit(fmt.Errorf("can't parse config file: %w", err), 1) } } cfg.Manifest = m @@ -100,7 +103,7 @@ func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error) f, err := os.Create(ctx.String("out")) if err != nil { - return cli.NewExitError(fmt.Errorf("can't create output file: %w", err), 1) + return cli.Exit(fmt.Errorf("can't create output file: %w", err), 1) } defer f.Close() @@ -108,7 +111,7 @@ func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error) err = cb(cfg) if err != nil { - return cli.NewExitError(fmt.Errorf("error during generation: %w", err), 1) + return cli.Exit(fmt.Errorf("error during generation: %w", err), 1) } return nil } diff --git a/cli/smartcontract/generate_test.go b/cli/smartcontract/generate_test.go index 195be3d08..89391cd9d 100644 --- a/cli/smartcontract/generate_test.go +++ b/cli/smartcontract/generate_test.go @@ -13,7 +13,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/stretchr/testify/require" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func TestGenerate(t *testing.T) { @@ -125,7 +125,7 @@ func TestGenerate(t *testing.T) { 0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, 0x03, 0x04, } app := cli.NewApp() - app.Commands = []cli.Command{generateWrapperCmd} + app.Commands = []*cli.Command{generateWrapperCmd} rawCfg := `package: wrapper hash: ` + h.StringLE() + ` @@ -351,7 +351,7 @@ func TestGenerateValidPackageName(t *testing.T) { 0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, 0x03, 0x04, } app := cli.NewApp() - app.Commands = []cli.Command{generateWrapperCmd, generateRPCWrapperCmd} + app.Commands = []*cli.Command{generateWrapperCmd, generateRPCWrapperCmd} require.NoError(t, app.Run([]string{"", "generate-wrapper", "--manifest", manifestFile, "--out", outFile, @@ -432,7 +432,7 @@ const rewriteExpectedOutputs = false func TestGenerateRPCBindings(t *testing.T) { tmpDir := t.TempDir() app := cli.NewApp() - app.Commands = []cli.Command{generateWrapperCmd, generateRPCWrapperCmd} + app.Commands = []*cli.Command{generateWrapperCmd, generateRPCWrapperCmd} var checkBinding = func(manifest string, hash string, good string) { t.Run(manifest, func(t *testing.T) { @@ -549,7 +549,7 @@ func TestAssistedRPCBindings(t *testing.T) { func TestGenerate_Errors(t *testing.T) { app := cli.NewApp() - app.Commands = []cli.Command{generateWrapperCmd} + app.Commands = []*cli.Command{generateWrapperCmd} app.ExitErrHandler = func(*cli.Context, error) {} checkError := func(t *testing.T, msg string, args ...string) { diff --git a/cli/smartcontract/manifest.go b/cli/smartcontract/manifest.go index e940b333b..f6488f2f3 100644 --- a/cli/smartcontract/manifest.go +++ b/cli/smartcontract/manifest.go @@ -13,7 +13,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func manifestAddGroup(ctx *cli.Context) error { @@ -22,25 +22,25 @@ func manifestAddGroup(ctx *cli.Context) error { } sender, err := flags.ParseAddress(ctx.String("sender")) if err != nil { - return cli.NewExitError(fmt.Errorf("invalid sender: %w", err), 1) + return cli.Exit(fmt.Errorf("invalid sender: %w", err), 1) } nf, _, err := readNEFFile(ctx.String("nef")) if err != nil { - return cli.NewExitError(fmt.Errorf("can't read NEF file: %w", err), 1) + return cli.Exit(fmt.Errorf("can't read NEF file: %w", err), 1) } mPath := ctx.String("manifest") m, _, err := readManifest(mPath, util.Uint160{}) if err != nil { - return cli.NewExitError(fmt.Errorf("can't read contract manifest: %w", err), 1) + return cli.Exit(fmt.Errorf("can't read contract manifest: %w", err), 1) } h := state.CreateContractHash(sender, nf.Checksum, m.Name) gAcc, w, err := options.GetAccFromContext(ctx) if err != nil { - return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1) + return cli.Exit(fmt.Errorf("can't get account to sign group with: %w", err), 1) } defer w.Close() @@ -64,12 +64,12 @@ func manifestAddGroup(ctx *cli.Context) error { rawM, err := json.Marshal(m) if err != nil { - return cli.NewExitError(fmt.Errorf("can't marshal manifest: %w", err), 1) + return cli.Exit(fmt.Errorf("can't marshal manifest: %w", err), 1) } err = os.WriteFile(mPath, rawM, os.ModePerm) if err != nil { - return cli.NewExitError(fmt.Errorf("can't write manifest file: %w", err), 1) + return cli.Exit(fmt.Errorf("can't write manifest file: %w", err), 1) } return nil } diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 442fcf4e3..ad80a3a9f 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -27,13 +27,17 @@ import ( "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/wallet" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" "gopkg.in/yaml.v3" ) -// addressFlagName is a flag name used for address-related operations. It should be -// the same within the smartcontract package, thus, use this constant. -const addressFlagName = "address, a" +// addressFlagName and addressFlagAlias are a flag name and its alias +// used for address-related operations. It should be the same within +// the smartcontract package, thus, use this constant. +const ( + addressFlagName = "address" + addressFlagAlias = "a" +) var ( errNoInput = errors.New("no input file was found, specify an input file with the '--in or -i' flag") @@ -43,9 +47,10 @@ var ( errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument") errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag") errFileExist = errors.New("A file with given smart-contract name already exists") - addressFlag = flags.AddressFlag{ - Name: addressFlagName, - Usage: "Address to use as transaction signee (and gas source)", + addressFlag = &flags.AddressFlag{ + Name: addressFlagName, + Aliases: []string{addressFlagAlias}, + Usage: "Address to use as transaction signee (and gas source)", } ) @@ -74,11 +79,12 @@ func RuntimeNotify(args []any) { ) // NewCommands returns 'contract' command. -func NewCommands() []cli.Command { +func NewCommands() []*cli.Command { testInvokeScriptFlags := []cli.Flag{ - cli.StringFlag{ - Name: "in, i", - Usage: "Input location of the .nef file that needs to be invoked", + &cli.StringFlag{ + Name: "in", + Aliases: []string{"i"}, + Usage: "Input location of the .nef file that needs to be invoked", }, options.Historic, } @@ -96,37 +102,43 @@ func NewCommands() []cli.Command { invokeFunctionFlags = append(invokeFunctionFlags, options.Wallet...) invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...) deployFlags := append(invokeFunctionFlags, []cli.Flag{ - cli.StringFlag{ - Name: "in, i", - Usage: "Input file for the smart contract (*.nef)", + &cli.StringFlag{ + Name: "in", + Aliases: []string{"i"}, + Usage: "Input file for the smart contract (*.nef)", }, - cli.StringFlag{ - Name: "manifest, m", - Usage: "Manifest input file (*.manifest.json)", + &cli.StringFlag{ + Name: "manifest", + Aliases: []string{"m"}, + Usage: "Manifest input file (*.manifest.json)", }, }...) manifestAddGroupFlags := append([]cli.Flag{ - cli.StringFlag{ - Name: "sender, s", - Usage: "Deploy transaction sender", + &cli.StringFlag{ + Name: "sender", + Aliases: []string{"s"}, + Usage: "Deploy transaction sender", }, - flags.AddressFlag{ - Name: addressFlagName, // use the same name for handler code unification. - Usage: "Account to sign group with", + &flags.AddressFlag{ + Name: addressFlagName, // use the same name for handler code unification. + Aliases: []string{addressFlagAlias}, + Usage: "Account to sign group with", }, - cli.StringFlag{ - Name: "nef, n", - Usage: "Path to the NEF file", + &cli.StringFlag{ + Name: "nef", + Aliases: []string{"n"}, + Usage: "Path to the NEF file", }, - cli.StringFlag{ - Name: "manifest, m", - Usage: "Path to the manifest", + &cli.StringFlag{ + Name: "manifest", + Aliases: []string{"m"}, + Usage: "Path to the manifest", }, }, options.Wallet...) - return []cli.Command{{ + return []*cli.Command{{ Name: "contract", Usage: "Compile - debug - deploy smart contracts", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "compile", Usage: "Compile a smart contract to a .nef file", @@ -141,47 +153,53 @@ func NewCommands() []cli.Command { `, Action: contractCompile, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "in, i", - Usage: "Input file for the smart contract to be compiled (*.go file or directory)", + &cli.StringFlag{ + Name: "in", + Aliases: []string{"i"}, + Usage: "Input file for the smart contract to be compiled (*.go file or directory)", }, - cli.StringFlag{ - Name: "out, o", - Usage: "Output of the compiled contract", + &cli.StringFlag{ + Name: "out", + Aliases: []string{"o"}, + Usage: "Output of the compiled contract", }, - cli.BoolFlag{ - Name: "verbose, v", - Usage: "Print out additional information after a compiling", + &cli.BoolFlag{ + Name: "verbose", + Aliases: []string{"v"}, + Usage: "Print out additional information after a compiling", }, - cli.StringFlag{ - Name: "debug, d", - Usage: "Emit debug info in a separate file", + &cli.StringFlag{ + Name: "debug", + Aliases: []string{"d"}, + Usage: "Emit debug info in a separate file", }, - cli.StringFlag{ - Name: "manifest, m", - Usage: "Emit contract manifest (*.manifest.json) file into separate file using configuration input file (*.yml)", + &cli.StringFlag{ + Name: "manifest", + Aliases: []string{"m"}, + Usage: "Emit contract manifest (*.manifest.json) file into separate file using configuration input file (*.yml)", }, - cli.StringFlag{ - Name: "config, c", - Usage: "Configuration input file (*.yml)", + &cli.StringFlag{ + Name: "config", + Aliases: []string{"c"}, + Usage: "Configuration input file (*.yml)", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-standards", Usage: "Do not check compliance with supported standards", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-events", Usage: "Do not check emitted events with the manifest", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-permissions", Usage: "Do not check if invoked contracts are allowed in manifest", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "guess-eventtypes", Usage: "Guess event types for smart-contract bindings configuration from the code usages", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "bindings", Usage: "Output file for smart-contract bindings configuration", }, @@ -254,13 +272,15 @@ func NewCommands() []cli.Command { UsageText: "neo-go contract init -n name [--skip-details]", Action: initSmartContract, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "name, n", - Usage: "Name of the smart-contract to be initialized", + &cli.StringFlag{ + Name: "name", + Aliases: []string{"n"}, + Usage: "Name of the smart-contract to be initialized", }, - cli.BoolFlag{ - Name: "skip-details, skip", - Usage: "Skip filling in the projects and contract details", + &cli.BoolFlag{ + Name: "skip-details", + Aliases: []string{"skip"}, + Usage: "Skip filling in the projects and contract details", }, }, }, @@ -270,13 +290,15 @@ func NewCommands() []cli.Command { UsageText: "neo-go contract inspect -i file [-c]", Action: inspect, Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "compile, c", - Usage: "Compile input file (it should be go code then)", + &cli.BoolFlag{ + Name: "compile", + Aliases: []string{"c"}, + Usage: "Compile input file (it should be go code then)", }, - cli.StringFlag{ - Name: "in, i", - Usage: "Input file of the program (either .go or .nef)", + &cli.StringFlag{ + Name: "in", + Aliases: []string{"i"}, + Usage: "Input file of the program (either .go or .nef)", }, }, }, @@ -286,24 +308,26 @@ func NewCommands() []cli.Command { UsageText: "neo-go contract calc-hash -i nef -m manifest -s address", Action: calcHash, Flags: []cli.Flag{ - flags.AddressFlag{ - Name: "sender, s", - Usage: "Sender script hash or address", + &flags.AddressFlag{ + Name: "sender", + Aliases: []string{"s"}, + Usage: "Sender script hash or address", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "in", Usage: "Path to NEF file", }, - cli.StringFlag{ - Name: "manifest, m", - Usage: "Path to manifest file", + &cli.StringFlag{ + Name: "manifest", + Aliases: []string{"m"}, + Usage: "Path to manifest file", }, }, }, { Name: "manifest", Usage: "Manifest-related commands", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "add-group", Usage: "Adds group to the manifest", @@ -324,12 +348,12 @@ func initSmartContract(ctx *cli.Context) error { } contractName := ctx.String("name") if contractName == "" { - return cli.NewExitError(errNoSmartContractName, 1) + return cli.Exit(errNoSmartContractName, 1) } // Check if the file already exists, if yes, exit if _, err := os.Stat(contractName); err == nil { - return cli.NewExitError(errFileExist, 1) + return cli.Exit(errFileExist, 1) } basePath := contractName @@ -338,7 +362,7 @@ func initSmartContract(ctx *cli.Context) error { // create base directory if err := os.Mkdir(basePath, os.ModePerm); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } m := ProjectConfig{ @@ -363,10 +387,10 @@ func initSmartContract(ctx *cli.Context) error { } b, err := yaml.Marshal(m) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if err := os.WriteFile(filepath.Join(basePath, "neo-go.yml"), b, 0644); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } ver := ModVersion @@ -382,12 +406,12 @@ require ( github.com/nspcc-dev/neo-go/pkg/interop ` + ver + ` )`) if err := os.WriteFile(filepath.Join(basePath, "go.mod"), gm, 0644); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } data := []byte(fmt.Sprintf(smartContractTmpl, contractName)) if err := os.WriteFile(filepath.Join(basePath, fileName), data, 0644); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } fmt.Fprintf(ctx.App.Writer, "Successfully initialized smart contract [%s]\n", contractName) @@ -401,7 +425,7 @@ func contractCompile(ctx *cli.Context) error { } src := ctx.String("in") if len(src) == 0 { - return cli.NewExitError(errNoInput, 1) + return cli.Exit(errNoInput, 1) } manifestFile := ctx.String("manifest") confFile := ctx.String("config") @@ -409,7 +433,7 @@ func contractCompile(ctx *cli.Context) error { out := ctx.String("out") bindings := ctx.String("bindings") if len(confFile) == 0 && (len(manifestFile) != 0 || len(debugFile) != 0 || len(bindings) != 0) { - return cli.NewExitError(errNoConfFile, 1) + return cli.Exit(errNoConfFile, 1) } autocomplete := len(manifestFile) == 0 && len(confFile) == 0 && @@ -419,7 +443,7 @@ func contractCompile(ctx *cli.Context) error { var root string fileInfo, err := os.Stat(src) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to stat source file or directory: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to stat source file or directory: %w", err), 1) } if fileInfo.IsDir() { base := filepath.Base(fileInfo.Name()) @@ -470,7 +494,7 @@ func contractCompile(ctx *cli.Context) error { result, err := compiler.CompileAndSave(src, o) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if ctx.Bool("verbose") { fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(result)) @@ -485,33 +509,33 @@ func calcHash(ctx *cli.Context) error { } sender := ctx.Generic("sender").(*flags.Address) if !sender.IsSet { - return cli.NewExitError("sender is not set", 1) + return cli.Exit("sender is not set", 1) } p := ctx.String("in") if p == "" { - return cli.NewExitError(errors.New("no .nef file was provided"), 1) + return cli.Exit(errors.New("no .nef file was provided"), 1) } mpath := ctx.String("manifest") if mpath == "" { - return cli.NewExitError(errors.New("no manifest file provided"), 1) + return cli.Exit(errors.New("no manifest file provided"), 1) } f, err := os.ReadFile(p) if err != nil { - return cli.NewExitError(fmt.Errorf("can't read .nef file: %w", err), 1) + return cli.Exit(fmt.Errorf("can't read .nef file: %w", err), 1) } nefFile, err := nef.FileFromBytes(f) if err != nil { - return cli.NewExitError(fmt.Errorf("can't unmarshal .nef file: %w", err), 1) + return cli.Exit(fmt.Errorf("can't unmarshal .nef file: %w", err), 1) } manifestBytes, err := os.ReadFile(mpath) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to read manifest file: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to read manifest file: %w", err), 1) } m := &manifest.Manifest{} err = json.Unmarshal(manifestBytes, m) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to restore manifest file: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to restore manifest file: %w", err), 1) } fmt.Fprintln(ctx.App.Writer, "Contract hash:", state.CreateContractHash(sender.Uint160(), nefFile.Checksum, m.Name).StringLE()) return nil @@ -528,7 +552,7 @@ func invokeFunction(ctx *cli.Context) error { func invokeInternal(ctx *cli.Context, signAndPush bool) error { var ( err error - exitErr *cli.ExitError + exitErr cli.ExitCoder operation string params []any paramsStart = 1 @@ -539,22 +563,23 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error { args := ctx.Args() if !args.Present() { - return cli.NewExitError(errNoScriptHash, 1) + return cli.Exit(errNoScriptHash, 1) } - script, err := flags.ParseAddress(args[0]) + argsSlice := args.Slice() + script, err := flags.ParseAddress(argsSlice[0]) if err != nil { - return cli.NewExitError(fmt.Errorf("incorrect script hash: %w", err), 1) + return cli.Exit(fmt.Errorf("incorrect script hash: %w", err), 1) } - if len(args) <= 1 { - return cli.NewExitError(errNoMethod, 1) + if len(argsSlice) <= 1 { + return cli.Exit(errNoMethod, 1) } - operation = args[1] + operation = argsSlice[1] paramsStart++ - if len(args) > paramsStart { - cosignersOffset, scParams, err = cmdargs.ParseParams(args[paramsStart:], true) + if len(argsSlice) > paramsStart { + cosignersOffset, scParams, err = cmdargs.ParseParams(argsSlice[paramsStart:], true) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } params = make([]any, len(scParams)) for i := range scParams { @@ -575,7 +600,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error { if signAndPush { acc, w, err = options.GetAccFromContext(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer w.Close() } @@ -595,7 +620,7 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet, if signAndPush { signersAccounts, err = cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.None) if err != nil { - return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1) + return cli.Exit(fmt.Errorf("invalid signers: %w", err), 1) } } gctx, cancel := options.GetTimeoutContext(ctx) @@ -615,12 +640,12 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet, out := ctx.String("out") resp, err = inv.Call(script, operation, params...) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if resp.State != "HALT" { errText := fmt.Sprintf("Warning: %s VM state returned from the RPC node: %s", resp.State, resp.FaultException) if !signAndPush { - return cli.NewExitError(errText, 1) + return cli.Exit(errText, 1) } action := "send" @@ -630,25 +655,25 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet, process = "Saving" } if !ctx.Bool("force") { - return cli.NewExitError(errText+".\nUse --force flag to "+action+" the transaction anyway.", 1) + return cli.Exit(errText+".\nUse --force flag to "+action+" the transaction anyway.", 1) } fmt.Fprintln(ctx.App.Writer, errText+".\n"+process+" transaction...") } if !signAndPush { b, err := json.MarshalIndent(resp, "", " ") if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } fmt.Fprintln(ctx.App.Writer, string(b)) return nil } if len(resp.Script) == 0 { - return cli.NewExitError(errors.New("no script returned from the RPC node"), 1) + return cli.Exit(errors.New("no script returned from the RPC node"), 1) } tx, err := act.MakeUnsignedUncheckedRun(resp.Script, resp.GasConsumed, nil) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to create tx: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to create tx: %w", err), 1) } return txctx.SignAndSend(ctx, act, acc, tx) } @@ -656,16 +681,16 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet, func testInvokeScript(ctx *cli.Context) error { src := ctx.String("in") if len(src) == 0 { - return cli.NewExitError(errNoInput, 1) + return cli.Exit(errNoInput, 1) } b, err := os.ReadFile(src) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } nefFile, err := nef.FileFromBytes(b) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to restore .nef file: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to restore .nef file: %w", err), 1) } signers, exitErr := cmdargs.GetSignersFromContext(ctx, 0) @@ -683,12 +708,12 @@ func testInvokeScript(ctx *cli.Context) error { resp, err := inv.Run(nefFile.Script) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } b, err = json.MarshalIndent(resp, "", " ") if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } fmt.Fprintln(ctx.App.Writer, string(b)) @@ -715,7 +740,7 @@ func inspect(ctx *cli.Context) error { in := ctx.String("in") compile := ctx.Bool("compile") if len(in) == 0 { - return cli.NewExitError(errNoInput, 1) + return cli.Exit(errNoInput, 1) } var ( b []byte @@ -724,16 +749,16 @@ func inspect(ctx *cli.Context) error { if compile { b, err = compiler.Compile(in, nil) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to compile: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to compile: %w", err), 1) } } else { f, err := os.ReadFile(in) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to read .nef file: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to read .nef file: %w", err), 1) } nefFile, err := nef.FileFromBytes(f) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to restore .nef file: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to restore .nef file: %w", err), 1) } b = nefFile.Script } @@ -748,22 +773,22 @@ func inspect(ctx *cli.Context) error { func contractDeploy(ctx *cli.Context) error { nefFile, f, err := readNEFFile(ctx.String("in")) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } m, manifestBytes, err := readManifest(ctx.String("manifest"), util.Uint160{}) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to read manifest file: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to read manifest file: %w", err), 1) } var appCallParams = []any{f, manifestBytes} - signOffset, data, err := cmdargs.ParseParams(ctx.Args(), true) + signOffset, data, err := cmdargs.ParseParams(ctx.Args().Slice(), true) if err != nil { - return cli.NewExitError(fmt.Errorf("unable to parse 'data' parameter: %w", err), 1) + return cli.Exit(fmt.Errorf("unable to parse 'data' parameter: %w", err), 1) } if len(data) > 1 { - return cli.NewExitError("'data' should be represented as a single parameter", 1) + return cli.Exit("'data' should be represented as a single parameter", 1) } if len(data) != 0 { appCallParams = append(appCallParams, data[0]) @@ -771,7 +796,7 @@ func contractDeploy(ctx *cli.Context) error { acc, w, err := options.GetAccFromContext(ctx) if err != nil { - return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1) + return cli.Exit(fmt.Errorf("can't get sender address: %w", err), 1) } defer w.Close() sender := acc.ScriptHash() @@ -801,12 +826,12 @@ func ParseContractConfig(confFile string) (ProjectConfig, error) { conf := ProjectConfig{} confBytes, err := os.ReadFile(confFile) if err != nil { - return conf, cli.NewExitError(err, 1) + return conf, cli.Exit(err, 1) } err = yaml.Unmarshal(confBytes, &conf) if err != nil { - return conf, cli.NewExitError(fmt.Errorf("bad config: %w", err), 1) + return conf, cli.Exit(fmt.Errorf("bad config: %w", err), 1) } return conf, nil } diff --git a/cli/smartcontract/smart_contract_test.go b/cli/smartcontract/smart_contract_test.go index 69717b37c..7bab33645 100644 --- a/cli/smartcontract/smart_contract_test.go +++ b/cli/smartcontract/smart_contract_test.go @@ -9,7 +9,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/stretchr/testify/require" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" "gopkg.in/yaml.v3" ) diff --git a/cli/txctx/tx.go b/cli/txctx/tx.go index 498439373..805de75ca 100644 --- a/cli/txctx/tx.go +++ b/cli/txctx/tx.go @@ -16,32 +16,34 @@ import ( "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/wallet" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) var ( // GasFlag is a flag used for the additional network fee. - GasFlag = flags.Fixed8Flag{ - Name: "gas, g", - Usage: "Network fee to add to the transaction (prioritizing it)", + GasFlag = &flags.Fixed8Flag{ + Name: "gas", + Aliases: []string{"g"}, + Usage: "Network fee to add to the transaction (prioritizing it)", } // SysGasFlag is a flag used for the additional system fee. - SysGasFlag = flags.Fixed8Flag{ - Name: "sysgas, e", - Usage: "System fee to add to the transaction (compensating for execution)", + SysGasFlag = &flags.Fixed8Flag{ + Name: "sysgas", + Aliases: []string{"e"}, + Usage: "System fee to add to the transaction (compensating for execution)", } // OutFlag is a flag used for file output. - OutFlag = cli.StringFlag{ + OutFlag = &cli.StringFlag{ Name: "out", Usage: "File (JSON) to put signature context with a transaction to", } // ForceFlag is a flag used to force transaction send. - ForceFlag = cli.BoolFlag{ + ForceFlag = &cli.BoolFlag{ Name: "force", Usage: "Do not ask for a confirmation (and ignore errors)", } // AwaitFlag is a flag used to wait for the transaction to be included in a block. - AwaitFlag = cli.BoolFlag{ + AwaitFlag = &cli.BoolFlag{ Name: "await", Usage: "Wait for the transaction to be included in a block", } @@ -71,7 +73,7 @@ func SignAndSend(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, tx *tr promptTime := time.Now() err := input.ConfirmTx(ctx.App.Writer, tx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } waitTime := time.Since(promptTime) // Compensate for confirmation waiting. @@ -83,17 +85,17 @@ func SignAndSend(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, tx *tr ) resTx, vub, err = act.SignAndSend(tx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if ctx.Bool("await") { aer, err = act.Wait(resTx, vub, err) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", resTx.StringLE(), err), 1) + return cli.Exit(fmt.Errorf("failed to await transaction %s: %w", resTx.StringLE(), err), 1) } } } if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } DumpTransactionInfo(ctx.App.Writer, tx.Hash(), aer) diff --git a/cli/util/cancel.go b/cli/util/cancel.go index fbb112ad8..fcb56a059 100644 --- a/cli/util/cancel.go +++ b/cli/util/cancel.go @@ -16,20 +16,20 @@ import ( "github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm/opcode" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func cancelTx(ctx *cli.Context) error { - args := ctx.Args() + args := ctx.Args().Slice() if len(args) == 0 { - return cli.NewExitError("transaction hash is missing", 1) + return cli.Exit("transaction hash is missing", 1) } else if len(args) > 1 { - return cli.NewExitError("only one transaction hash is accepted", 1) + return cli.Exit("only one transaction hash is accepted", 1) } txHash, err := util.Uint256DecodeStringLE(strings.TrimPrefix(args[0], "0x")) if err != nil { - return cli.NewExitError(fmt.Sprintf("invalid tx hash: %s", args[0]), 1) + return cli.Exit(fmt.Sprintf("invalid tx hash: %s", args[0]), 1) } gctx, cancel := options.GetTimeoutContext(ctx) @@ -37,13 +37,13 @@ func cancelTx(ctx *cli.Context) error { acc, w, err := options.GetAccFromContext(ctx) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to get account from context to sign the conflicting transaction: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to get account from context to sign the conflicting transaction: %w", err), 1) } defer w.Close() signers, err := cmdargs.GetSignersAccounts(acc, w, nil, transaction.CalledByEntry) if err != nil { - return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1) + return cli.Exit(fmt.Errorf("invalid signers: %w", err), 1) } c, a, exitErr := options.GetRPCWithActor(gctx, ctx, signers) if exitErr != nil { @@ -52,11 +52,11 @@ func cancelTx(ctx *cli.Context) error { mainTx, _ := c.GetRawTransactionVerbose(txHash) if mainTx != nil && !mainTx.Blockhash.Equals(util.Uint256{}) { - return cli.NewExitError(fmt.Errorf("target transaction %s is accepted at block %s", txHash, mainTx.Blockhash.StringLE()), 1) + return cli.Exit(fmt.Errorf("target transaction %s is accepted at block %s", txHash, mainTx.Blockhash.StringLE()), 1) } if mainTx != nil && !mainTx.HasSigner(acc.ScriptHash()) { - return cli.NewExitError(fmt.Errorf("account %s is not a signer of the conflicting transaction", acc.Address), 1) + return cli.Exit(fmt.Errorf("account %s is not a signer of the conflicting transaction", acc.Address), 1) } resHash, resVub, err := a.SendTunedRun([]byte{byte(opcode.RET)}, []transaction.Attribute{{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: txHash}}}, func(r *result.Invoke, t *transaction.Transaction) error { @@ -74,7 +74,7 @@ func cancelTx(ctx *cli.Context) error { return nil }) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to send conflicting transaction: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to send conflicting transaction: %w", err), 1) } var res *state.AppExecResult if ctx.Bool("await") { @@ -82,19 +82,19 @@ func cancelTx(ctx *cli.Context) error { if err != nil { if errors.Is(err, waiter.ErrTxNotAccepted) { if mainTx == nil { - return cli.NewExitError(fmt.Errorf("neither target nor conflicting transaction is accepted before the current height %d (ValidUntilBlock value of conlicting transaction). Main transaction is unknown to the provided RPC node, thus still has chances to be accepted, you may try cancellation again", resVub), 1) + return cli.Exit(fmt.Errorf("neither target nor conflicting transaction is accepted before the current height %d (ValidUntilBlock value of conlicting transaction). Main transaction is unknown to the provided RPC node, thus still has chances to be accepted, you may try cancellation again", resVub), 1) } fmt.Fprintf(ctx.App.Writer, "Neither target nor conflicting transaction is accepted before the current height %d (ValidUntilBlock value of both target and conflicting transactions). Main transaction is not valid anymore, cancellation is successful\n", resVub) return nil } - return cli.NewExitError(fmt.Errorf("failed to await target/ conflicting transaction %s/ %s: %w", txHash.StringLE(), resHash.StringLE(), err), 1) + return cli.Exit(fmt.Errorf("failed to await target/ conflicting transaction %s/ %s: %w", txHash.StringLE(), resHash.StringLE(), err), 1) } if txHash.Equals(res.Container) { tx, err := c.GetRawTransactionVerbose(txHash) if err != nil { - return cli.NewExitError(fmt.Errorf("target transaction %s is accepted", txHash), 1) + return cli.Exit(fmt.Errorf("target transaction %s is accepted", txHash), 1) } - return cli.NewExitError(fmt.Errorf("target transaction %s is accepted at block %s", txHash, tx.Blockhash.StringLE()), 1) + return cli.Exit(fmt.Errorf("target transaction %s is accepted at block %s", txHash, tx.Blockhash.StringLE()), 1) } fmt.Fprintln(ctx.App.Writer, "Conflicting transaction accepted") } diff --git a/cli/util/convert.go b/cli/util/convert.go index 49b69fa9a..2b7e80d73 100644 --- a/cli/util/convert.go +++ b/cli/util/convert.go @@ -11,27 +11,28 @@ import ( "github.com/nspcc-dev/neo-go/cli/txctx" vmcli "github.com/nspcc-dev/neo-go/cli/vm" "github.com/nspcc-dev/neo-go/pkg/vm" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // NewCommands returns util commands for neo-go CLI. -func NewCommands() []cli.Command { +func NewCommands() []*cli.Command { txDumpFlags := append([]cli.Flag{}, options.RPC...) txSendFlags := append(txDumpFlags, txctx.AwaitFlag) txCancelFlags := append([]cli.Flag{ - flags.AddressFlag{ - Name: "address, a", - Usage: "Address to use as conflicting transaction signee (and gas source)", + &flags.AddressFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Address to use as conflicting transaction signee (and gas source)", }, txctx.GasFlag, txctx.AwaitFlag, }, options.RPC...) txCancelFlags = append(txCancelFlags, options.Wallet...) - return []cli.Command{ + return []*cli.Command{ { Name: "util", Usage: "Various helper commands", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "convert", Usage: "Convert provided argument into other possible formats", @@ -44,7 +45,7 @@ func NewCommands() []cli.Command { { Name: "sendtx", Usage: "Send complete transaction stored in a context file", - UsageText: "sendtx [-r ] [--await]", + UsageText: "sendtx [-r ] [--await] ", Description: `Sends the transaction from the given context file to the given RPC node if it's completely signed and ready. This command expects a ContractParametersContext JSON file for input, it can't handle binary (or hex- or base64-encoded) @@ -57,7 +58,7 @@ func NewCommands() []cli.Command { { Name: "canceltx", Usage: "Cancel transaction by sending conflicting transaction", - UsageText: "canceltx -r --wallet [--account ] [--wallet-config ] [--gas ] [--await]", + UsageText: "canceltx -r --wallet [--account ] [--wallet-config ] [--gas ] [--await] ", Description: `Aims to prevent a transaction from being added to the blockchain by dispatching a more prioritized conflicting transaction to the specified RPC node. The input for this command should be the transaction hash. If another account is not specified, the conflicting transaction is @@ -90,14 +91,15 @@ func NewCommands() []cli.Command { { Name: "ops", Usage: "Pretty-print VM opcodes of the given base64- or hex- encoded script (base64 is checked first). If the input file is specified, then the script is taken from the file.", - UsageText: "ops [-i path-to-file] [--hex]", + UsageText: "ops [-i path-to-file] [--hex] ", Action: handleOps, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "in, i", - Usage: "Input file containing base64- or hex- encoded script representation", + &cli.StringFlag{ + Name: "in", + Aliases: []string{"i"}, + Usage: "Input file containing base64- or hex- encoded script representation", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "hex", Usage: "Use hex encoding and do not check base64", }, @@ -109,9 +111,9 @@ func NewCommands() []cli.Command { } func handleParse(ctx *cli.Context) error { - res, err := vmcli.Parse(ctx.Args()) + res, err := vmcli.Parse(ctx.Args().Slice()) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } fmt.Fprint(ctx.App.Writer, res) return nil @@ -127,21 +129,21 @@ func handleOps(ctx *cli.Context) error { if len(in) != 0 { b, err := os.ReadFile(in) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to read file: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to read file: %w", err), 1) } s = string(b) } else { if !ctx.Args().Present() { - return cli.NewExitError("missing script", 1) + return cli.Exit("missing script", 1) } - s = ctx.Args()[0] + s = ctx.Args().Slice()[0] } b, err = base64.StdEncoding.DecodeString(s) if err != nil || ctx.Bool("hex") { b, err = hex.DecodeString(s) } if err != nil { - return cli.NewExitError("unknown encoding: base64 or hex are supported", 1) + return cli.Exit("unknown encoding: base64 or hex are supported", 1) } v := vm.New() v.LoadScript(b) diff --git a/cli/util/dump.go b/cli/util/dump.go index 33ad698fe..6d4e8d38f 100644 --- a/cli/util/dump.go +++ b/cli/util/dump.go @@ -8,30 +8,30 @@ import ( "github.com/nspcc-dev/neo-go/cli/paramcontext" "github.com/nspcc-dev/neo-go/cli/query" "github.com/nspcc-dev/neo-go/pkg/core/transaction" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func txDump(ctx *cli.Context) error { - args := ctx.Args() + args := ctx.Args().Slice() if len(args) == 0 { - return cli.NewExitError("missing input file", 1) + return cli.Exit("missing input file", 1) } else if len(args) > 1 { - return cli.NewExitError("only one input file is accepted", 1) + return cli.Exit("only one input file is accepted", 1) } c, err := paramcontext.Read(args[0]) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } tx, ok := c.Verifiable.(*transaction.Transaction) if !ok { - return cli.NewExitError("verifiable item is not a transaction", 1) + return cli.Exit("verifiable item is not a transaction", 1) } err = query.DumpApplicationLog(ctx, nil, tx, nil, true) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if ctx.String(options.RPCEndpointFlag) != "" { @@ -41,15 +41,15 @@ func txDump(ctx *cli.Context) error { var err error cl, err := options.GetRPCClient(gctx, ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } res, err := cl.InvokeScript(tx.Script, tx.Signers) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } resS, err := json.MarshalIndent(res, "", " ") if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } fmt.Fprintln(ctx.App.Writer, string(resS)) } diff --git a/cli/util/send.go b/cli/util/send.go index a67465274..be65c7fbf 100644 --- a/cli/util/send.go +++ b/cli/util/send.go @@ -8,25 +8,25 @@ import ( "github.com/nspcc-dev/neo-go/cli/txctx" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func sendTx(ctx *cli.Context) error { - args := ctx.Args() + args := ctx.Args().Slice() if len(args) == 0 { - return cli.NewExitError("missing input file", 1) + return cli.Exit("missing input file", 1) } else if len(args) > 1 { - return cli.NewExitError("only one input file is accepted", 1) + return cli.Exit("only one input file is accepted", 1) } pc, err := paramcontext.Read(args[0]) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } tx, err := pc.GetCompleteTransaction() if err != nil { - return cli.NewExitError(fmt.Errorf("failed to complete transaction: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to complete transaction: %w", err), 1) } gctx, cancel := options.GetTimeoutContext(ctx) @@ -34,18 +34,18 @@ func sendTx(ctx *cli.Context) error { c, err := options.GetRPCClient(gctx, ctx) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to create RPC client: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to create RPC client: %w", err), 1) } res, err := c.SendRawTransaction(tx) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1) } var aer *state.AppExecResult if ctx.Bool("await") { version, err := c.GetVersion() aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", res.StringLE(), err), 1) + return cli.Exit(fmt.Errorf("failed to await transaction %s: %w", res.StringLE(), err), 1) } } txctx.DumpTransactionInfo(ctx.App.Writer, res, aer) diff --git a/cli/vm/cli.go b/cli/vm/cli.go index 8389d0c84..d8a95bcf0 100644 --- a/cli/vm/cli.go +++ b/cli/vm/cli.go @@ -44,7 +44,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/util/slice" "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -70,22 +70,22 @@ const ( ) var ( - historicFlag = cli.IntFlag{ + historicFlag = &cli.IntFlag{ Name: historicFlagFullName, Usage: "Height for historic script invocation (for MPT-enabled blockchain configuration with KeepOnlyLatestState setting disabled). " + "Assuming that block N-th is specified as an argument, the historic invocation is based on the storage state of height N and fake currently-accepting block with index N+1.", } - gasFlag = cli.Int64Flag{ + gasFlag = &cli.Int64Flag{ Name: gasFlagFullName, Usage: "GAS limit for this execution (integer number, satoshi).", } - hashFlag = cli.StringFlag{ + hashFlag = &cli.StringFlag{ Name: hashFlagFullName, Usage: "Smart-contract hash in LE form or address", } ) -var commands = []cli.Command{ +var commands = []*cli.Command{ { Name: "exit", Usage: "Exit the VM prompt", @@ -339,9 +339,10 @@ Example: Usage: "Dump state of the chain that is used for VM CLI invocations (use -v for verbose node configuration)", UsageText: `env [-v]`, Flags: []cli.Flag{ - cli.BoolFlag{ - Name: verboseFlagFullName + ",v", - Usage: "Print the whole blockchain node configuration.", + &cli.BoolFlag{ + Name: verboseFlagFullName, + Aliases: []string{"v"}, + Usage: "Print the whole blockchain node configuration.", }, }, Description: `Dump state of the chain that is used for VM CLI invocations (use -v for verbose node configuration). @@ -353,15 +354,17 @@ Example: { Name: "storage", Usage: "Dump storage of the contract with the specified hash, address or ID as is at the current stage of script invocation", - UsageText: `storage [] [--backwards] [--diff]`, + UsageText: `storage [--backwards] [--diff] []`, Flags: []cli.Flag{ - cli.BoolFlag{ - Name: backwardsFlagFullName + ",b", - Usage: "Backwards traversal direction", + &cli.BoolFlag{ + Name: backwardsFlagFullName, + Aliases: []string{"b"}, + Usage: "Backwards traversal direction", }, - cli.BoolFlag{ - Name: diffFlagFullName + ",d", - Usage: "Dump only those storage items that were added or changed during the current script invocation. Note that this call won't show removed storage items, use 'changes' command for that.", + &cli.BoolFlag{ + Name: diffFlagFullName, + Aliases: []string{"d"}, + Usage: "Dump only those storage items that were added or changed during the current script invocation. Note that this call won't show removed storage items, use 'changes' command for that.", }, }, Description: `Dump storage of the contract with the specified hash, address or ID as is at the current stage of script invocation. @@ -400,7 +403,7 @@ func init() { if !c.Hidden { var flagsItems []readline.PrefixCompleterInterface for _, f := range c.Flags { - names := strings.SplitN(f.GetName(), ", ", 2) // only long name will be offered + names := strings.SplitN(f.Names()[0], ", ", 2) // only long name will be offered flagsItems = append(flagsItems, readline.PcItem("--"+names[0])) } pcItems = append(pcItems, readline.PcItem(c.Name, flagsItems...)) @@ -459,7 +462,7 @@ func NewWithConfig(printLogotype bool, onExit func(int), c *readline.Config, cfg log, _, logCloser, err := options.HandleLoggingParams(false, cfg.ApplicationConfiguration) if err != nil { - return nil, cli.NewExitError(fmt.Errorf("failed to init logger: %w", err), 1) + return nil, cli.Exit(fmt.Errorf("failed to init logger: %w", err), 1) } filter := zap.WrapCore(func(z zapcore.Core) zapcore.Core { return options.NewFilteringCore(z, func(entry zapcore.Entry) bool { @@ -479,12 +482,12 @@ func NewWithConfig(printLogotype bool, onExit func(int), c *readline.Config, cfg chain, err := core.NewBlockchain(store, cfg.Blockchain(), fLog) if err != nil { - return nil, cli.NewExitError(fmt.Errorf("could not initialize blockchain: %w", err), 1) + return nil, cli.Exit(fmt.Errorf("could not initialize blockchain: %w", err), 1) } // Do not run chain, we need only state-related functionality from it. ic, err := chain.GetTestVM(trigger.Application, nil, nil) if err != nil { - return nil, cli.NewExitError(fmt.Errorf("failed to create test VM: %w", err), 1) + return nil, cli.Exit(fmt.Errorf("failed to create test VM: %w", err), 1) } vmcli := CLI{ @@ -610,7 +613,7 @@ func handleJump(c *cli.Context) error { } func getInstructionParameter(c *cli.Context) (int, error) { - args := c.Args() + args := c.Args().Slice() if len(args) != 1 { return 0, fmt.Errorf("%w: ", ErrMissingParameter) } @@ -690,7 +693,7 @@ func getHashFlag(c *cli.Context) (util.Uint160, error) { } func handleLoadNEF(c *cli.Context) error { - args := c.Args() + args := c.Args().Slice() if len(args) < 1 { return fmt.Errorf("%w: is required", ErrMissingParameter) } @@ -734,7 +737,7 @@ func handleLoadNEF(c *cli.Context) error { } var signers []transaction.Signer if signersStartOffset != 0 && len(args) > signersStartOffset { - signers, err = cmdargs.ParseSigners(c.Args()[signersStartOffset:]) + signers, err = cmdargs.ParseSigners(args[signersStartOffset:]) if err != nil { return fmt.Errorf("%w: failed to parse signers: %w", ErrInvalidParameter, err) } @@ -761,7 +764,7 @@ func handleLoadNEF(c *cli.Context) error { } func handleLoadBase64(c *cli.Context) error { - args := c.Args() + args := c.Args().Slice() if len(args) < 1 { return fmt.Errorf("%w: ", ErrMissingParameter) } @@ -801,7 +804,7 @@ func createFakeTransaction(script []byte, signers []transaction.Signer) *transac } func handleLoadHex(c *cli.Context) error { - args := c.Args() + args := c.Args().Slice() if len(args) < 1 { return fmt.Errorf("%w: ", ErrMissingParameter) } @@ -833,7 +836,7 @@ func handleLoadHex(c *cli.Context) error { } func handleLoadGo(c *cli.Context) error { - args := c.Args() + args := c.Args().Slice() if len(args) < 1 { return fmt.Errorf("%w: ", ErrMissingParameter) } @@ -885,7 +888,7 @@ func handleLoadGo(c *cli.Context) error { } func handleLoadTx(c *cli.Context) error { - args := c.Args() + args := c.Args().Slice() if len(args) < 1 { return fmt.Errorf("%w: ", ErrMissingParameter) } @@ -933,7 +936,7 @@ func handleLoadDeployed(c *cli.Context) error { if !c.Args().Present() { return errors.New("contract hash, address or ID is mandatory argument") } - args := c.Args() + args := c.Args().Slice() hashOrID := args[0] ic := getInteropContextFromContext(c.App) h, err := flags.ParseAddress(hashOrID) @@ -1062,7 +1065,7 @@ func getManifestFromFile(name string) (*manifest.Manifest, error) { func handleRun(c *cli.Context) error { v := getVMFromContext(c.App) cs := getContractStateFromContext(c.App) - args := c.Args() + args := c.Args().Slice() if len(args) != 0 { var ( params []stackitem.Item @@ -1181,7 +1184,7 @@ func handleStep(c *cli.Context) error { return nil } v := getVMFromContext(c.App) - args := c.Args() + args := c.Args().Slice() if len(args) > 0 { n, err = strconv.Atoi(args[0]) if err != nil { @@ -1422,7 +1425,7 @@ func (c *CLI) Run() error { } func handleParse(c *cli.Context) error { - res, err := Parse(c.Args()) + res, err := Parse(c.Args().Slice()) if err != nil { return err } diff --git a/cli/vm/cli_test.go b/cli/vm/cli_test.go index 63454271a..555c66fc9 100644 --- a/cli/vm/cli_test.go +++ b/cli/vm/cli_test.go @@ -1188,7 +1188,7 @@ func TestDumpStorage(t *testing.T) { "storage "+address.Uint160ToString(h), "storage 1", "storage 1 "+hex.EncodeToString(expected[0].Key), - "storage 1 --backwards", + "storage --backwards 1", "exit", ) e.checkStorage(t, expected...) @@ -1214,11 +1214,11 @@ func TestDumpStorageDiff(t *testing.T) { diff := storage.KeyValue{Key: []byte{3}, Value: []byte{3}} e.runProg(t, "storage 1", - "storage 1 --diff", + "storage --diff 1", "loadhex "+hex.EncodeToString(script.Bytes()), "run", "storage 1", - "storage 1 --diff", + "storage --diff 1", "exit", ) diff --git a/cli/vm/vm.go b/cli/vm/vm.go index ca7a5a11f..49eb932cf 100644 --- a/cli/vm/vm.go +++ b/cli/vm/vm.go @@ -8,14 +8,14 @@ import ( "github.com/nspcc-dev/neo-go/cli/cmdargs" "github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // NewCommands returns 'vm' command. -func NewCommands() []cli.Command { +func NewCommands() []*cli.Command { cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath} cfgFlags = append(cfgFlags, options.Network...) - return []cli.Command{{ + return []*cli.Command{{ Name: "vm", Usage: "Start the virtual machine", Action: startVMPrompt, @@ -30,7 +30,7 @@ func startVMPrompt(ctx *cli.Context) error { cfg, err := options.GetConfigFromContext(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if ctx.NumFlags() == 0 { cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.InMemoryDB @@ -42,7 +42,7 @@ func startVMPrompt(ctx *cli.Context) error { p, err := NewWithConfig(true, os.Exit, &readline.Config{}, cfg) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to create VM CLI: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to create VM CLI: %w", err), 1) } return p.Run() } diff --git a/cli/wallet/multisig.go b/cli/wallet/multisig.go index f6d600da9..9c3f2ed6d 100644 --- a/cli/wallet/multisig.go +++ b/cli/wallet/multisig.go @@ -12,7 +12,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func signStoredTransaction(ctx *cli.Context) error { @@ -28,52 +28,52 @@ func signStoredTransaction(ctx *cli.Context) error { pc, err := paramcontext.Read(ctx.String("in")) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if !addrFlag.IsSet { - return cli.NewExitError("address was not provided", 1) + return cli.Exit("address was not provided", 1) } acc, _, err := options.GetAccFromContext(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } tx, ok := pc.Verifiable.(*transaction.Transaction) if !ok { - return cli.NewExitError("verifiable item is not a transaction", 1) + return cli.Exit("verifiable item is not a transaction", 1) } if !tx.HasSigner(acc.ScriptHash()) { - return cli.NewExitError("tx signers don't contain provided account", 1) + return cli.Exit("tx signers don't contain provided account", 1) } if acc.CanSign() { sign := acc.SignHashable(pc.Network, pc.Verifiable) if err := pc.AddSignature(acc.ScriptHash(), acc.Contract, acc.PublicKey(), sign); err != nil { - return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1) + return cli.Exit(fmt.Errorf("can't add signature: %w", err), 1) } } else if rpcNode == "" { - return cli.NewExitError(fmt.Errorf("can't sign transactions with the given account and no RPC endpoing given to send anything signed"), 1) + return cli.Exit(fmt.Errorf("can't sign transactions with the given account and no RPC endpoing given to send anything signed"), 1) } // Not saving and not sending, print. if out == "" && rpcNode == "" { txt, err := json.MarshalIndent(pc, " ", " ") if err != nil { - return cli.NewExitError(fmt.Errorf("can't display resulting context: %w", err), 1) + return cli.Exit(fmt.Errorf("can't display resulting context: %w", err), 1) } fmt.Fprintln(ctx.App.Writer, string(txt)) return nil } if out != "" { if err := paramcontext.Save(pc, out); err != nil { - return cli.NewExitError(fmt.Errorf("can't save resulting context: %w", err), 1) + return cli.Exit(fmt.Errorf("can't save resulting context: %w", err), 1) } } if rpcNode != "" { tx, err = pc.GetCompleteTransaction() if err != nil { - return cli.NewExitError(fmt.Errorf("failed to complete transaction: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to complete transaction: %w", err), 1) } gctx, cancel := options.GetTimeoutContext(ctx) @@ -82,17 +82,17 @@ func signStoredTransaction(ctx *cli.Context) error { var err error // `GetRPCClient` returns specialized type. c, err := options.GetRPCClient(gctx, ctx) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to create RPC client: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to create RPC client: %w", err), 1) } res, err := c.SendRawTransaction(tx) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1) + return cli.Exit(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1) } if ctx.Bool("await") { version, err := c.GetVersion() aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", res.StringLE(), err), 1) + return cli.Exit(fmt.Errorf("failed to await transaction %s: %w", res.StringLE(), err), 1) } } } diff --git a/cli/wallet/nep11.go b/cli/wallet/nep11.go index 072d81381..a74e83077 100644 --- a/cli/wallet/nep11.go +++ b/cli/wallet/nep11.go @@ -19,20 +19,20 @@ import ( "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/wallet" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) -func newNEP11Commands() []cli.Command { +func newNEP11Commands() []*cli.Command { maxIters := strconv.Itoa(config.DefaultMaxIteratorResultItems) - tokenAddressFlag := flags.AddressFlag{ + tokenAddressFlag := &flags.AddressFlag{ Name: "token", Usage: "Token contract address or hash in LE", } - ownerAddressFlag := flags.AddressFlag{ + ownerAddressFlag := &flags.AddressFlag{ Name: "address", Usage: "NFT owner address or hash in LE", } - tokenID := cli.StringFlag{ + tokenID := &cli.StringFlag{ Name: "id", Usage: "Hex-encoded token ID", } @@ -45,7 +45,7 @@ func newNEP11Commands() []cli.Command { copy(transferFlags, baseTransferFlags) transferFlags = append(transferFlags, tokenID) transferFlags = append(transferFlags, options.RPC...) - return []cli.Command{ + return []*cli.Command{ { Name: "balance", Usage: "Get address balance", @@ -247,16 +247,16 @@ func printNEP11Owner(ctx *cli.Context, divisible bool) error { } tokenHash := ctx.Generic("token").(*flags.Address) if !tokenHash.IsSet { - return cli.NewExitError("token contract hash was not set", 1) + return cli.Exit("token contract hash was not set", 1) } tokenID := ctx.String("id") if tokenID == "" { - return cli.NewExitError(errors.New("token ID should be specified"), 1) + return cli.Exit(errors.New("token ID should be specified"), 1) } tokenIDBytes, err := hex.DecodeString(tokenID) if err != nil { - return cli.NewExitError(fmt.Errorf("invalid tokenID bytes: %w", err), 1) + return cli.Exit(fmt.Errorf("invalid tokenID bytes: %w", err), 1) } gctx, cancel := options.GetTimeoutContext(ctx) @@ -271,7 +271,7 @@ func printNEP11Owner(ctx *cli.Context, divisible bool) error { n11 := nep11.NewDivisibleReader(inv, tokenHash.Uint160()) result, err := n11.OwnerOfExpanded(tokenIDBytes, config.DefaultMaxIteratorResultItems) if err != nil { - return cli.NewExitError(fmt.Sprintf("failed to call NEP-11 divisible `ownerOf` method: %s", err.Error()), 1) + return cli.Exit(fmt.Sprintf("failed to call NEP-11 divisible `ownerOf` method: %s", err.Error()), 1) } for _, h := range result { fmt.Fprintln(ctx.App.Writer, address.Uint160ToString(h)) @@ -280,7 +280,7 @@ func printNEP11Owner(ctx *cli.Context, divisible bool) error { n11 := nep11.NewNonDivisibleReader(inv, tokenHash.Uint160()) result, err := n11.OwnerOf(tokenIDBytes) if err != nil { - return cli.NewExitError(fmt.Sprintf("failed to call NEP-11 non-divisible `ownerOf` method: %s", err.Error()), 1) + return cli.Exit(fmt.Sprintf("failed to call NEP-11 non-divisible `ownerOf` method: %s", err.Error()), 1) } fmt.Fprintln(ctx.App.Writer, address.Uint160ToString(result)) } @@ -292,12 +292,12 @@ func printNEP11TokensOf(ctx *cli.Context) error { var err error tokenHash := ctx.Generic("token").(*flags.Address) if !tokenHash.IsSet { - return cli.NewExitError("token contract hash was not set", 1) + return cli.Exit("token contract hash was not set", 1) } acc := ctx.Generic("address").(*flags.Address) if !acc.IsSet { - return cli.NewExitError("owner address flag was not set", 1) + return cli.Exit("owner address flag was not set", 1) } gctx, cancel := options.GetTimeoutContext(ctx) @@ -311,7 +311,7 @@ func printNEP11TokensOf(ctx *cli.Context) error { n11 := nep11.NewBaseReader(inv, tokenHash.Uint160()) result, err := n11.TokensOfExpanded(acc.Uint160(), config.DefaultMaxIteratorResultItems) if err != nil { - return cli.NewExitError(fmt.Sprintf("failed to call NEP-11 `tokensOf` method: %s", err.Error()), 1) + return cli.Exit(fmt.Sprintf("failed to call NEP-11 `tokensOf` method: %s", err.Error()), 1) } for i := range result { @@ -327,7 +327,7 @@ func printNEP11Tokens(ctx *cli.Context) error { } tokenHash := ctx.Generic("token").(*flags.Address) if !tokenHash.IsSet { - return cli.NewExitError("token contract hash was not set", 1) + return cli.Exit("token contract hash was not set", 1) } gctx, cancel := options.GetTimeoutContext(ctx) @@ -341,7 +341,7 @@ func printNEP11Tokens(ctx *cli.Context) error { n11 := nep11.NewBaseReader(inv, tokenHash.Uint160()) result, err := n11.TokensExpanded(config.DefaultMaxIteratorResultItems) if err != nil { - return cli.NewExitError(fmt.Sprintf("failed to call optional NEP-11 `tokens` method: %s", err.Error()), 1) + return cli.Exit(fmt.Sprintf("failed to call optional NEP-11 `tokens` method: %s", err.Error()), 1) } for i := range result { @@ -357,16 +357,16 @@ func printNEP11Properties(ctx *cli.Context) error { } tokenHash := ctx.Generic("token").(*flags.Address) if !tokenHash.IsSet { - return cli.NewExitError("token contract hash was not set", 1) + return cli.Exit("token contract hash was not set", 1) } tokenID := ctx.String("id") if tokenID == "" { - return cli.NewExitError(errors.New("token ID should be specified"), 1) + return cli.Exit(errors.New("token ID should be specified"), 1) } tokenIDBytes, err := hex.DecodeString(tokenID) if err != nil { - return cli.NewExitError(fmt.Errorf("invalid tokenID bytes: %w", err), 1) + return cli.Exit(fmt.Errorf("invalid tokenID bytes: %w", err), 1) } gctx, cancel := options.GetTimeoutContext(ctx) @@ -380,12 +380,12 @@ func printNEP11Properties(ctx *cli.Context) error { n11 := nep11.NewBaseReader(inv, tokenHash.Uint160()) result, err := n11.Properties(tokenIDBytes) if err != nil { - return cli.NewExitError(fmt.Sprintf("failed to call NEP-11 `properties` method: %s", err.Error()), 1) + return cli.Exit(fmt.Sprintf("failed to call NEP-11 `properties` method: %s", err.Error()), 1) } bytes, err := stackitem.ToJSON(result) if err != nil { - return cli.NewExitError(fmt.Sprintf("failed to convert result to JSON: %s", err), 1) + return cli.Exit(fmt.Sprintf("failed to convert result to JSON: %s", err), 1) } fmt.Fprintln(ctx.App.Writer, string(bytes)) return nil diff --git a/cli/wallet/nep17.go b/cli/wallet/nep17.go index 02f8730c6..f0f17f478 100644 --- a/cli/wallet/nep17.go +++ b/cli/wallet/nep17.go @@ -27,7 +27,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/wallet" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // transferTarget represents target address, token amount and data for transfer. @@ -39,7 +39,7 @@ type transferTarget struct { } var ( - tokenFlag = cli.StringFlag{ + tokenFlag = &cli.StringFlag{ Name: "token", Usage: "Token to use (hash or name (for NEO/GAS or imported tokens))", } @@ -47,15 +47,16 @@ var ( walletPathFlag, walletConfigFlag, tokenFlag, - flags.AddressFlag{ - Name: "address, a", - Usage: "Address to use", + &flags.AddressFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Address to use", }, } importFlags = append([]cli.Flag{ walletPathFlag, walletConfigFlag, - flags.AddressFlag{ + &flags.AddressFlag{ Name: "token", Usage: "Token contract address or hash in LE", }, @@ -71,7 +72,7 @@ var ( txctx.SysGasFlag, txctx.ForceFlag, txctx.AwaitFlag, - cli.StringFlag{ + &cli.StringFlag{ Name: "amount", Usage: "Amount of asset to send", }, @@ -88,14 +89,14 @@ var ( }, options.RPC...) ) -func newNEP17Commands() []cli.Command { +func newNEP17Commands() []*cli.Command { balanceFlags := make([]cli.Flag, len(baseBalanceFlags)) copy(balanceFlags, baseBalanceFlags) balanceFlags = append(balanceFlags, options.RPC...) transferFlags := make([]cli.Flag, len(baseTransferFlags)) copy(transferFlags, baseTransferFlags) transferFlags = append(transferFlags, options.RPC...) - return []cli.Command{ + return []*cli.Command{ { Name: "balance", Usage: "Get address balance", @@ -222,7 +223,7 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte } wall, _, err := readWallet(ctx) if err != nil { - return cli.NewExitError(fmt.Errorf("bad wallet: %w", err), 1) + return cli.Exit(fmt.Errorf("bad wallet: %w", err), 1) } defer wall.Close() @@ -231,12 +232,12 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte addrHash := addrFlag.Uint160() acc := wall.GetAccount(addrHash) if acc == nil { - return cli.NewExitError(fmt.Errorf("can't find account for the address: %s", address.Uint160ToString(addrHash)), 1) + return cli.Exit(fmt.Errorf("can't find account for the address: %s", address.Uint160ToString(addrHash)), 1) } accounts = append(accounts, acc) } else { if len(wall.Accounts) == 0 { - return cli.NewExitError(errors.New("no accounts in the wallet"), 1) + return cli.Exit(errors.New("no accounts in the wallet"), 1) } accounts = wall.Accounts } @@ -246,7 +247,7 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte c, err := options.GetRPCClient(gctx, ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } name := ctx.String("token") @@ -274,7 +275,7 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte // But if we have an exact hash, it must be correct. token, err = getTokenWithStandard(c, h, standard) if err != nil { - return cli.NewExitError(fmt.Errorf("%q is not a valid %s token: %w", name, standard, err), 1) + return cli.Exit(fmt.Errorf("%q is not a valid %s token: %w", name, standard, err), 1) } } } @@ -284,7 +285,7 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte if len(tokenID) > 0 { _, err = hex.DecodeString(tokenID) if err != nil { - return cli.NewExitError(fmt.Errorf("invalid token ID: %w", err), 1) + return cli.Exit(fmt.Errorf("invalid token ID: %w", err), 1) } } } @@ -296,7 +297,7 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte err = accHandler(ctx, c, acc.ScriptHash(), name, token, tokenID) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } } return nil @@ -388,20 +389,20 @@ func importNEPToken(ctx *cli.Context, standard string) error { } wall, _, err := openWallet(ctx, true) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() tokenHashFlag := ctx.Generic("token").(*flags.Address) if !tokenHashFlag.IsSet { - return cli.NewExitError("token contract hash was not set", 1) + return cli.Exit("token contract hash was not set", 1) } tokenHash := tokenHashFlag.Uint160() for _, t := range wall.Extra.Tokens { if t.Hash.Equals(tokenHash) && t.Standard == standard { printTokenInfo(ctx, t) - return cli.NewExitError(fmt.Errorf("%s token already exists", standard), 1) + return cli.Exit(fmt.Errorf("%s token already exists", standard), 1) } } @@ -410,17 +411,17 @@ func importNEPToken(ctx *cli.Context, standard string) error { c, err := options.GetRPCClient(gctx, ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } tok, err := getTokenWithStandard(c, tokenHash, standard) if err != nil { - return cli.NewExitError(fmt.Errorf("can't receive token info: %w", err), 1) + return cli.Exit(fmt.Errorf("can't receive token info: %w", err), 1) } wall.AddToken(tok) if err := wall.Save(); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } printTokenInfo(ctx, tok) return nil @@ -457,14 +458,14 @@ func printNEPInfo(ctx *cli.Context, standard string) error { } wall, _, err := readWallet(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() if name := ctx.String("token"); name != "" { token, err := getMatchingToken(ctx, wall, name, standard) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } printTokenInfo(ctx, token) return nil @@ -493,13 +494,13 @@ func removeNEPToken(ctx *cli.Context, standard string) error { } wall, _, err := openWallet(ctx, true) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() token, err := getMatchingToken(ctx, wall, ctx.String("token"), standard) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if !ctx.Bool("force") { if ok := askForConsent(ctx.App.Writer); !ok { @@ -507,9 +508,9 @@ func removeNEPToken(ctx *cli.Context, standard string) error { } } if err := wall.RemoveToken(token.Hash); err != nil { - return cli.NewExitError(fmt.Errorf("can't remove token: %w", err), 1) + return cli.Exit(fmt.Errorf("can't remove token: %w", err), 1) } else if err := wall.Save(); err != nil { - return cli.NewExitError(fmt.Errorf("error while saving wallet: %w", err), 1) + return cli.Exit(fmt.Errorf("error while saving wallet: %w", err), 1) } return nil } @@ -517,25 +518,25 @@ func removeNEPToken(ctx *cli.Context, standard string) error { func multiTransferNEP17(ctx *cli.Context) error { wall, pass, err := readWallet(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() fromFlag := ctx.Generic("from").(*flags.Address) from, err := getDefaultAddress(fromFlag, wall) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } acc, err := options.GetUnlockedAccount(wall, from, pass) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } gctx, cancel := options.GetTimeoutContext(ctx) defer cancel() if ctx.NArg() == 0 { - return cli.NewExitError("empty recipients list", 1) + return cli.Exit("empty recipients list", 1) } var ( recipients []transferTarget @@ -554,7 +555,7 @@ func multiTransferNEP17(ctx *cli.Context) error { } signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry) if err != nil { - return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1) + return cli.Exit(fmt.Errorf("invalid signers: %w", err), 1) } c, act, exitErr := options.GetRPCWithActor(gctx, ctx, signersAccounts) if exitErr != nil { @@ -566,7 +567,7 @@ func multiTransferNEP17(ctx *cli.Context) error { arg := ctx.Args().Get(i) ss := strings.SplitN(arg, ":", 3) if len(ss) != 3 { - return cli.NewExitError("send format must be '::", 1) + return cli.Exit("send format must be '::", 1) } token, ok := cache[ss[0]] if !ok { @@ -574,18 +575,18 @@ func multiTransferNEP17(ctx *cli.Context) error { if err != nil { token, err = getMatchingTokenRPC(ctx, c, from, ss[0], manifest.NEP17StandardName) if err != nil { - return cli.NewExitError(fmt.Errorf("can't fetch matching token from RPC-node: %w", err), 1) + return cli.Exit(fmt.Errorf("can't fetch matching token from RPC-node: %w", err), 1) } } } cache[ss[0]] = token addr, err := address.StringToUint160(ss[1]) if err != nil { - return cli.NewExitError(fmt.Errorf("invalid address: '%s'", ss[1]), 1) + return cli.Exit(fmt.Errorf("invalid address: '%s'", ss[1]), 1) } amount, err := fixedn.FromString(ss[2], int(token.Decimals)) if err != nil { - return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1) + return cli.Exit(fmt.Errorf("invalid amount: %w", err), 1) } recipients = append(recipients, transferTarget{ Token: token.Hash, @@ -597,7 +598,7 @@ func multiTransferNEP17(ctx *cli.Context) error { tx, err := makeMultiTransferNEP17(act, recipients) if err != nil { - return cli.NewExitError(fmt.Errorf("can't make transaction: %w", err), 1) + return cli.Exit(fmt.Errorf("can't make transaction: %w", err), 1) } return txctx.SignAndSend(ctx, act, acc, tx) } @@ -611,18 +612,18 @@ func transferNEP(ctx *cli.Context, standard string) error { wall, pass, err := readWallet(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() fromFlag := ctx.Generic("from").(*flags.Address) from, err := getDefaultAddress(fromFlag, wall) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } acc, err := options.GetUnlockedAccount(wall, from, pass) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } gctx, cancel := options.GetTimeoutContext(ctx) @@ -638,7 +639,7 @@ func transferNEP(ctx *cli.Context, standard string) error { } signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry) if err != nil { - return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1) + return cli.Exit(fmt.Errorf("invalid signers: %w", err), 1) } c, act, exitErr := options.GetRPCWithActor(gctx, ctx, signersAccounts) @@ -648,14 +649,14 @@ func transferNEP(ctx *cli.Context, standard string) error { toFlag := ctx.Generic("to").(*flags.Address) if !toFlag.IsSet { - return cli.NewExitError(errors.New("missing receiver address (--to)"), 1) + return cli.Exit(errors.New("missing receiver address (--to)"), 1) } to := toFlag.Uint160() token, err := getMatchingToken(ctx, wall, ctx.String("token"), standard) if err != nil { token, err = getMatchingTokenRPC(ctx, c, from, ctx.String("token"), standard) if err != nil { - return cli.NewExitError(fmt.Errorf("can't fetch matching token from RPC-node: %w", err), 1) + return cli.Exit(fmt.Errorf("can't fetch matching token from RPC-node: %w", err), 1) } } @@ -663,7 +664,7 @@ func transferNEP(ctx *cli.Context, standard string) error { amount, err := fixedn.FromString(amountArg, int(token.Decimals)) // It's OK for NEP-11 transfer to not have amount set. if err != nil && (standard == manifest.NEP17StandardName || amountArg != "") { - return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1) + return cli.Exit(fmt.Errorf("invalid amount: %w", err), 1) } switch standard { case manifest.NEP17StandardName: @@ -672,11 +673,11 @@ func transferNEP(ctx *cli.Context, standard string) error { case manifest.NEP11StandardName: tokenID := ctx.String("id") if tokenID == "" { - return cli.NewExitError(errors.New("token ID should be specified"), 1) + return cli.Exit(errors.New("token ID should be specified"), 1) } tokenIDBytes, terr := hex.DecodeString(tokenID) if terr != nil { - return cli.NewExitError(fmt.Errorf("invalid token ID: %w", terr), 1) + return cli.Exit(fmt.Errorf("invalid token ID: %w", terr), 1) } if amountArg == "" { n11 := nep11.NewNonDivisible(act, token.Hash) @@ -686,10 +687,10 @@ func transferNEP(ctx *cli.Context, standard string) error { tx, err = n11.TransferDUnsigned(act.Sender(), to, amount, tokenIDBytes, data) } default: - return cli.NewExitError(fmt.Errorf("unsupported token standard %s", standard), 1) + return cli.Exit(fmt.Errorf("unsupported token standard %s", standard), 1) } if err != nil { - return cli.NewExitError(fmt.Errorf("can't make transaction: %w", err), 1) + return cli.Exit(fmt.Errorf("can't make transaction: %w", err), 1) } return txctx.SignAndSend(ctx, act, acc, tx) diff --git a/cli/wallet/validator.go b/cli/wallet/validator.go index 512c02045..cc6fd3a9b 100644 --- a/cli/wallet/validator.go +++ b/cli/wallet/validator.go @@ -12,11 +12,11 @@ import ( "github.com/nspcc-dev/neo-go/pkg/rpcclient/neo" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/wallet" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) -func newValidatorCommands() []cli.Command { - return []cli.Command{ +func newValidatorCommands() []*cli.Command { + return []*cli.Command{ { Name: "register", Usage: "Register as a new candidate", @@ -30,9 +30,10 @@ func newValidatorCommands() []cli.Command { txctx.OutFlag, txctx.ForceFlag, txctx.AwaitFlag, - flags.AddressFlag{ - Name: "address, a", - Usage: "Address to register", + &flags.AddressFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Address to register", }, }, options.RPC...), }, @@ -49,9 +50,10 @@ func newValidatorCommands() []cli.Command { txctx.OutFlag, txctx.ForceFlag, txctx.AwaitFlag, - flags.AddressFlag{ - Name: "address, a", - Usage: "Address to unregister", + &flags.AddressFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Address to unregister", }, }, options.RPC...), }, @@ -72,13 +74,15 @@ func newValidatorCommands() []cli.Command { txctx.OutFlag, txctx.ForceFlag, txctx.AwaitFlag, - flags.AddressFlag{ - Name: "address, a", - Usage: "Address to vote from", + &flags.AddressFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Address to vote from", }, - cli.StringFlag{ - Name: "candidate, c", - Usage: "Public key of candidate to vote for", + &cli.StringFlag{ + Name: "candidate", + Aliases: []string{"c"}, + Usage: "Public key of candidate to vote for", }, }, options.RPC...), }, @@ -103,18 +107,18 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w } wall, pass, err := readWallet(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() addrFlag := ctx.Generic("address").(*flags.Address) if !addrFlag.IsSet { - return cli.NewExitError("address was not provided", 1) + return cli.Exit("address was not provided", 1) } addr := addrFlag.Uint160() acc, err := options.GetUnlockedAccount(wall, addr, pass) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } gctx, cancel := options.GetTimeoutContext(ctx) @@ -122,7 +126,7 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w signers, err := cmdargs.GetSignersAccounts(acc, wall, nil, transaction.CalledByEntry) if err != nil { - return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1) + return cli.Exit(fmt.Errorf("invalid signers: %w", err), 1) } _, act, exitErr := options.GetRPCWithActor(gctx, ctx, signers) if exitErr != nil { @@ -132,7 +136,7 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w contract := neo.New(act) tx, err := mkTx(contract, addr, acc) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } return txctx.SignAndSend(ctx, act, acc, tx) } diff --git a/cli/wallet/wallet.go b/cli/wallet/wallet.go index 1f9bc9701..4d7e8dfee 100644 --- a/cli/wallet/wallet.go +++ b/cli/wallet/wallet.go @@ -24,7 +24,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/wallet" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) const ( @@ -47,38 +47,40 @@ var ( ) var ( - walletPathFlag = cli.StringFlag{ - Name: "wallet, w", - Usage: "Path to the wallet file ('-' to read from stdin); conflicts with --wallet-config flag.", + walletPathFlag = &cli.StringFlag{ + Name: "wallet", + Aliases: []string{"w"}, + Usage: "Path to the wallet file ('-' to read from stdin); conflicts with --wallet-config flag.", } - walletConfigFlag = cli.StringFlag{ + walletConfigFlag = &cli.StringFlag{ Name: "wallet-config", Usage: "Path to the wallet config file; conflicts with --wallet flag.", } - wifFlag = cli.StringFlag{ + wifFlag = &cli.StringFlag{ Name: "wif", Usage: "WIF to import", } - decryptFlag = cli.BoolFlag{ - Name: "decrypt, d", - Usage: "Decrypt encrypted keys.", + decryptFlag = &cli.BoolFlag{ + Name: "decrypt", + Aliases: []string{"d"}, + Usage: "Decrypt encrypted keys.", } - inFlag = cli.StringFlag{ + inFlag = &cli.StringFlag{ Name: "in", Usage: "File with JSON transaction", } - fromAddrFlag = flags.AddressFlag{ + fromAddrFlag = &flags.AddressFlag{ Name: "from", Usage: "Address to send an asset from", } - toAddrFlag = flags.AddressFlag{ + toAddrFlag = &flags.AddressFlag{ Name: "to", Usage: "Address to send an asset to", } ) // NewCommands returns 'wallet' command. -func NewCommands() []cli.Command { +func NewCommands() []*cli.Command { claimFlags := []cli.Flag{ walletPathFlag, walletConfigFlag, @@ -87,9 +89,10 @@ func NewCommands() []cli.Command { txctx.OutFlag, txctx.ForceFlag, txctx.AwaitFlag, - flags.AddressFlag{ - Name: "address, a", - Usage: "Address to claim GAS for", + &flags.AddressFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Address to claim GAS for", }, } claimFlags = append(claimFlags, options.RPC...) @@ -99,16 +102,17 @@ func NewCommands() []cli.Command { txctx.OutFlag, txctx.AwaitFlag, inFlag, - flags.AddressFlag{ - Name: "address, a", - Usage: "Address to use", + &flags.AddressFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Address to use", }, } signFlags = append(signFlags, options.RPC...) - return []cli.Command{{ + return []*cli.Command{{ Name: "wallet", Usage: "Create, open and manage a Neo wallet", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "claim", Usage: "Claim GAS", @@ -124,9 +128,10 @@ func NewCommands() []cli.Command { Flags: []cli.Flag{ walletPathFlag, walletConfigFlag, - cli.BoolFlag{ - Name: "account, a", - Usage: "Create a new account", + &cli.BoolFlag{ + Name: "account", + Aliases: []string{"a"}, + Usage: "Create a new account", }, }, }, @@ -137,9 +142,10 @@ func NewCommands() []cli.Command { Action: changePassword, Flags: []cli.Flag{ walletPathFlag, - flags.AddressFlag{ - Name: "address, a", - Usage: "Address to change password for", + &flags.AddressFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Address to change password for", }, }, }, @@ -151,9 +157,10 @@ func NewCommands() []cli.Command { Flags: []cli.Flag{ walletPathFlag, walletConfigFlag, - cli.StringFlag{ - Name: "out, o", - Usage: "Where to write converted wallet", + &cli.StringFlag{ + Name: "out", + Aliases: []string{"o"}, + Usage: "Where to write converted wallet", }, }, }, @@ -191,9 +198,10 @@ func NewCommands() []cli.Command { Flags: []cli.Flag{ walletPathFlag, walletConfigFlag, - flags.AddressFlag{ - Name: "address, a", - Usage: "Address to print public keys for", + &flags.AddressFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Address to print public keys for", }, }, }, @@ -223,11 +231,12 @@ func NewCommands() []cli.Command { walletPathFlag, walletConfigFlag, wifFlag, - cli.StringFlag{ - Name: "name, n", - Usage: "Optional account name", + &cli.StringFlag{ + Name: "name", + Aliases: []string{"n"}, + Usage: "Optional account name", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "contract", Usage: "Verification script for custom contracts", }, @@ -250,13 +259,15 @@ func NewCommands() []cli.Command { walletPathFlag, walletConfigFlag, wifFlag, - cli.StringFlag{ - Name: "name, n", - Usage: "Optional account name", + &cli.StringFlag{ + Name: "name", + Aliases: []string{"n"}, + Usage: "Optional account name", }, - cli.IntFlag{ - Name: "min, m", - Usage: "Minimal number of signatures", + &cli.IntFlag{ + Name: "min", + Aliases: []string{"m"}, + Usage: "Minimal number of signatures", }, }, }, @@ -269,13 +280,15 @@ func NewCommands() []cli.Command { walletPathFlag, walletConfigFlag, wifFlag, - cli.StringFlag{ - Name: "name, n", - Usage: "Optional account name", + &cli.StringFlag{ + Name: "name", + Aliases: []string{"n"}, + Usage: "Optional account name", }, - flags.AddressFlag{ - Name: "contract, c", - Usage: "Contract hash or address", + &flags.AddressFlag{ + Name: "contract", + Aliases: []string{"c"}, + Usage: "Contract hash or address", }, }, options.RPC...), }, @@ -288,9 +301,10 @@ func NewCommands() []cli.Command { walletPathFlag, walletConfigFlag, txctx.ForceFlag, - flags.AddressFlag{ - Name: "address, a", - Usage: "Account address or hash in LE form to be removed", + &flags.AddressFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Account address or hash in LE form to be removed", }, }, }, @@ -358,24 +372,24 @@ func changePassword(ctx *cli.Context) error { } wall, _, err := openWallet(ctx, false) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() if len(wall.Accounts) == 0 { - return cli.NewExitError("wallet has no accounts", 1) + return cli.Exit("wallet has no accounts", 1) } addrFlag := ctx.Generic("address").(*flags.Address) if addrFlag.IsSet { // Check for account presence first before asking for password. acc := wall.GetAccount(addrFlag.Uint160()) if acc == nil { - return cli.NewExitError("account is missing", 1) + return cli.Exit("account is missing", 1) } } oldPass, err := input.ReadPassword(EnterOldPasswordPrompt) if err != nil { - return cli.NewExitError(fmt.Errorf("Error reading old password: %w", err), 1) + return cli.Exit(fmt.Errorf("Error reading old password: %w", err), 1) } for i := range wall.Accounts { @@ -384,13 +398,13 @@ func changePassword(ctx *cli.Context) error { } err := wall.Accounts[i].Decrypt(oldPass, wall.Scrypt) if err != nil { - return cli.NewExitError(fmt.Errorf("unable to decrypt account %s: %w", wall.Accounts[i].Address, err), 1) + return cli.Exit(fmt.Errorf("unable to decrypt account %s: %w", wall.Accounts[i].Address, err), 1) } } pass, err := readNewPassword() if err != nil { - return cli.NewExitError(fmt.Errorf("Error reading new password: %w", err), 1) + return cli.Exit(fmt.Errorf("Error reading new password: %w", err), 1) } for i := range wall.Accounts { if addrFlag.IsSet && wall.Accounts[i].Address != addrFlag.String() { @@ -398,12 +412,12 @@ func changePassword(ctx *cli.Context) error { } err := wall.Accounts[i].Encrypt(pass, wall.Scrypt) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } } err = wall.Save() if err != nil { - return cli.NewExitError(fmt.Errorf("Error saving the wallet: %w", err), 1) + return cli.Exit(fmt.Errorf("Error saving the wallet: %w", err), 1) } return nil } @@ -414,16 +428,16 @@ func convertWallet(ctx *cli.Context) error { } wall, pass, err := newWalletV2FromFile(ctx.String("wallet"), ctx.String("wallet-config")) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } out := ctx.String("out") if len(out) == 0 { - return cli.NewExitError("missing out path", 1) + return cli.Exit("missing out path", 1) } newWallet, err := wallet.NewWallet(out) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } newWallet.Scrypt = wall.Scrypt @@ -431,19 +445,19 @@ func convertWallet(ctx *cli.Context) error { if len(wall.Accounts) != 1 || pass == nil { password, err := input.ReadPassword(fmt.Sprintf("Enter password for account %s (label '%s') > ", acc.Address, acc.Label)) if err != nil { - return cli.NewExitError(fmt.Errorf("Error reading password: %w", err), 1) + return cli.Exit(fmt.Errorf("Error reading password: %w", err), 1) } pass = &password } newAcc, err := acc.convert(*pass, wall.Scrypt) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } newWallet.AddAccount(newAcc) } if err := newWallet.Save(); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } return nil } @@ -454,12 +468,12 @@ func addAccount(ctx *cli.Context) error { } wall, pass, err := openWallet(ctx, true) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() if err := createAccount(wall, pass); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } return nil @@ -468,7 +482,7 @@ func addAccount(ctx *cli.Context) error { func exportKeys(ctx *cli.Context) error { wall, pass, err := readWallet(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() @@ -476,13 +490,13 @@ func exportKeys(ctx *cli.Context) error { decrypt := ctx.Bool("decrypt") if ctx.NArg() == 0 && decrypt { - return cli.NewExitError(errors.New("address must be provided if '--decrypt' flag is used"), 1) + return cli.Exit(errors.New("address must be provided if '--decrypt' flag is used"), 1) } else if ctx.NArg() > 0 { // check address format just to catch possible typos addr = ctx.Args().First() _, err := address.StringToUint160(addr) if err != nil { - return cli.NewExitError(fmt.Errorf("can't parse address: %w", err), 1) + return cli.Exit(fmt.Errorf("can't parse address: %w", err), 1) } } @@ -508,14 +522,14 @@ loop: if pass == nil { password, err := input.ReadPassword(EnterPasswordPrompt) if err != nil { - return cli.NewExitError(fmt.Errorf("Error reading password: %w", err), 1) + return cli.Exit(fmt.Errorf("Error reading password: %w", err), 1) } pass = &password } pk, err := keys.NEP2Decrypt(wif, *pass, wall.Scrypt) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } wif = pk.WIF() @@ -536,22 +550,22 @@ func importMultisig(ctx *cli.Context) error { wall, pass, err := openWallet(ctx, true) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() m := ctx.Int("min") if ctx.NArg() < m { - return cli.NewExitError(errors.New("insufficient number of public keys"), 1) + return cli.Exit(errors.New("insufficient number of public keys"), 1) } - args := []string(ctx.Args()) + args := ctx.Args().Slice() pubs := make([]*keys.PublicKey, len(args)) for i := range args { pubs[i], err = keys.NewPublicKeyFromString(args[i]) if err != nil { - return cli.NewExitError(fmt.Errorf("can't decode public key %d: %w", i, err), 1) + return cli.Exit(fmt.Errorf("can't decode public key %d: %w", i, err), 1) } } @@ -579,31 +593,31 @@ loop: if acc != nil { err = acc.ConvertMultisigEncrypted(accPub, m, pubs) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if label != nil { acc.Label = *label } if err := addAccountAndSave(wall, acc); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } return nil } if !ctx.IsSet("wif") { - return cli.NewExitError(errors.New("none of the provided public keys correspond to an existing key in the wallet or multiple matching accounts found in the wallet, and no WIF is provided"), 1) + return cli.Exit(errors.New("none of the provided public keys correspond to an existing key in the wallet or multiple matching accounts found in the wallet, and no WIF is provided"), 1) } acc, err = newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if err := acc.ConvertMultisig(m, pubs); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if err := addAccountAndSave(wall, acc); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } return nil @@ -615,13 +629,13 @@ func importDeployed(ctx *cli.Context) error { } wall, pass, err := openWallet(ctx, true) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() rawHash := ctx.Generic("contract").(*flags.Address) if !rawHash.IsSet { - return cli.NewExitError("contract hash was not provided", 1) + return cli.Exit("contract hash was not provided", 1) } var label *string @@ -631,7 +645,7 @@ func importDeployed(ctx *cli.Context) error { } acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } gctx, cancel := options.GetTimeoutContext(ctx) @@ -639,16 +653,16 @@ func importDeployed(ctx *cli.Context) error { c, err := options.GetRPCClient(gctx, ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } cs, err := c.GetContractStateByHash(rawHash.Uint160()) if err != nil { - return cli.NewExitError(fmt.Errorf("can't fetch contract info: %w", err), 1) + return cli.Exit(fmt.Errorf("can't fetch contract info: %w", err), 1) } md := cs.Manifest.ABI.GetMethod(manifest.MethodVerify, -1) if md == nil || md.ReturnType != smartcontract.BoolType { - return cli.NewExitError("contract has no `verify` method with boolean return", 1) + return cli.Exit("contract has no `verify` method with boolean return", 1) } acc.Address = address.Uint160ToString(cs.Hash) // Explicitly overwrite single signature script of the provided WIF since the contract is known to be deployed. @@ -663,7 +677,7 @@ func importDeployed(ctx *cli.Context) error { acc.Contract.Deployed = true if err := addAccountAndSave(wall, acc); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } return nil @@ -675,7 +689,7 @@ func importWallet(ctx *cli.Context) error { } wall, pass, err := openWallet(ctx, true) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() @@ -687,19 +701,19 @@ func importWallet(ctx *cli.Context) error { acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if ctrFlag := ctx.String("contract"); ctrFlag != "" { ctr, err := hex.DecodeString(ctrFlag) if err != nil { - return cli.NewExitError("invalid contract", 1) + return cli.Exit("invalid contract", 1) } acc.Contract.Script = ctr } if err := addAccountAndSave(wall, acc); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } return nil @@ -711,17 +725,17 @@ func removeAccount(ctx *cli.Context) error { } wall, _, err := openWallet(ctx, true) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() addr := ctx.Generic("address").(*flags.Address) if !addr.IsSet { - return cli.NewExitError("valid account address must be provided", 1) + return cli.Exit("valid account address must be provided", 1) } acc := wall.GetAccount(addr.Uint160()) if acc == nil { - return cli.NewExitError("account wasn't found", 1) + return cli.Exit("account wasn't found", 1) } if !ctx.Bool("force") { @@ -732,10 +746,10 @@ func removeAccount(ctx *cli.Context) error { } if err := wall.RemoveAccount(acc.Address); err != nil { - return cli.NewExitError(fmt.Errorf("error on remove: %w", err), 1) + return cli.Exit(fmt.Errorf("error on remove: %w", err), 1) } if err := wall.Save(); err != nil { - return cli.NewExitError(fmt.Errorf("error while saving wallet: %w", err), 1) + return cli.Exit(fmt.Errorf("error while saving wallet: %w", err), 1) } return nil } @@ -758,14 +772,14 @@ func dumpWallet(ctx *cli.Context) error { } wall, pass, err := readWallet(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() if ctx.Bool("decrypt") { if pass == nil { password, err := input.ReadPassword(EnterPasswordPrompt) if err != nil { - return cli.NewExitError(fmt.Errorf("Error reading password: %w", err), 1) + return cli.Exit(fmt.Errorf("Error reading password: %w", err), 1) } pass = &password } @@ -773,7 +787,7 @@ func dumpWallet(ctx *cli.Context) error { // Just testing the decryption here. err := wall.Accounts[i].Decrypt(*pass, wall.Scrypt) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } } } @@ -787,7 +801,7 @@ func dumpKeys(ctx *cli.Context) error { } wall, _, err := readWallet(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() accounts := wall.Accounts @@ -796,7 +810,7 @@ func dumpKeys(ctx *cli.Context) error { if addrFlag.IsSet { acc := wall.GetAccount(addrFlag.Uint160()) if acc == nil { - return cli.NewExitError("account is missing", 1) + return cli.Exit("account is missing", 1) } accounts = []*wallet.Account{acc} } @@ -826,7 +840,7 @@ func dumpKeys(ctx *cli.Context) error { continue } if addrFlag.IsSet { - return cli.NewExitError(fmt.Errorf("unknown script type for address %s", address.Uint160ToString(addrFlag.Uint160())), 1) + return cli.Exit(fmt.Errorf("unknown script type for address %s", address.Uint160ToString(addrFlag.Uint160())), 1) } } return nil @@ -838,7 +852,7 @@ func stripKeys(ctx *cli.Context) error { } wall, _, err := readWallet(ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() if !ctx.Bool("force") { @@ -851,7 +865,7 @@ func stripKeys(ctx *cli.Context) error { a.EncryptedWIF = "" } if err := wall.Save(); err != nil { - return cli.NewExitError(fmt.Errorf("error while saving wallet: %w", err), 1) + return cli.Exit(fmt.Errorf("error while saving wallet: %w", err), 1) } return nil } @@ -867,28 +881,28 @@ func createWallet(ctx *cli.Context) error { return errConflictingWalletFlags } if len(path) == 0 && len(configPath) == 0 { - return cli.NewExitError(errNoPath, 1) + return cli.Exit(errNoPath, 1) } var pass *string if len(configPath) != 0 { cfg, err := options.ReadWalletConfig(configPath) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } path = cfg.Path pass = &cfg.Password } wall, err := wallet.NewWallet(path) if err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if err := wall.Save(); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } if ctx.Bool("account") { if err := createAccount(wall, pass); err != nil { - return cli.NewExitError(err, 1) + return cli.Exit(err, 1) } defer wall.Close() } @@ -949,14 +963,14 @@ func createAccount(wall *wallet.Wallet, pass *string) error { func openWallet(ctx *cli.Context, canUseWalletConfig bool) (*wallet.Wallet, *string, error) { path, pass, err := getWalletPathAndPass(ctx, canUseWalletConfig) if err != nil { - return nil, nil, cli.NewExitError(fmt.Errorf("failed to get wallet path or password: %w", err), 1) + return nil, nil, cli.Exit(fmt.Errorf("failed to get wallet path or password: %w", err), 1) } if path == "-" { return nil, nil, errNoStdin } w, err := wallet.NewWalletFromFile(path) if err != nil { - return nil, nil, cli.NewExitError(fmt.Errorf("failed to read wallet: %w", err), 1) + return nil, nil, cli.Exit(fmt.Errorf("failed to read wallet: %w", err), 1) } return w, pass, nil } diff --git a/cli/wallet/wallet_test.go b/cli/wallet/wallet_test.go index a6c828dda..a735388a9 100644 --- a/cli/wallet/wallet_test.go +++ b/cli/wallet/wallet_test.go @@ -992,7 +992,7 @@ func TestOfflineSigning(t *testing.T) { e.Run(t, "neo-go", "util", "sendtx", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], - txPath, "--await") + "--await", txPath) e.CheckAwaitableTxPersisted(t) }) } diff --git a/go.mod b/go.mod index 48ccd4eb4..8a85627d2 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 github.com/twmb/murmur3 v1.1.8 - github.com/urfave/cli v1.22.5 + github.com/urfave/cli/v2 v2.27.2 go.etcd.io/bbolt v1.3.9 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.21.0 @@ -42,7 +42,7 @@ require ( github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/consensys/bavard v0.1.13 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/frankban/quicktest v1.14.5 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -60,6 +60,7 @@ require ( github.com/rs/zerolog v1.30.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/x448/float16 v0.8.4 // indirect + github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/mod v0.16.0 // indirect diff --git a/go.sum b/go.sum index e791eceff..213490dad 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -22,9 +21,8 @@ github.com/consensys/gnark v0.9.1/go.mod h1:udWvWGXnfBE7mn7BsNoGAvZDnUhcONBEtNij github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb h1:f0BMgIjhZy4lSRHCXFbQst85f5agZAjtDMixQqBWNpc= github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -131,20 +129,20 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg= github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= -github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= -github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= +github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -216,7 +214,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/internal/testcli/executor.go b/internal/testcli/executor.go index 2fec7f8b1..072738417 100644 --- a/internal/testcli/executor.go +++ b/internal/testcli/executor.go @@ -34,7 +34,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm/vmstate" "github.com/stretchr/testify/require" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" "go.uber.org/zap" "go.uber.org/zap/zaptest" "golang.org/x/term" diff --git a/scripts/compare-dumps/compare-dumps.go b/scripts/compare-dumps/compare-dumps.go index 4b78eeffe..4e5621498 100644 --- a/scripts/compare-dumps/compare-dumps.go +++ b/scripts/compare-dumps/compare-dumps.go @@ -12,7 +12,7 @@ import ( "path/filepath" "sort" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) var ledgerContractID = -4 diff --git a/scripts/compare-states/compare-states.go b/scripts/compare-states/compare-states.go index 989d52628..dcefeecfa 100644 --- a/scripts/compare-states/compare-states.go +++ b/scripts/compare-states/compare-states.go @@ -10,7 +10,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/rpcclient" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/pmezard/go-difflib/difflib" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) var errStateMatches = errors.New("state matches") @@ -167,9 +167,10 @@ func main() { ctl.Usage = "compare-states RPC_A RPC_B" ctl.Action = cliMain ctl.Flags = []cli.Flag{ - cli.BoolFlag{ - Name: "ignore-height, g", - Usage: "Ignore height difference", + &cli.BoolFlag{ + Name: "ignore-height", + Aliases: []string{"h"}, + Usage: "Ignore height difference", }, }