cli: upgrade urfave lib to v2

Close #3097

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
This commit is contained in:
Ekaterina Pavlova 2024-07-09 21:24:39 +03:00
parent b32e568d21
commit acde7bd0de
39 changed files with 980 additions and 693 deletions

View file

@ -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) {

View file

@ -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
}

View file

@ -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 flags 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.

View file

@ -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)
}

View file

@ -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 flags value in the given Context.
func (f Fixed8Flag) Get(ctx *cli.Context) Fixed8 {
adr := ctx.Generic(f.Name).(*Fixed8)
return *adr
}

View file

@ -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())
}

View file

@ -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)
}
}

View file

@ -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)
}

View file

@ -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...)

View file

@ -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) {

View file

@ -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
}

View file

@ -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) {

View file

@ -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 <hash> -r endpoint [-s timeout] [-v]",
UsageText: "neo-go query tx -r endpoint [-s timeout] [-v] <hash>",
Action: queryTx,
Flags: queryTxFlags,
},
{
Name: "voter",
Usage: "Print NEO holder account state",
UsageText: "neo-go query voter <address> -r endpoint [-s timeout]",
UsageText: "neo-go query voter -r endpoint [-s timeout] <address>",
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 {

View file

@ -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
}

View file

@ -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"
)

View file

@ -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 <file.json> --out <file.go> [--hash <hash>] [--config <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 <file.json> --out <file.go> [--hash <hash>] [--config <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
}

View file

@ -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) {

View file

@ -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
}

View file

@ -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
}

View file

@ -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"
)

View file

@ -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)

View file

@ -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")
}

View file

@ -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 <endpoint>] <file.in> [--await]",
UsageText: "sendtx [-r <endpoint>] [--await] <file.in>",
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 <txid> -r <endpoint> --wallet <wallet> [--account <account>] [--wallet-config <path>] [--gas <gas>] [--await]",
UsageText: "canceltx -r <endpoint> --wallet <wallet> [--account <account>] [--wallet-config <path>] [--gas <gas>] [--await] <txid>",
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 <base64/hex-encoded script> [-i path-to-file] [--hex]",
UsageText: "ops [-i path-to-file] [--hex] <base64/hex-encoded script>",
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)

View file

@ -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))
}

View file

@ -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)

View file

@ -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 <hash-or-address-or-id> [<prefix>] [--backwards] [--diff]`,
UsageText: `storage [--backwards] [--diff] <hash-or-address-or-id> [<prefix>]`,
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: <ip>", 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: <nef> 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: <string>", 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: <string>", 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: <file>", 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: <file-or-hash>", 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
}

View file

@ -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",
)

View file

@ -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()
}

View file

@ -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)
}
}
}

View file

@ -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

View file

@ -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 '<token>:<addr>:<amount>", 1)
return cli.Exit("send format must be '<token>:<addr>:<amount>", 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)

View file

@ -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)
}

View file

@ -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
}

View file

@ -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)
})
}

5
go.mod
View file

@ -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

15
go.sum
View file

@ -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=

View file

@ -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"

View file

@ -12,7 +12,7 @@ import (
"path/filepath"
"sort"
"github.com/urfave/cli"
"github.com/urfave/cli/v2"
)
var ledgerContractID = -4

View file

@ -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",
},
}