mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-28 19:31:34 +00:00
Merge pull request #3495 from nspcc-dev/cli
cli: upgrade urfave lib to v2
This commit is contained in:
commit
c65d9f40e3
44 changed files with 1229 additions and 963 deletions
|
@ -12,7 +12,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/vm"
|
"github.com/nspcc-dev/neo-go/cli/vm"
|
||||||
"github.com/nspcc-dev/neo-go/cli/wallet"
|
"github.com/nspcc-dev/neo-go/cli/wallet"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func versionPrinter(c *cli.Context) {
|
func versionPrinter(c *cli.Context) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -138,16 +138,16 @@ const (
|
||||||
|
|
||||||
// GetSignersFromContext returns signers parsed from context args starting
|
// GetSignersFromContext returns signers parsed from context args starting
|
||||||
// from the specified offset.
|
// 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()
|
args := ctx.Args()
|
||||||
var (
|
var (
|
||||||
signers []transaction.Signer
|
signers []transaction.Signer
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if args.Present() && len(args) > offset {
|
if args.Present() && args.Len() > offset {
|
||||||
signers, err = ParseSigners(args[offset:])
|
signers, err = ParseSigners(args.Slice()[offset:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cli.NewExitError(err, 1)
|
return nil, cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return signers, nil
|
return signers, nil
|
||||||
|
@ -230,7 +230,7 @@ func parseCosigner(c string) (transaction.Signer, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDataFromContext returns data parameter from context args.
|
// 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 (
|
var (
|
||||||
data any
|
data any
|
||||||
offset int
|
offset int
|
||||||
|
@ -239,17 +239,17 @@ func GetDataFromContext(ctx *cli.Context) (int, any, *cli.ExitError) {
|
||||||
)
|
)
|
||||||
args := ctx.Args()
|
args := ctx.Args()
|
||||||
if args.Present() {
|
if args.Present() {
|
||||||
offset, params, err = ParseParams(args, true)
|
offset, params, err = ParseParams(args.Slice(), true)
|
||||||
if err != nil {
|
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 {
|
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 {
|
if len(params) != 0 {
|
||||||
data, err = smartcontract.ExpandParameterToEmitable(params[0])
|
data, err = smartcontract.ExpandParameterToEmitable(params[0])
|
||||||
if err != nil {
|
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.
|
// 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.
|
// 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() {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -348,3 +348,14 @@ func GetSignersAccounts(senderAcc *wallet.Account, wall *wallet.Wallet, signers
|
||||||
}
|
}
|
||||||
return signersAccounts, nil
|
return signersAccounts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnsureNotEmpty returns a function that checks if the flag with the given name
|
||||||
|
// is not empty.
|
||||||
|
func EnsureNotEmpty(flagName string) func(*cli.Context, string) error {
|
||||||
|
return func(ctx *cli.Context, name string) error {
|
||||||
|
if ctx.String(flagName) == "" {
|
||||||
|
return cli.Exit(fmt.Errorf("required flag --%s is empty", flagName), 1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"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.
|
// Address is a wrapper for a Uint160 with flag.Value methods.
|
||||||
|
@ -16,11 +16,15 @@ type Address struct {
|
||||||
Value util.Uint160
|
Value util.Uint160
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddressFlag is a flag with type string.
|
// AddressFlag is a flag with type Uint160.
|
||||||
type AddressFlag struct {
|
type AddressFlag struct {
|
||||||
Name string
|
Name string
|
||||||
Usage string
|
Usage string
|
||||||
Value Address
|
Value Address
|
||||||
|
Aliases []string
|
||||||
|
Required bool
|
||||||
|
Hidden bool
|
||||||
|
Action func(*cli.Context, string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -37,7 +41,7 @@ func (a Address) String() string {
|
||||||
func (a *Address) Set(s string) error {
|
func (a *Address) Set(s string) error {
|
||||||
addr, err := ParseAddress(s)
|
addr, err := ParseAddress(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
a.IsSet = true
|
a.IsSet = true
|
||||||
a.Value = addr
|
a.Value = addr
|
||||||
|
@ -63,9 +67,9 @@ func (f AddressFlag) IsSet() bool {
|
||||||
// (for usage defaults).
|
// (for usage defaults).
|
||||||
func (f AddressFlag) String() string {
|
func (f AddressFlag) String() string {
|
||||||
var names []string
|
var names []string
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
names = append(names, getNameHelp(name))
|
names = append(names, getNameHelp(name))
|
||||||
})
|
}
|
||||||
|
|
||||||
return strings.Join(names, ", ") + "\t" + f.Usage
|
return strings.Join(names, ", ") + "\t" + f.Usage
|
||||||
}
|
}
|
||||||
|
@ -77,17 +81,57 @@ func getNameHelp(name string) string {
|
||||||
return fmt.Sprintf("--%s value", name)
|
return fmt.Sprintf("--%s value", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of the flag.
|
// Names returns the names of the flag.
|
||||||
func (f AddressFlag) GetName() string {
|
func (f AddressFlag) Names() []string {
|
||||||
return f.Name
|
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.
|
// Apply populates the flag given the flag set and environment.
|
||||||
// Ignores errors.
|
// Ignores errors.
|
||||||
func (f AddressFlag) Apply(set *flag.FlagSet) {
|
func (f AddressFlag) Apply(set *flag.FlagSet) error {
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
set.Var(&f.Value, name, f.Usage)
|
set.Var(&f.Value, name, f.Usage)
|
||||||
})
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunAction executes flag action if set.
|
||||||
|
func (f AddressFlag) RunAction(c *cli.Context) error {
|
||||||
|
if f.Action != nil {
|
||||||
|
return f.Action(c, address.Uint160ToString(f.Value.Value))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValue returns the flags value as string representation.
|
||||||
|
func (f AddressFlag) GetValue() string {
|
||||||
|
return address.Uint160ToString(f.Value.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the flag’s value in the given Context.
|
||||||
|
func (f AddressFlag) Get(ctx *cli.Context) Address {
|
||||||
|
adr := ctx.Generic(f.Name).(*Address)
|
||||||
|
return *adr
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseAddress parses a Uint160 from either an LE string or an address.
|
// ParseAddress parses a Uint160 from either an LE string or an address.
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseAddress(t *testing.T) {
|
func TestParseAddress(t *testing.T) {
|
||||||
|
@ -109,22 +110,102 @@ func TestAddress_getNameHelp(t *testing.T) {
|
||||||
require.Equal(t, "--flag value", getNameHelp("flag"))
|
require.Equal(t, "--flag value", getNameHelp("flag"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddressFlag_GetName(t *testing.T) {
|
func TestAddressFlag_Names(t *testing.T) {
|
||||||
flag := AddressFlag{
|
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) {
|
func TestAddress(t *testing.T) {
|
||||||
f := flag.NewFlagSet("", flag.ContinueOnError)
|
f := flag.NewFlagSet("", flag.ContinueOnError)
|
||||||
f.SetOutput(io.Discard) // don't pollute test output
|
f.SetOutput(io.Discard) // don't pollute test output
|
||||||
addr := AddressFlag{Name: "addr, a"}
|
addr := AddressFlag{Name: "addr", Aliases: []string{"a"}}
|
||||||
addr.Apply(f)
|
err := addr.Apply(f)
|
||||||
|
require.NoError(t, err)
|
||||||
require.NoError(t, f.Parse([]string{"--addr", "NRHkiY2hLy5ypD32CKZtL6pNwhbFMqDEhR"}))
|
require.NoError(t, f.Parse([]string{"--addr", "NRHkiY2hLy5ypD32CKZtL6pNwhbFMqDEhR"}))
|
||||||
require.Equal(t, "NRHkiY2hLy5ypD32CKZtL6pNwhbFMqDEhR", f.Lookup("a").Value.String())
|
require.Equal(t, "NRHkiY2hLy5ypD32CKZtL6pNwhbFMqDEhR", f.Lookup("a").Value.String())
|
||||||
require.NoError(t, f.Parse([]string{"-a", "NRHkiY2hLy5ypD32CKZtL6pNwhbFMqDEhR"}))
|
require.NoError(t, f.Parse([]string{"-a", "NRHkiY2hLy5ypD32CKZtL6pNwhbFMqDEhR"}))
|
||||||
require.Equal(t, "NRHkiY2hLy5ypD32CKZtL6pNwhbFMqDEhR", f.Lookup("a").Value.String())
|
require.Equal(t, "NRHkiY2hLy5ypD32CKZtL6pNwhbFMqDEhR", f.Lookup("a").Value.String())
|
||||||
require.Error(t, f.Parse([]string{"--addr", "kek"}))
|
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)
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
"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.
|
// Fixed8 is a wrapper for a Uint160 with flag.Value methods.
|
||||||
|
@ -18,6 +18,10 @@ type Fixed8Flag struct {
|
||||||
Name string
|
Name string
|
||||||
Usage string
|
Usage string
|
||||||
Value Fixed8
|
Value Fixed8
|
||||||
|
Aliases []string
|
||||||
|
Required bool
|
||||||
|
Hidden bool
|
||||||
|
Action func(*cli.Context, string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -34,7 +38,7 @@ func (a Fixed8) String() string {
|
||||||
func (a *Fixed8) Set(s string) error {
|
func (a *Fixed8) Set(s string) error {
|
||||||
f, err := fixedn.Fixed8FromString(s)
|
f, err := fixedn.Fixed8FromString(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
a.Value = f
|
a.Value = f
|
||||||
return nil
|
return nil
|
||||||
|
@ -45,31 +49,75 @@ func (a *Fixed8) Fixed8() fixedn.Fixed8 {
|
||||||
return a.Value
|
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
|
// String returns a readable representation of this value
|
||||||
// (for usage defaults).
|
// (for usage defaults).
|
||||||
func (f Fixed8Flag) String() string {
|
func (f Fixed8Flag) String() string {
|
||||||
var names []string
|
var names []string
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
names = append(names, getNameHelp(name))
|
names = append(names, getNameHelp(name))
|
||||||
})
|
}
|
||||||
|
|
||||||
return strings.Join(names, ", ") + "\t" + f.Usage
|
return strings.Join(names, ", ") + "\t" + f.Usage
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of the flag.
|
// Names returns the names of the flag.
|
||||||
func (f Fixed8Flag) GetName() string {
|
func (f Fixed8Flag) Names() []string {
|
||||||
return f.Name
|
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.
|
// Apply populates the flag given the flag set and environment.
|
||||||
// Ignores errors.
|
// Ignores errors.
|
||||||
func (f Fixed8Flag) Apply(set *flag.FlagSet) {
|
func (f Fixed8Flag) Apply(set *flag.FlagSet) error {
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
set.Var(&f.Value, name, f.Usage)
|
set.Var(&f.Value, name, f.Usage)
|
||||||
})
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fixed8FromContext returns a parsed util.Fixed8 value provided flag name.
|
// Fixed8FromContext returns a parsed util.Fixed8 value provided flag name.
|
||||||
func Fixed8FromContext(ctx *cli.Context, name string) fixedn.Fixed8 {
|
func Fixed8FromContext(ctx *cli.Context, name string) fixedn.Fixed8 {
|
||||||
return ctx.Generic(name).(*Fixed8).Value
|
return ctx.Generic(name).(*Fixed8).Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RunAction executes flag action if set.
|
||||||
|
func (f Fixed8Flag) RunAction(c *cli.Context) error {
|
||||||
|
if f.Action != nil {
|
||||||
|
return f.Action(c, f.Value.Value.String())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValue returns the flags value as string representation.
|
||||||
|
func (f Fixed8Flag) GetValue() string {
|
||||||
|
return f.Value.Value.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the flag’s value in the given Context.
|
||||||
|
func (f Fixed8Flag) Get(ctx *cli.Context) Fixed8 {
|
||||||
|
adr := ctx.Generic(f.Name).(*Fixed8)
|
||||||
|
return *adr
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFixed8_String(t *testing.T) {
|
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())
|
require.Equal(t, "--myFlag value\tGas amount", flag.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFixed8Flag_GetName(t *testing.T) {
|
func TestFixed8Flag_Names(t *testing.T) {
|
||||||
flag := Fixed8Flag{
|
flag := Fixed8Flag{
|
||||||
Name: "myFlag",
|
Name: "myFlag",
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, "myFlag", flag.GetName())
|
require.Equal(t, []string{"myFlag"}, flag.Names())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFixed8(t *testing.T) {
|
func TestFixed8(t *testing.T) {
|
||||||
f := flag.NewFlagSet("", flag.ContinueOnError)
|
f := flag.NewFlagSet("", flag.ContinueOnError)
|
||||||
f.SetOutput(io.Discard) // don't pollute test output
|
f.SetOutput(io.Discard) // don't pollute test output
|
||||||
gas := Fixed8Flag{Name: "gas, g"}
|
gas := Fixed8Flag{Name: "gas", Aliases: []string{"g"}, Usage: "Gas amount", Value: Fixed8{Value: 0}, Required: true, Hidden: false, Action: nil}
|
||||||
gas.Apply(f)
|
err := gas.Apply(f)
|
||||||
|
require.NoError(t, err)
|
||||||
require.NoError(t, f.Parse([]string{"--gas", "0.123"}))
|
require.NoError(t, f.Parse([]string{"--gas", "0.123"}))
|
||||||
require.Equal(t, "0.123", f.Lookup("g").Value.String())
|
require.Equal(t, "0.123", f.Lookup("g").Value.String())
|
||||||
require.NoError(t, f.Parse([]string{"-g", "0.456"}))
|
require.NoError(t, f.Parse([]string{"-g", "0.456"}))
|
||||||
require.Equal(t, "0.456", f.Lookup("g").Value.String())
|
require.Equal(t, "0.456", f.Lookup("g").Value.String())
|
||||||
require.Error(t, f.Parse([]string{"--gas", "kek"}))
|
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())
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/app"
|
"github.com/nspcc-dev/neo-go/cli/app"
|
||||||
|
@ -10,6 +11,7 @@ func main() {
|
||||||
ctl := app.New()
|
ctl := app.New()
|
||||||
|
|
||||||
if err := ctl.Run(os.Args); err != nil {
|
if err := ctl.Run(os.Args); err != nil {
|
||||||
panic(err)
|
fmt.Fprintln(ctl.ErrWriter, err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,11 +55,14 @@ func TestNEP11Import(t *testing.T) {
|
||||||
"--wallet", walletPath,
|
"--wallet", walletPath,
|
||||||
}
|
}
|
||||||
// missing token hash
|
// missing token hash
|
||||||
e.RunWithError(t, args...)
|
e.RunWithErrorCheck(t, `Required flag "token" not set`, args...)
|
||||||
|
|
||||||
// excessive parameters
|
// excessive parameters
|
||||||
e.RunWithError(t, append(args, "--token", nnsContractHash.StringLE(), "something")...)
|
e.RunWithError(t, append(args, "--token", nnsContractHash.StringLE(), "something")...)
|
||||||
|
|
||||||
|
// empty token hash
|
||||||
|
e.RunWithErrorCheck(t, `invalid value "" for flag -token: zero length string`, append(args, "--token", "")...)
|
||||||
|
|
||||||
// good: non-divisible
|
// good: non-divisible
|
||||||
e.Run(t, append(args, "--token", nnsContractHash.StringLE())...)
|
e.Run(t, append(args, "--token", nnsContractHash.StringLE())...)
|
||||||
|
|
||||||
|
@ -229,7 +232,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOf",
|
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOf",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdOwnerOf...)
|
e.RunWithErrorCheck(t, `Required flag "token" not set`, cmdOwnerOf...)
|
||||||
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
|
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
|
||||||
|
|
||||||
// ownerOf: missing token ID
|
// ownerOf: missing token ID
|
||||||
|
@ -244,11 +247,11 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf",
|
cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdTokensOf...)
|
e.RunWithErrorCheck(t, `Required flags "token, address" not set`, cmdTokensOf...)
|
||||||
cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE())
|
cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE())
|
||||||
|
|
||||||
// tokensOf: missing owner address
|
// tokensOf: missing owner address
|
||||||
e.RunWithError(t, cmdTokensOf...)
|
e.RunWithErrorCheck(t, `Required flag "address" not set`, cmdTokensOf...)
|
||||||
cmdTokensOf = append(cmdTokensOf, "--address", nftOwnerAddr)
|
cmdTokensOf = append(cmdTokensOf, "--address", nftOwnerAddr)
|
||||||
|
|
||||||
// tokensOf: good
|
// tokensOf: good
|
||||||
|
@ -260,7 +263,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
"neo-go", "wallet", "nep11", "properties",
|
"neo-go", "wallet", "nep11", "properties",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdProperties...)
|
e.RunWithErrorCheck(t, `Required flag "token" not set`, cmdProperties...)
|
||||||
cmdProperties = append(cmdProperties, "--token", h.StringLE())
|
cmdProperties = append(cmdProperties, "--token", h.StringLE())
|
||||||
|
|
||||||
// properties: no token ID
|
// properties: no token ID
|
||||||
|
@ -286,7 +289,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens",
|
cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdTokens...)
|
e.RunWithErrorCheck(t, `Required flag "token" not set`, cmdTokens...)
|
||||||
cmdTokens = append(cmdTokens, "--token", h.StringLE())
|
cmdTokens = append(cmdTokens, "--token", h.StringLE())
|
||||||
|
|
||||||
// tokens: excessive parameters
|
// tokens: excessive parameters
|
||||||
|
@ -514,7 +517,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOfD",
|
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOfD",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdOwnerOf...)
|
e.RunWithErrorCheck(t, `Required flag "token" not set`, cmdOwnerOf...)
|
||||||
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
|
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
|
||||||
|
|
||||||
// ownerOfD: missing token ID
|
// ownerOfD: missing token ID
|
||||||
|
@ -529,11 +532,11 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf",
|
cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdTokensOf...)
|
e.RunWithErrorCheck(t, `Required flags "token, address" not set`, cmdTokensOf...)
|
||||||
cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE())
|
cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE())
|
||||||
|
|
||||||
// tokensOf: missing owner address
|
// tokensOf: missing owner address
|
||||||
e.RunWithError(t, cmdTokensOf...)
|
e.RunWithErrorCheck(t, `Required flag "address" not set`, cmdTokensOf...)
|
||||||
cmdTokensOf = append(cmdTokensOf, "--address", testcli.ValidatorAddr)
|
cmdTokensOf = append(cmdTokensOf, "--address", testcli.ValidatorAddr)
|
||||||
|
|
||||||
// tokensOf: good
|
// tokensOf: good
|
||||||
|
@ -547,7 +550,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
"neo-go", "wallet", "nep11", "properties",
|
"neo-go", "wallet", "nep11", "properties",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdProperties...)
|
e.RunWithErrorCheck(t, `Required flag "token" not set`, cmdProperties...)
|
||||||
cmdProperties = append(cmdProperties, "--token", h.StringLE())
|
cmdProperties = append(cmdProperties, "--token", h.StringLE())
|
||||||
|
|
||||||
// properties: no token ID
|
// properties: no token ID
|
||||||
|
@ -580,7 +583,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens",
|
cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
}
|
}
|
||||||
e.RunWithError(t, cmdTokens...)
|
e.RunWithErrorCheck(t, `Required flag "token" not set`, cmdTokens...)
|
||||||
cmdTokens = append(cmdTokens, "--token", h.StringLE())
|
cmdTokens = append(cmdTokens, "--token", h.StringLE())
|
||||||
|
|
||||||
// tokens: good, several tokens
|
// tokens: good, several tokens
|
||||||
|
|
|
@ -21,14 +21,13 @@ func TestNEP17Balance(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := testcli.NewExecutor(t, true)
|
||||||
|
|
||||||
args := []string{
|
args := []string{
|
||||||
"neo-go", "wallet", "nep17", "multitransfer",
|
"neo-go", "wallet", "nep17", "multitransfer", "--force",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", testcli.ValidatorWallet,
|
||||||
"--from", testcli.ValidatorAddr,
|
"--from", testcli.ValidatorAddr,
|
||||||
"GAS:" + testcli.TestWalletMultiAccount1 + ":1",
|
"GAS:" + testcli.TestWalletMultiAccount1 + ":1",
|
||||||
"NEO:" + testcli.TestWalletMultiAccount1 + ":10",
|
"NEO:" + testcli.TestWalletMultiAccount1 + ":10",
|
||||||
"GAS:" + testcli.TestWalletMultiAccount3 + ":3",
|
"GAS:" + testcli.TestWalletMultiAccount3 + ":3",
|
||||||
"--force",
|
|
||||||
}
|
}
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, args...)
|
e.Run(t, args...)
|
||||||
|
@ -114,7 +113,7 @@ func TestNEP17Balance(t *testing.T) {
|
||||||
e.CheckEOF(t)
|
e.CheckEOF(t)
|
||||||
})
|
})
|
||||||
t.Run("Bad wallet", func(t *testing.T) {
|
t.Run("Bad wallet", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmdbalance, "--wallet", "/dev/null")...)
|
e.RunWithError(t, append(cmdbalance, "--wallet", "/dev/null", "-r", "test")...)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +136,7 @@ func TestNEP17Transfer(t *testing.T) {
|
||||||
as := append([]string{}, args[:8]...)
|
as := append([]string{}, args[:8]...)
|
||||||
as = append(as, args[10:]...)
|
as = append(as, args[10:]...)
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.RunWithError(t, as...)
|
e.RunWithErrorCheck(t, `Required flag "to" not set`, as...)
|
||||||
e.In.Reset()
|
e.In.Reset()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -327,7 +326,7 @@ func TestNEP17ImportToken(t *testing.T) {
|
||||||
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
|
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
|
||||||
|
|
||||||
// missing token hash
|
// missing token hash
|
||||||
e.RunWithError(t, "neo-go", "wallet", "nep17", "import",
|
e.RunWithErrorCheck(t, `Required flag "token" not set`, "neo-go", "wallet", "nep17", "import",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
"--wallet", walletPath)
|
"--wallet", walletPath)
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
"github.com/nspcc-dev/neo-go/internal/testcli"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetRPCClient(t *testing.T) {
|
func TestGetRPCClient(t *testing.T) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
"github.com/nspcc-dev/neo-go/cli/input"
|
"github.com/nspcc-dev/neo-go/cli/input"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
|
@ -26,7 +27,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"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"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
|
@ -47,69 +48,92 @@ const (
|
||||||
const RPCEndpointFlag = "rpc-endpoint"
|
const RPCEndpointFlag = "rpc-endpoint"
|
||||||
|
|
||||||
// Wallet is a set of flags used for wallet operations.
|
// Wallet is a set of flags used for wallet operations.
|
||||||
var Wallet = []cli.Flag{cli.StringFlag{
|
var Wallet = []cli.Flag{
|
||||||
Name: "wallet, w",
|
&cli.StringFlag{
|
||||||
Usage: "wallet to use to get the key for transaction signing; conflicts with --wallet-config flag",
|
Name: "wallet",
|
||||||
}, cli.StringFlag{
|
Aliases: []string{"w"},
|
||||||
|
Usage: "Wallet to use to get the key for transaction signing; conflicts with --wallet-config flag",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
Name: "wallet-config",
|
Name: "wallet-config",
|
||||||
Usage: "path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag"},
|
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
|
// Network is a set of flags for choosing the network to operate on
|
||||||
// (privnet/mainnet/testnet).
|
// (privnet/mainnet/testnet).
|
||||||
var Network = []cli.Flag{
|
var Network = []cli.Flag{
|
||||||
cli.BoolFlag{Name: "privnet, p", Usage: "use private network configuration (if --config-file option is not specified)"},
|
&cli.BoolFlag{
|
||||||
cli.BoolFlag{Name: "mainnet, m", Usage: "use mainnet network configuration (if --config-file option is not specified)"},
|
Name: "privnet",
|
||||||
cli.BoolFlag{Name: "testnet, t", Usage: "use testnet network configuration (if --config-file option is not specified)"},
|
Aliases: []string{"p"},
|
||||||
cli.BoolFlag{Name: "unittest", Hidden: true},
|
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).
|
// RPC is a set of flags used for RPC connections (endpoint and timeout).
|
||||||
var RPC = []cli.Flag{
|
var RPC = []cli.Flag{
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: RPCEndpointFlag + ", r",
|
Name: RPCEndpointFlag,
|
||||||
|
Aliases: []string{"r"},
|
||||||
Usage: "RPC node address",
|
Usage: "RPC node address",
|
||||||
|
Required: true,
|
||||||
|
Action: cmdargs.EnsureNotEmpty("rpc-endpoint"),
|
||||||
},
|
},
|
||||||
cli.DurationFlag{
|
&cli.DurationFlag{
|
||||||
Name: "timeout, s",
|
Name: "timeout",
|
||||||
|
Aliases: []string{"s"},
|
||||||
Value: DefaultTimeout,
|
Value: DefaultTimeout,
|
||||||
Usage: "Timeout for the operation",
|
Usage: "Timeout for the operation",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Historic is a flag for commands that can perform historic invocations.
|
// Historic is a flag for commands that can perform historic invocations.
|
||||||
var Historic = cli.StringFlag{
|
var Historic = &cli.StringFlag{
|
||||||
Name: "historic",
|
Name: "historic",
|
||||||
Usage: "Use historic state (height, block hash or state root hash)",
|
Usage: "Use historic state (height, block hash or state root hash)",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config is a flag for commands that use node configuration.
|
// Config is a flag for commands that use node configuration.
|
||||||
var Config = cli.StringFlag{
|
var Config = &cli.StringFlag{
|
||||||
Name: "config-path",
|
Name: "config-path",
|
||||||
Usage: "path to directory with per-network configuration files (may be overridden by --config-file option for the configuration file)",
|
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
|
// ConfigFile is a flag for commands that use node configuration and provide
|
||||||
// path to the specific config file instead of config path.
|
// path to the specific config file instead of config path.
|
||||||
var ConfigFile = cli.StringFlag{
|
var ConfigFile = &cli.StringFlag{
|
||||||
Name: "config-file",
|
Name: "config-file",
|
||||||
Usage: "path to the node configuration file (overrides --config-path option)",
|
Usage: "Path to the node configuration file (overrides --config-path option)",
|
||||||
}
|
}
|
||||||
|
|
||||||
// RelativePath is a flag for commands that use node configuration and provide
|
// RelativePath is a flag for commands that use node configuration and provide
|
||||||
// a prefix to all relative paths in config files.
|
// a prefix to all relative paths in config files.
|
||||||
var RelativePath = cli.StringFlag{
|
var RelativePath = &cli.StringFlag{
|
||||||
Name: "relative-path",
|
Name: "relative-path",
|
||||||
Usage: "a prefix to all relative paths in the node configuration file",
|
Usage: "Prefix to all relative paths in the node configuration file",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug is a flag for commands that allow node in debug mode usage.
|
// Debug is a flag for commands that allow node in debug mode usage.
|
||||||
var Debug = cli.BoolFlag{
|
var Debug = &cli.BoolFlag{
|
||||||
Name: "debug, d",
|
Name: "debug",
|
||||||
Usage: "enable debug logging (LOTS of output, overrides configuration)",
|
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'")
|
|
||||||
var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash")
|
var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash")
|
||||||
var errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag")
|
var errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag")
|
||||||
var errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location")
|
var errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location")
|
||||||
|
@ -145,16 +169,13 @@ func GetTimeoutContext(ctx *cli.Context) (context.Context, func()) {
|
||||||
// GetRPCClient returns an RPC client instance for the given Context.
|
// GetRPCClient returns an RPC client instance for the given Context.
|
||||||
func GetRPCClient(gctx context.Context, ctx *cli.Context) (*rpcclient.Client, cli.ExitCoder) {
|
func GetRPCClient(gctx context.Context, ctx *cli.Context) (*rpcclient.Client, cli.ExitCoder) {
|
||||||
endpoint := ctx.String(RPCEndpointFlag)
|
endpoint := ctx.String(RPCEndpointFlag)
|
||||||
if len(endpoint) == 0 {
|
|
||||||
return nil, cli.NewExitError(errNoEndpoint, 1)
|
|
||||||
}
|
|
||||||
c, err := rpcclient.New(gctx, endpoint, rpcclient.Options{})
|
c, err := rpcclient.New(gctx, endpoint, rpcclient.Options{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cli.NewExitError(err, 1)
|
return nil, cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
err = c.Init()
|
err = c.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cli.NewExitError(err, 1)
|
return nil, cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
@ -173,7 +194,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.
|
// Might as well be a block hash, but it makes no practical difference.
|
||||||
return invoker.NewHistoricWithState(u256, c, signers), nil
|
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
|
// GetRPCWithInvoker combines GetRPCClient with GetInvoker for cases where it's
|
||||||
|
@ -314,7 +335,7 @@ func GetRPCWithActor(gctx context.Context, ctx *cli.Context, signers []actor.Sig
|
||||||
a, actorErr := actor.New(c, signers)
|
a, actorErr := actor.New(c, signers)
|
||||||
if actorErr != nil {
|
if actorErr != nil {
|
||||||
c.Close()
|
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
|
return c, a, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetNetwork(t *testing.T) {
|
func TestGetNetwork(t *testing.T) {
|
||||||
|
|
|
@ -22,21 +22,22 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCommands returns 'query' command.
|
// NewCommands returns 'query' command.
|
||||||
func NewCommands() []cli.Command {
|
func NewCommands() []*cli.Command {
|
||||||
queryTxFlags := append([]cli.Flag{
|
queryTxFlags := append([]cli.Flag{
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "verbose, v",
|
Name: "verbose",
|
||||||
|
Aliases: []string{"v"},
|
||||||
Usage: "Output full tx info and execution logs",
|
Usage: "Output full tx info and execution logs",
|
||||||
},
|
},
|
||||||
}, options.RPC...)
|
}, options.RPC...)
|
||||||
return []cli.Command{{
|
return []*cli.Command{{
|
||||||
Name: "query",
|
Name: "query",
|
||||||
Usage: "Query data from RPC node",
|
Usage: "Query data from RPC node",
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "candidates",
|
Name: "candidates",
|
||||||
Usage: "Get candidates and votes",
|
Usage: "Get candidates and votes",
|
||||||
|
@ -61,14 +62,14 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "tx",
|
Name: "tx",
|
||||||
Usage: "Query transaction status",
|
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,
|
Action: queryTx,
|
||||||
Flags: queryTxFlags,
|
Flags: queryTxFlags,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "voter",
|
Name: "voter",
|
||||||
Usage: "Print NEO holder account state",
|
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,
|
Action: queryVoter,
|
||||||
Flags: options.RPC,
|
Flags: options.RPC,
|
||||||
},
|
},
|
||||||
|
@ -77,16 +78,16 @@ func NewCommands() []cli.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryTx(ctx *cli.Context) error {
|
func queryTx(ctx *cli.Context) error {
|
||||||
args := ctx.Args()
|
args := ctx.Args().Slice()
|
||||||
if len(args) == 0 {
|
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 {
|
} 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"))
|
txHash, err := util.Uint256DecodeStringLE(strings.TrimPrefix(args[0], "0x"))
|
||||||
if err != nil {
|
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)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
@ -94,25 +95,25 @@ func queryTx(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
txOut, err := c.GetRawTransactionVerbose(txHash)
|
txOut, err := c.GetRawTransactionVerbose(txHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var res *result.ApplicationLog
|
var res *result.ApplicationLog
|
||||||
if !txOut.Blockhash.Equals(util.Uint256{}) {
|
if !txOut.Blockhash.Equals(util.Uint256{}) {
|
||||||
res, err = c.GetApplicationLog(txHash, nil)
|
res, err = c.GetApplicationLog(txHash, nil)
|
||||||
if err != 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"))
|
err = DumpApplicationLog(ctx, res, &txOut.Transaction, &txOut.TransactionMetadata, ctx.Bool("verbose"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -179,16 +180,16 @@ func queryCandidates(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
vals, err := c.GetCandidates()
|
vals, err := c.GetCandidates()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
comm, err := c.GetCommittee()
|
comm, err := c.GetCommittee()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(vals, func(i, j int) bool {
|
sort.Slice(vals, func(i, j int) bool {
|
||||||
|
@ -225,12 +226,12 @@ func queryCommittee(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
comm, err := c.GetCommittee()
|
comm, err := c.GetCommittee()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, k := range comm {
|
for _, k := range comm {
|
||||||
|
@ -251,12 +252,12 @@ func queryHeight(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
blockCount, err := c.GetBlockCount()
|
blockCount, err := c.GetBlockCount()
|
||||||
if err != nil {
|
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.
|
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 {
|
func queryVoter(ctx *cli.Context) error {
|
||||||
args := ctx.Args()
|
args := ctx.Args().Slice()
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return cli.NewExitError("No address specified", 1)
|
return cli.Exit("no address specified", 1)
|
||||||
} else if len(args) > 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])
|
addr, err := flags.ParseAddress(args[0])
|
||||||
if err != nil {
|
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)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
@ -294,14 +295,14 @@ func queryVoter(ctx *cli.Context) error {
|
||||||
|
|
||||||
st, err := neoToken.GetAccountState(addr)
|
st, err := neoToken.GetAccountState(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if st == nil {
|
if st == nil {
|
||||||
st = new(state.NEOBalance)
|
st = new(state.NEOBalance)
|
||||||
}
|
}
|
||||||
dec, err := neoToken.Decimals()
|
dec, err := neoToken.Decimals()
|
||||||
if err != nil {
|
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"
|
voted := "null"
|
||||||
if st.VoteTo != nil {
|
if st.VoteTo != nil {
|
||||||
|
|
|
@ -27,13 +27,13 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/services/oracle"
|
"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/rpcsrv"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/services/stateroot"
|
"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"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCommands returns 'node' command.
|
// NewCommands returns 'node' command.
|
||||||
func NewCommands() []cli.Command {
|
func NewCommands() []*cli.Command {
|
||||||
cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
|
cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
|
||||||
cfgFlags = append(cfgFlags, options.Network...)
|
cfgFlags = append(cfgFlags, options.Network...)
|
||||||
var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags))
|
var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags))
|
||||||
|
@ -41,75 +41,80 @@ func NewCommands() []cli.Command {
|
||||||
cfgFlags = append(cfgFlags, options.Debug)
|
cfgFlags = append(cfgFlags, options.Debug)
|
||||||
|
|
||||||
cfgWithCountFlags = append(cfgWithCountFlags,
|
cfgWithCountFlags = append(cfgWithCountFlags,
|
||||||
cli.UintFlag{
|
&cli.UintFlag{
|
||||||
Name: "count, c",
|
Name: "count",
|
||||||
Usage: "number of blocks to be processed (default or 0: all chain)",
|
Aliases: []string{"c"},
|
||||||
|
Usage: "Number of blocks to be processed (default or 0: all chain)",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
var cfgCountOutFlags = make([]cli.Flag, len(cfgWithCountFlags))
|
var cfgCountOutFlags = make([]cli.Flag, len(cfgWithCountFlags))
|
||||||
copy(cfgCountOutFlags, cfgWithCountFlags)
|
copy(cfgCountOutFlags, cfgWithCountFlags)
|
||||||
cfgCountOutFlags = append(cfgCountOutFlags,
|
cfgCountOutFlags = append(cfgCountOutFlags,
|
||||||
cli.UintFlag{
|
&cli.UintFlag{
|
||||||
Name: "start, s",
|
Name: "start",
|
||||||
Usage: "block number to start from (default: 0)",
|
Aliases: []string{"s"},
|
||||||
|
Usage: "Block number to start from",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "out, o",
|
Name: "out",
|
||||||
|
Aliases: []string{"o"},
|
||||||
Usage: "Output file (stdout if not given)",
|
Usage: "Output file (stdout if not given)",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
var cfgCountInFlags = make([]cli.Flag, len(cfgWithCountFlags))
|
var cfgCountInFlags = make([]cli.Flag, len(cfgWithCountFlags))
|
||||||
copy(cfgCountInFlags, cfgWithCountFlags)
|
copy(cfgCountInFlags, cfgWithCountFlags)
|
||||||
cfgCountInFlags = append(cfgCountInFlags,
|
cfgCountInFlags = append(cfgCountInFlags,
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "in, i",
|
Name: "in",
|
||||||
|
Aliases: []string{"i"},
|
||||||
Usage: "Input file (stdin if not given)",
|
Usage: "Input file (stdin if not given)",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "dump",
|
Name: "dump",
|
||||||
Usage: "directory for storing JSON dumps",
|
Usage: "Directory for storing JSON dumps",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "incremental, n",
|
Name: "incremental",
|
||||||
Usage: "use if dump is incremental",
|
Aliases: []string{"n"},
|
||||||
|
Usage: "Use if dump is incremental",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
var cfgHeightFlags = make([]cli.Flag, len(cfgFlags)+1)
|
var cfgHeightFlags = make([]cli.Flag, len(cfgFlags)+1)
|
||||||
copy(cfgHeightFlags, cfgFlags)
|
copy(cfgHeightFlags, cfgFlags)
|
||||||
cfgHeightFlags[len(cfgHeightFlags)-1] = cli.UintFlag{
|
cfgHeightFlags[len(cfgHeightFlags)-1] = &cli.UintFlag{
|
||||||
Name: "height",
|
Name: "height",
|
||||||
Usage: "Height of the state to reset DB to",
|
Usage: "Height of the state to reset DB to",
|
||||||
Required: true,
|
Required: true,
|
||||||
}
|
}
|
||||||
return []cli.Command{
|
return []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "node",
|
Name: "node",
|
||||||
Usage: "start a NeoGo node",
|
Usage: "Start a NeoGo node",
|
||||||
UsageText: "neo-go node [--config-path path] [-d] [-p/-m/-t] [--config-file file]",
|
UsageText: "neo-go node [--config-path path] [-d] [-p/-m/-t] [--config-file file]",
|
||||||
Action: startServer,
|
Action: startServer,
|
||||||
Flags: cfgFlags,
|
Flags: cfgFlags,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "db",
|
Name: "db",
|
||||||
Usage: "database manipulations",
|
Usage: "Database manipulations",
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "dump",
|
Name: "dump",
|
||||||
Usage: "dump blocks (starting with block #1) to the file",
|
Usage: "Dump blocks (starting with block #1) to the file",
|
||||||
UsageText: "neo-go db dump -o file [-s start] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]",
|
UsageText: "neo-go db dump [-o file] [-s start] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]",
|
||||||
Action: dumpDB,
|
Action: dumpDB,
|
||||||
Flags: cfgCountOutFlags,
|
Flags: cfgCountOutFlags,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "restore",
|
Name: "restore",
|
||||||
Usage: "restore blocks from the file",
|
Usage: "Restore blocks from the file",
|
||||||
UsageText: "neo-go db restore -i file [--dump] [-n] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]",
|
UsageText: "neo-go db restore [-i file] [--dump] [-n] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]",
|
||||||
Action: restoreDB,
|
Action: restoreDB,
|
||||||
Flags: cfgCountInFlags,
|
Flags: cfgCountInFlags,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "reset",
|
Name: "reset",
|
||||||
Usage: "reset database to the previous state",
|
Usage: "Reset database to the previous state",
|
||||||
UsageText: "neo-go db reset --height height [--config-path path] [-p/-m/-t] [--config-file file]",
|
UsageText: "neo-go db reset --height height [--config-path path] [-p/-m/-t] [--config-file file]",
|
||||||
Action: resetDB,
|
Action: resetDB,
|
||||||
Flags: cfgHeightFlags,
|
Flags: cfgHeightFlags,
|
||||||
|
@ -134,7 +139,7 @@ func newGraceContext() context.Context {
|
||||||
func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *metrics.Service, *metrics.Service, error) {
|
func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *metrics.Service, *metrics.Service, error) {
|
||||||
chain, _, err := initBlockChain(cfg, log)
|
chain, _, err := initBlockChain(cfg, log)
|
||||||
if err != nil {
|
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)
|
prometheus := metrics.NewPrometheusService(cfg.ApplicationConfiguration.Prometheus, log)
|
||||||
pprof := metrics.NewPprofService(cfg.ApplicationConfiguration.Pprof, 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()
|
go chain.Run()
|
||||||
err = prometheus.Start()
|
err = prometheus.Start()
|
||||||
if err != nil {
|
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()
|
err = pprof.Start()
|
||||||
if err != nil {
|
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
|
return chain, prometheus, pprof, nil
|
||||||
|
@ -158,11 +163,11 @@ func dumpDB(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
cfg, err := options.GetConfigFromContext(ctx)
|
cfg, err := options.GetConfigFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration)
|
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if logCloser != nil {
|
if logCloser != nil {
|
||||||
defer func() { _ = logCloser() }()
|
defer func() { _ = logCloser() }()
|
||||||
|
@ -174,7 +179,7 @@ func dumpDB(ctx *cli.Context) error {
|
||||||
if out := ctx.String("out"); out != "" {
|
if out := ctx.String("out"); out != "" {
|
||||||
outStream, err = os.Create(out)
|
outStream, err = os.Create(out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer outStream.Close()
|
defer outStream.Close()
|
||||||
|
@ -192,7 +197,7 @@ func dumpDB(ctx *cli.Context) error {
|
||||||
|
|
||||||
chainCount := chain.BlockHeight() + 1
|
chainCount := chain.BlockHeight() + 1
|
||||||
if start+count > chainCount {
|
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 {
|
if count == 0 {
|
||||||
count = chainCount - start
|
count = chainCount - start
|
||||||
|
@ -203,7 +208,7 @@ func dumpDB(ctx *cli.Context) error {
|
||||||
writer.WriteU32LE(count)
|
writer.WriteU32LE(count)
|
||||||
err = chaindump.Dump(chain, writer, start, count)
|
err = chaindump.Dump(chain, writer, start, count)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err.Error(), 1)
|
return cli.Exit(err.Error(), 1)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -218,7 +223,7 @@ func restoreDB(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration)
|
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if logCloser != nil {
|
if logCloser != nil {
|
||||||
defer func() { _ = logCloser() }()
|
defer func() { _ = logCloser() }()
|
||||||
|
@ -229,7 +234,7 @@ func restoreDB(ctx *cli.Context) error {
|
||||||
if in := ctx.String("in"); in != "" {
|
if in := ctx.String("in"); in != "" {
|
||||||
inStream, err = os.Open(in)
|
inStream, err = os.Open(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer inStream.Close()
|
defer inStream.Close()
|
||||||
|
@ -254,7 +259,7 @@ func restoreDB(ctx *cli.Context) error {
|
||||||
if ctx.Bool("incremental") {
|
if ctx.Bool("incremental") {
|
||||||
start = reader.ReadU32LE()
|
start = reader.ReadU32LE()
|
||||||
if chain.BlockHeight()+1 < start {
|
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)
|
chain.BlockHeight()+1, start), 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,10 +271,10 @@ func restoreDB(ctx *cli.Context) error {
|
||||||
|
|
||||||
var allBlocks = reader.ReadU32LE()
|
var allBlocks = reader.ReadU32LE()
|
||||||
if reader.Err != nil {
|
if reader.Err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if skip+count > allBlocks {
|
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 {
|
if count == 0 {
|
||||||
count = allBlocks - skip
|
count = allBlocks - skip
|
||||||
|
@ -320,7 +325,7 @@ func restoreDB(ctx *cli.Context) error {
|
||||||
|
|
||||||
err = chaindump.Restore(chain, reader, skip, count, f)
|
err = chaindump.Restore(chain, reader, skip, count, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -331,29 +336,29 @@ func resetDB(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
cfg, err := options.GetConfigFromContext(ctx)
|
cfg, err := options.GetConfigFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
h := uint32(ctx.Uint("height"))
|
h := uint32(ctx.Uint("height"))
|
||||||
|
|
||||||
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration)
|
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if logCloser != nil {
|
if logCloser != nil {
|
||||||
defer func() { _ = logCloser() }()
|
defer func() { _ = logCloser() }()
|
||||||
}
|
}
|
||||||
chain, store, err := initBlockChain(cfg, log)
|
chain, store, err := initBlockChain(cfg, log)
|
||||||
if err != nil {
|
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)
|
err = chain.Reset(h)
|
||||||
if err != nil {
|
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()
|
err = store.Close()
|
||||||
if err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -442,12 +447,12 @@ func startServer(ctx *cli.Context) error {
|
||||||
|
|
||||||
cfg, err := options.GetConfigFromContext(ctx)
|
cfg, err := options.GetConfigFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
var logDebug = ctx.Bool("debug")
|
var logDebug = ctx.Bool("debug")
|
||||||
log, logLevel, logCloser, err := options.HandleLoggingParams(logDebug, cfg.ApplicationConfiguration)
|
log, logLevel, logCloser, err := options.HandleLoggingParams(logDebug, cfg.ApplicationConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if logCloser != nil {
|
if logCloser != nil {
|
||||||
defer func() { _ = logCloser() }()
|
defer func() { _ = logCloser() }()
|
||||||
|
@ -458,12 +463,12 @@ func startServer(ctx *cli.Context) error {
|
||||||
|
|
||||||
serverConfig, err := network.NewServerConfig(cfg)
|
serverConfig, err := network.NewServerConfig(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
pprof.ShutDown()
|
pprof.ShutDown()
|
||||||
|
@ -473,26 +478,26 @@ func startServer(ctx *cli.Context) error {
|
||||||
|
|
||||||
serv, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), log)
|
serv, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), log)
|
||||||
if err != nil {
|
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.
|
srMod := chain.GetStateModule().(*corestate.Module) // Take full responsibility here.
|
||||||
sr, err := stateroot.New(serverConfig.StateRootCfg, srMod, log, chain, serv.BroadcastExtensible)
|
sr, err := stateroot.New(serverConfig.StateRootCfg, srMod, log, chain, serv.BroadcastExtensible)
|
||||||
if err != nil {
|
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)
|
serv.AddExtensibleService(sr, stateroot.Category, sr.OnPayload)
|
||||||
|
|
||||||
oracleSrv, err := mkOracle(cfg.ApplicationConfiguration.Oracle, cfg.ProtocolConfiguration.Magic, chain, serv, log)
|
oracleSrv, err := mkOracle(cfg.ApplicationConfiguration.Oracle, cfg.ProtocolConfiguration.Magic, chain, serv, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
dbftSrv, err := mkConsensus(cfg.ApplicationConfiguration.Consensus, serverConfig.TimePerBlock, chain, serv, log)
|
dbftSrv, err := mkConsensus(cfg.ApplicationConfiguration.Consensus, serverConfig.TimePerBlock, chain, serv, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
p2pNotary, err := mkP2PNotary(cfg.ApplicationConfiguration.P2PNotary, chain, serv, log)
|
p2pNotary, err := mkP2PNotary(cfg.ApplicationConfiguration.P2PNotary, chain, serv, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
rpcServer := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan)
|
rpcServer := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan)
|
||||||
|
@ -640,7 +645,7 @@ Main:
|
||||||
}
|
}
|
||||||
|
|
||||||
if shutdownErr != nil {
|
if shutdownErr != nil {
|
||||||
return cli.NewExitError(shutdownErr, 1)
|
return cli.Exit(shutdownErr, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -650,7 +655,7 @@ Main:
|
||||||
func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, storage.Store, error) {
|
func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, storage.Store, error) {
|
||||||
store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration)
|
store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration)
|
||||||
if err != nil {
|
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)
|
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)
|
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
|
return chain, store, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
|
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -56,13 +56,13 @@ func TestCalcHash(t *testing.T) {
|
||||||
|
|
||||||
cmd := []string{"neo-go", "contract", "calc-hash"}
|
cmd := []string{"neo-go", "contract", "calc-hash"}
|
||||||
t.Run("no sender", func(t *testing.T) {
|
t.Run("no sender", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, "--in", nefPath, "--manifest", manifestPath)...)
|
e.RunWithErrorCheck(t, `Required flag "sender" not set`, append(cmd, "--in", nefPath, "--manifest", manifestPath)...)
|
||||||
})
|
})
|
||||||
t.Run("no nef file", func(t *testing.T) {
|
t.Run("no nef file", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--manifest", manifestPath)...)
|
e.RunWithErrorCheck(t, `Required flag "in" not set`, append(cmd, "--sender", sender.StringLE(), "--manifest", manifestPath)...)
|
||||||
})
|
})
|
||||||
t.Run("no manifest file", func(t *testing.T) {
|
t.Run("no manifest file", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--in", nefPath)...)
|
e.RunWithErrorCheck(t, `Required flag "manifest" not set`, append(cmd, "--sender", sender.StringLE(), "--in", nefPath)...)
|
||||||
})
|
})
|
||||||
t.Run("invalid nef path", func(t *testing.T) {
|
t.Run("invalid nef path", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(),
|
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(),
|
||||||
|
@ -289,7 +289,7 @@ func TestContractInitAndCompile(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, false)
|
e := testcli.NewExecutor(t, false)
|
||||||
|
|
||||||
t.Run("no path is provided", func(t *testing.T) {
|
t.Run("no path is provided", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "init")
|
e.RunWithErrorCheck(t, `Required flag "name" not set`, "neo-go", "contract", "init")
|
||||||
})
|
})
|
||||||
t.Run("invalid path", func(t *testing.T) {
|
t.Run("invalid path", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "init", "--name", "\x00")
|
e.RunWithError(t, "neo-go", "contract", "init", "--name", "\x00")
|
||||||
|
@ -313,7 +313,7 @@ func TestContractInitAndCompile(t *testing.T) {
|
||||||
manifestPath := filepath.Join(tmpDir, "testcontract.manifest.json")
|
manifestPath := filepath.Join(tmpDir, "testcontract.manifest.json")
|
||||||
cmd := []string{"neo-go", "contract", "compile"}
|
cmd := []string{"neo-go", "contract", "compile"}
|
||||||
t.Run("missing source", func(t *testing.T) {
|
t.Run("missing source", func(t *testing.T) {
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithErrorCheck(t, `Required flag "in" not set`, cmd...)
|
||||||
})
|
})
|
||||||
|
|
||||||
cmd = append(cmd, "--in", srcPath, "--out", nefPath, "--manifest", manifestPath)
|
cmd = append(cmd, "--in", srcPath, "--out", nefPath, "--manifest", manifestPath)
|
||||||
|
@ -487,10 +487,10 @@ func TestDeployWithSigners(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "deploy",
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
||||||
"--in", "", "--manifest", manifestName)
|
"--in", nefName, "--manifest", manifestName)
|
||||||
})
|
})
|
||||||
t.Run("missing manifest", func(t *testing.T) {
|
t.Run("missing manifest", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "deploy",
|
e.RunWithErrorCheck(t, "required flag --manifest is empty", "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
||||||
"--in", nefName, "--manifest", "")
|
"--in", nefName, "--manifest", "")
|
||||||
|
@ -517,7 +517,7 @@ func TestDeployWithSigners(t *testing.T) {
|
||||||
"[", "str1", "str2", "]")
|
"[", "str1", "str2", "]")
|
||||||
})
|
})
|
||||||
t.Run("missing RPC", func(t *testing.T) {
|
t.Run("missing RPC", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "deploy",
|
e.RunWithErrorCheck(t, `Required flag "rpc-endpoint" not set`, "neo-go", "contract", "deploy",
|
||||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
||||||
"--in", nefName, "--manifest", manifestName,
|
"--in", nefName, "--manifest", manifestName,
|
||||||
"[", "str1", "str2", "]")
|
"[", "str1", "str2", "]")
|
||||||
|
@ -548,28 +548,29 @@ func TestContractManifestGroups(t *testing.T) {
|
||||||
"--out", nefName, "--manifest", manifestName)
|
"--out", nefName, "--manifest", manifestName)
|
||||||
|
|
||||||
t.Run("missing wallet", func(t *testing.T) {
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group")
|
e.RunWithErrorCheck(t, `Required flags "sender, address, nef, manifest" not set`, "neo-go", "contract", "manifest", "add-group")
|
||||||
})
|
})
|
||||||
t.Run("invalid wallet", func(t *testing.T) {
|
t.Run("invalid wallet", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
"--wallet", t.TempDir())
|
"--wallet", t.TempDir(), "--sender", testcli.TestWalletAccount, "--address", testcli.TestWalletAccount,
|
||||||
|
"--nef", nefName, "--manifest", manifestName)
|
||||||
})
|
})
|
||||||
t.Run("invalid sender", func(t *testing.T) {
|
t.Run("invalid sender", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
e.RunWithErrorCheck(t, `invalid value "not-a-sender" for flag -sender: invalid base58 digit ('-')`, "neo-go", "contract", "manifest", "add-group",
|
||||||
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
|
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
|
||||||
"--sender", "not-a-sender")
|
"--sender", "not-a-sender", "--nef", nefName, "--manifest", manifestName)
|
||||||
})
|
})
|
||||||
t.Run("invalid NEF file", func(t *testing.T) {
|
t.Run("invalid NEF file", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
|
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
|
||||||
"--sender", testcli.TestWalletAccount, "--nef", tmpDir)
|
"--sender", testcli.TestWalletAccount, "--nef", tmpDir, "--manifest", manifestName)
|
||||||
})
|
})
|
||||||
t.Run("corrupted NEF file", func(t *testing.T) {
|
t.Run("corrupted NEF file", func(t *testing.T) {
|
||||||
f := filepath.Join(tmpDir, "invalid.nef")
|
f := filepath.Join(tmpDir, "invalid.nef")
|
||||||
require.NoError(t, os.WriteFile(f, []byte{1, 2, 3}, os.ModePerm))
|
require.NoError(t, os.WriteFile(f, []byte{1, 2, 3}, os.ModePerm))
|
||||||
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
|
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
|
||||||
"--sender", testcli.TestWalletAccount, "--nef", f)
|
"--sender", testcli.TestWalletAccount, "--nef", f, "--manifest", manifestName)
|
||||||
})
|
})
|
||||||
t.Run("invalid manifest file", func(t *testing.T) {
|
t.Run("invalid manifest file", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
|
@ -630,9 +631,17 @@ func TestContract_TestInvokeScript(t *testing.T) {
|
||||||
"--out", goodNef, "--manifest", manifestName)
|
"--out", goodNef, "--manifest", manifestName)
|
||||||
|
|
||||||
t.Run("missing in", func(t *testing.T) {
|
t.Run("missing in", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
e.RunWithErrorCheck(t, `Required flag "in" not set`, "neo-go", "contract", "testinvokescript",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
|
||||||
})
|
})
|
||||||
|
t.Run("empty in", func(t *testing.T) {
|
||||||
|
e.RunWithErrorCheck(t, "required flag --in is empty", "neo-go", "contract", "testinvokescript", "-i", "",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
|
||||||
|
})
|
||||||
|
t.Run("empty rpc", func(t *testing.T) {
|
||||||
|
e.RunWithErrorCheck(t, "required flag --rpc-endpoint is empty", "neo-go", "contract", "testinvokescript", "-i", goodNef,
|
||||||
|
"--rpc-endpoint", "")
|
||||||
|
})
|
||||||
t.Run("unexisting in", func(t *testing.T) {
|
t.Run("unexisting in", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
|
@ -723,7 +732,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
|
|
||||||
t.Run("check calc hash", func(t *testing.T) {
|
t.Run("check calc hash", func(t *testing.T) {
|
||||||
// missing sender
|
// missing sender
|
||||||
e.RunWithError(t, "neo-go", "contract", "calc-hash",
|
e.RunWithErrorCheck(t, `Required flag "sender" not set`, "neo-go", "contract", "calc-hash",
|
||||||
"--in", nefName,
|
"--in", nefName,
|
||||||
"--manifest", manifestName)
|
"--manifest", manifestName)
|
||||||
|
|
||||||
|
@ -755,7 +764,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, "--", "notahash")...)
|
e.RunWithError(t, append(cmd, "--", "notahash")...)
|
||||||
})
|
})
|
||||||
t.Run("missing RPC address", func(t *testing.T) {
|
t.Run("missing RPC address", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "contract", "testinvokefunction",
|
e.RunWithErrorCheck(t, `Required flag "rpc-endpoint" not set`, "neo-go", "contract", "testinvokefunction",
|
||||||
h.StringLE(), "getValue")
|
h.StringLE(), "getValue")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1038,7 +1047,7 @@ func TestContractInspect(t *testing.T) {
|
||||||
|
|
||||||
cmd := []string{"neo-go", "contract", "inspect"}
|
cmd := []string{"neo-go", "contract", "inspect"}
|
||||||
t.Run("missing input", func(t *testing.T) {
|
t.Run("missing input", func(t *testing.T) {
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithErrorCheck(t, `Required flag "in" not set`, cmd...)
|
||||||
})
|
})
|
||||||
t.Run("with raw '.go'", func(t *testing.T) {
|
t.Run("with raw '.go'", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, "--in", srcPath)...)
|
e.RunWithError(t, append(cmd, "--in", srcPath)...)
|
||||||
|
|
|
@ -9,34 +9,39 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/binding"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/binding"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var generatorFlags = []cli.Flag{
|
var generatorFlags = []cli.Flag{
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "config, c",
|
Name: "config",
|
||||||
|
Aliases: []string{"c"},
|
||||||
Usage: "Configuration file to use",
|
Usage: "Configuration file to use",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "manifest, m",
|
Name: "manifest",
|
||||||
|
Aliases: []string{"m"},
|
||||||
Required: true,
|
Required: true,
|
||||||
Usage: "Read contract manifest (*.manifest.json) file",
|
Usage: "Read contract manifest (*.manifest.json) file",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("manifest"),
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "out, o",
|
Name: "out",
|
||||||
|
Aliases: []string{"o"},
|
||||||
Required: true,
|
Required: true,
|
||||||
Usage: "Output of the compiled wrapper",
|
Usage: "Output of the compiled wrapper",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("out"),
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "hash",
|
Name: "hash",
|
||||||
Usage: "Smart-contract hash. If not passed, the wrapper will be designed for dynamic hash usage",
|
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",
|
Name: "generate-wrapper",
|
||||||
Usage: "generate wrapper to use in other contracts",
|
Usage: "Generate wrapper to use in other contracts",
|
||||||
UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
|
UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
|
||||||
Description: `Generates a Go wrapper to use it in other smart contracts. If the
|
Description: `Generates a Go wrapper to use it in other smart contracts. If the
|
||||||
--hash flag is provided, CALLT instruction is used for the target contract
|
--hash flag is provided, CALLT instruction is used for the target contract
|
||||||
|
@ -48,9 +53,9 @@ var generateWrapperCmd = cli.Command{
|
||||||
Flags: generatorFlags,
|
Flags: generatorFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
var generateRPCWrapperCmd = cli.Command{
|
var generateRPCWrapperCmd = &cli.Command{
|
||||||
Name: "generate-rpcwrapper",
|
Name: "generate-rpcwrapper",
|
||||||
Usage: "generate RPC wrapper to use for data reads",
|
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>]",
|
UsageText: "neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
|
||||||
Action: contractGenerateRPCWrapper,
|
Action: contractGenerateRPCWrapper,
|
||||||
Flags: generatorFlags,
|
Flags: generatorFlags,
|
||||||
|
@ -76,23 +81,23 @@ func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error)
|
||||||
if hStr := ctx.String("hash"); len(hStr) != 0 {
|
if hStr := ctx.String("hash"); len(hStr) != 0 {
|
||||||
h, err = util.Uint160DecodeStringLE(strings.TrimPrefix(hStr, "0x"))
|
h, err = util.Uint160DecodeStringLE(strings.TrimPrefix(hStr, "0x"))
|
||||||
if err != nil {
|
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)
|
m, _, err := readManifest(ctx.String("manifest"), h)
|
||||||
if err != nil {
|
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()
|
cfg := binding.NewConfig()
|
||||||
if cfgPath := ctx.String("config"); cfgPath != "" {
|
if cfgPath := ctx.String("config"); cfgPath != "" {
|
||||||
bs, err := os.ReadFile(cfgPath)
|
bs, err := os.ReadFile(cfgPath)
|
||||||
if err != nil {
|
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)
|
err = yaml.Unmarshal(bs, &cfg)
|
||||||
if err != nil {
|
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
|
cfg.Manifest = m
|
||||||
|
@ -100,7 +105,7 @@ func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error)
|
||||||
|
|
||||||
f, err := os.Create(ctx.String("out"))
|
f, err := os.Create(ctx.String("out"))
|
||||||
if err != nil {
|
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()
|
defer f.Close()
|
||||||
|
|
||||||
|
@ -108,7 +113,7 @@ func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error)
|
||||||
|
|
||||||
err = cb(cfg)
|
err = cb(cfg)
|
||||||
if err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package smartcontract
|
package smartcontract_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -6,14 +6,13 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/internal/testcli"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenerate(t *testing.T) {
|
func TestGenerate(t *testing.T) {
|
||||||
|
@ -124,8 +123,7 @@ func TestGenerate(t *testing.T) {
|
||||||
0x04, 0x08, 0x15, 0x16, 0x23, 0x42, 0x43, 0x44, 0x00, 0x01,
|
0x04, 0x08, 0x15, 0x16, 0x23, 0x42, 0x43, 0x44, 0x00, 0x01,
|
||||||
0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, 0x03, 0x04,
|
0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, 0x03, 0x04,
|
||||||
}
|
}
|
||||||
app := cli.NewApp()
|
e := testcli.NewExecutor(t, false)
|
||||||
app.Commands = []cli.Command{generateWrapperCmd}
|
|
||||||
|
|
||||||
rawCfg := `package: wrapper
|
rawCfg := `package: wrapper
|
||||||
hash: ` + h.StringLE() + `
|
hash: ` + h.StringLE() + `
|
||||||
|
@ -144,12 +142,12 @@ callflags:
|
||||||
cfgPath := filepath.Join(t.TempDir(), "binding.yml")
|
cfgPath := filepath.Join(t.TempDir(), "binding.yml")
|
||||||
require.NoError(t, os.WriteFile(cfgPath, []byte(rawCfg), os.ModePerm))
|
require.NoError(t, os.WriteFile(cfgPath, []byte(rawCfg), os.ModePerm))
|
||||||
|
|
||||||
require.NoError(t, app.Run([]string{"", "generate-wrapper",
|
e.Run(t, []string{"", "contract", "generate-wrapper",
|
||||||
"--manifest", manifestFile,
|
"--manifest", manifestFile,
|
||||||
"--config", cfgPath,
|
"--config", cfgPath,
|
||||||
"--out", outFile,
|
"--out", outFile,
|
||||||
"--hash", h.StringLE(),
|
"--hash", h.StringLE(),
|
||||||
}))
|
}...)
|
||||||
|
|
||||||
const expected = `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
const expected = `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
|
@ -234,11 +232,11 @@ func MyFunc(in map[int]mycontract.Input) []mycontract.Output {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expected, string(data))
|
require.Equal(t, expected, string(data))
|
||||||
|
|
||||||
require.NoError(t, app.Run([]string{"", "generate-wrapper",
|
e.Run(t, []string{"", "contract", "generate-wrapper",
|
||||||
"--manifest", manifestFile,
|
"--manifest", manifestFile,
|
||||||
"--config", cfgPath,
|
"--config", cfgPath,
|
||||||
"--out", outFile,
|
"--out", outFile,
|
||||||
}))
|
}...)
|
||||||
expectedWithDynamicHash := `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
expectedWithDynamicHash := `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
// Package wrapper contains wrappers for MyContract contract.
|
// Package wrapper contains wrappers for MyContract contract.
|
||||||
|
@ -350,13 +348,12 @@ func TestGenerateValidPackageName(t *testing.T) {
|
||||||
0x04, 0x08, 0x15, 0x16, 0x23, 0x42, 0x43, 0x44, 0x00, 0x01,
|
0x04, 0x08, 0x15, 0x16, 0x23, 0x42, 0x43, 0x44, 0x00, 0x01,
|
||||||
0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, 0x03, 0x04,
|
0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, 0x03, 0x04,
|
||||||
}
|
}
|
||||||
app := cli.NewApp()
|
e := testcli.NewExecutor(t, false)
|
||||||
app.Commands = []cli.Command{generateWrapperCmd, generateRPCWrapperCmd}
|
e.Run(t, []string{"", "contract", "generate-wrapper",
|
||||||
require.NoError(t, app.Run([]string{"", "generate-wrapper",
|
|
||||||
"--manifest", manifestFile,
|
"--manifest", manifestFile,
|
||||||
"--out", outFile,
|
"--out", outFile,
|
||||||
"--hash", "0x" + h.StringLE(),
|
"--hash", "0x" + h.StringLE(),
|
||||||
}))
|
}...)
|
||||||
|
|
||||||
data, err := os.ReadFile(outFile)
|
data, err := os.ReadFile(outFile)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -378,11 +375,11 @@ func Get() int {
|
||||||
return neogointernal.CallWithToken(Hash, "get", int(contract.ReadOnly)).(int)
|
return neogointernal.CallWithToken(Hash, "get", int(contract.ReadOnly)).(int)
|
||||||
}
|
}
|
||||||
`, string(data))
|
`, string(data))
|
||||||
require.NoError(t, app.Run([]string{"", "generate-rpcwrapper",
|
e.Run(t, []string{"", "contract", "generate-rpcwrapper",
|
||||||
"--manifest", manifestFile,
|
"--manifest", manifestFile,
|
||||||
"--out", outFile,
|
"--out", outFile,
|
||||||
"--hash", "0x" + h.StringLE(),
|
"--hash", "0x" + h.StringLE(),
|
||||||
}))
|
}...)
|
||||||
|
|
||||||
data, err = os.ReadFile(outFile)
|
data, err = os.ReadFile(outFile)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -431,17 +428,16 @@ const rewriteExpectedOutputs = false
|
||||||
|
|
||||||
func TestGenerateRPCBindings(t *testing.T) {
|
func TestGenerateRPCBindings(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
app := cli.NewApp()
|
e := testcli.NewExecutor(t, false)
|
||||||
app.Commands = []cli.Command{generateWrapperCmd, generateRPCWrapperCmd}
|
|
||||||
|
|
||||||
var checkBinding = func(manifest string, hash string, good string) {
|
var checkBinding = func(manifest string, hash string, good string) {
|
||||||
t.Run(manifest, func(t *testing.T) {
|
t.Run(manifest, func(t *testing.T) {
|
||||||
outFile := filepath.Join(tmpDir, "out.go")
|
outFile := filepath.Join(tmpDir, "out.go")
|
||||||
require.NoError(t, app.Run([]string{"", "generate-rpcwrapper",
|
e.Run(t, []string{"", "contract", "generate-rpcwrapper",
|
||||||
"--manifest", manifest,
|
"--manifest", manifest,
|
||||||
"--out", outFile,
|
"--out", outFile,
|
||||||
"--hash", hash,
|
"--hash", hash,
|
||||||
}))
|
}...)
|
||||||
|
|
||||||
data, err := os.ReadFile(outFile)
|
data, err := os.ReadFile(outFile)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -478,8 +474,7 @@ func TestGenerateRPCBindings(t *testing.T) {
|
||||||
|
|
||||||
func TestAssistedRPCBindings(t *testing.T) {
|
func TestAssistedRPCBindings(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
app := cli.NewApp()
|
e := testcli.NewExecutor(t, false)
|
||||||
app.Commands = NewCommands()
|
|
||||||
|
|
||||||
var checkBinding = func(source string, hasDefinedHash bool, guessEventTypes bool, suffix ...string) {
|
var checkBinding = func(source string, hasDefinedHash bool, guessEventTypes bool, suffix ...string) {
|
||||||
testName := source
|
testName := source
|
||||||
|
@ -510,7 +505,7 @@ func TestAssistedRPCBindings(t *testing.T) {
|
||||||
if guessEventTypes {
|
if guessEventTypes {
|
||||||
cmd = append(cmd, "--guess-eventtypes")
|
cmd = append(cmd, "--guess-eventtypes")
|
||||||
}
|
}
|
||||||
require.NoError(t, app.Run(cmd))
|
e.Run(t, cmd...)
|
||||||
|
|
||||||
cmds := []string{"", "contract", "generate-rpcwrapper",
|
cmds := []string{"", "contract", "generate-rpcwrapper",
|
||||||
"--config", bindingF,
|
"--config", bindingF,
|
||||||
|
@ -520,7 +515,7 @@ func TestAssistedRPCBindings(t *testing.T) {
|
||||||
if hasDefinedHash {
|
if hasDefinedHash {
|
||||||
cmds = append(cmds, "--hash", "0x00112233445566778899aabbccddeeff00112233")
|
cmds = append(cmds, "--hash", "0x00112233445566778899aabbccddeeff00112233")
|
||||||
}
|
}
|
||||||
require.NoError(t, app.Run(cmds))
|
e.Run(t, cmds...)
|
||||||
|
|
||||||
data, err := os.ReadFile(outFile)
|
data, err := os.ReadFile(outFile)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -548,28 +543,22 @@ func TestAssistedRPCBindings(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerate_Errors(t *testing.T) {
|
func TestGenerate_Errors(t *testing.T) {
|
||||||
app := cli.NewApp()
|
e := testcli.NewExecutor(t, false)
|
||||||
app.Commands = []cli.Command{generateWrapperCmd}
|
args := []string{"neo-go", "contract", "generate-wrapper"}
|
||||||
app.ExitErrHandler = func(*cli.Context, error) {}
|
|
||||||
|
|
||||||
checkError := func(t *testing.T, msg string, args ...string) {
|
|
||||||
// cli.ExitError doesn't implement wraping properly, so we check for an error message.
|
|
||||||
err := app.Run(append([]string{"", "generate-wrapper"}, args...))
|
|
||||||
require.True(t, strings.Contains(err.Error(), msg), "got: %v", err)
|
|
||||||
}
|
|
||||||
t.Run("invalid hash", func(t *testing.T) {
|
t.Run("invalid hash", func(t *testing.T) {
|
||||||
checkError(t, "invalid contract hash", "--hash", "xxx", "--manifest", "yyy", "--out", "zzz")
|
e.RunWithErrorCheckExit(t, "invalid contract hash", append(args, "--hash", "xxx", "--manifest", "yyy", "--out", "zzz")...)
|
||||||
})
|
})
|
||||||
t.Run("missing manifest argument", func(t *testing.T) {
|
t.Run("missing manifest argument", func(t *testing.T) {
|
||||||
checkError(t, "Required flag \"manifest\" not set", "--hash", util.Uint160{}.StringLE(), "--out", "zzz")
|
e.RunWithErrorCheck(t, `Required flag "manifest" not set`, append(args, "--hash", util.Uint160{}.StringLE(), "--out", "zzz")...)
|
||||||
})
|
})
|
||||||
t.Run("missing manifest file", func(t *testing.T) {
|
t.Run("missing manifest file", func(t *testing.T) {
|
||||||
checkError(t, "can't read contract manifest", "--manifest", "notexists", "--hash", util.Uint160{}.StringLE(), "--out", "zzz")
|
e.RunWithErrorCheckExit(t, "can't read contract manifest", append(args, "--manifest", "notexists", "--hash", util.Uint160{}.StringLE(), "--out", "zzz")...)
|
||||||
})
|
})
|
||||||
t.Run("empty manifest", func(t *testing.T) {
|
t.Run("empty manifest", func(t *testing.T) {
|
||||||
manifestFile := filepath.Join(t.TempDir(), "invalid.json")
|
manifestFile := filepath.Join(t.TempDir(), "invalid.json")
|
||||||
require.NoError(t, os.WriteFile(manifestFile, []byte("[]"), os.ModePerm))
|
require.NoError(t, os.WriteFile(manifestFile, []byte("[]"), os.ModePerm))
|
||||||
checkError(t, "json: cannot unmarshal array into Go value of type manifest.Manifest", "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(), "--out", "zzz")
|
e.RunWithErrorCheckExit(t, "json: cannot unmarshal array into Go value of type manifest.Manifest", append(args, "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(), "--out", "zzz")...)
|
||||||
})
|
})
|
||||||
t.Run("invalid manifest", func(t *testing.T) {
|
t.Run("invalid manifest", func(t *testing.T) {
|
||||||
manifestFile := filepath.Join(t.TempDir(), "invalid.json")
|
manifestFile := filepath.Join(t.TempDir(), "invalid.json")
|
||||||
|
@ -577,7 +566,7 @@ func TestGenerate_Errors(t *testing.T) {
|
||||||
rawManifest, err := json.Marshal(m)
|
rawManifest, err := json.Marshal(m)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, os.WriteFile(manifestFile, rawManifest, os.ModePerm))
|
require.NoError(t, os.WriteFile(manifestFile, rawManifest, os.ModePerm))
|
||||||
checkError(t, "ABI: no methods", "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(), "--out", "zzz")
|
e.RunWithErrorCheckExit(t, "ABI: no methods", append(args, "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(), "--out", "zzz")...)
|
||||||
})
|
})
|
||||||
|
|
||||||
manifestFile := filepath.Join(t.TempDir(), "manifest.json")
|
manifestFile := filepath.Join(t.TempDir(), "manifest.json")
|
||||||
|
@ -593,9 +582,8 @@ func TestGenerate_Errors(t *testing.T) {
|
||||||
require.NoError(t, os.WriteFile(manifestFile, rawManifest, os.ModePerm))
|
require.NoError(t, os.WriteFile(manifestFile, rawManifest, os.ModePerm))
|
||||||
|
|
||||||
t.Run("missing config", func(t *testing.T) {
|
t.Run("missing config", func(t *testing.T) {
|
||||||
checkError(t, "can't read config file",
|
e.RunWithErrorCheckExit(t, "can't read config file", append(args, "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(),
|
||||||
"--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(),
|
"--config", filepath.Join(t.TempDir(), "not.exists.yml"), "--out", "zzz")...)
|
||||||
"--config", filepath.Join(t.TempDir(), "not.exists.yml"), "--out", "zzz")
|
|
||||||
})
|
})
|
||||||
t.Run("invalid config", func(t *testing.T) {
|
t.Run("invalid config", func(t *testing.T) {
|
||||||
rawCfg := `package: wrapper
|
rawCfg := `package: wrapper
|
||||||
|
@ -605,23 +593,13 @@ callflags:
|
||||||
cfgPath := filepath.Join(t.TempDir(), "binding.yml")
|
cfgPath := filepath.Join(t.TempDir(), "binding.yml")
|
||||||
require.NoError(t, os.WriteFile(cfgPath, []byte(rawCfg), os.ModePerm))
|
require.NoError(t, os.WriteFile(cfgPath, []byte(rawCfg), os.ModePerm))
|
||||||
|
|
||||||
checkError(t, "can't parse config file",
|
e.RunWithErrorCheckExit(t, "can't parse config file", append(args, "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(),
|
||||||
"--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(),
|
"--config", cfgPath, "--out", "zzz")...)
|
||||||
"--config", cfgPath, "--out", "zzz")
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompile_GuessEventTypes(t *testing.T) {
|
func TestCompile_GuessEventTypes(t *testing.T) {
|
||||||
app := cli.NewApp()
|
e := testcli.NewExecutor(t, false)
|
||||||
app.Commands = NewCommands()
|
|
||||||
app.ExitErrHandler = func(*cli.Context, error) {}
|
|
||||||
|
|
||||||
checkError := func(t *testing.T, msg string, args ...string) {
|
|
||||||
// cli.ExitError doesn't implement wraping properly, so we check for an error message.
|
|
||||||
err := app.Run(args)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.True(t, strings.Contains(err.Error(), msg), "got: %v", err)
|
|
||||||
}
|
|
||||||
check := func(t *testing.T, source string, expectedErrText string) {
|
check := func(t *testing.T, source string, expectedErrText string) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
configFile := filepath.Join(source, "invalid.yml")
|
configFile := filepath.Join(source, "invalid.yml")
|
||||||
|
@ -636,7 +614,7 @@ func TestCompile_GuessEventTypes(t *testing.T) {
|
||||||
"--out", nefF,
|
"--out", nefF,
|
||||||
"--guess-eventtypes",
|
"--guess-eventtypes",
|
||||||
}
|
}
|
||||||
checkError(t, expectedErrText, cmd...)
|
e.RunWithErrorCheckExit(t, expectedErrText, cmd...)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("not declared in manifest", func(t *testing.T) {
|
t.Run("not declared in manifest", func(t *testing.T) {
|
||||||
|
@ -664,10 +642,7 @@ func TestCompile_GuessEventTypes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateRPCBindings_Errors(t *testing.T) {
|
func TestGenerateRPCBindings_Errors(t *testing.T) {
|
||||||
app := cli.NewApp()
|
e := testcli.NewExecutor(t, false)
|
||||||
app.Commands = NewCommands()
|
|
||||||
app.ExitErrHandler = func(*cli.Context, error) {}
|
|
||||||
|
|
||||||
t.Run("duplicating resulting fields", func(t *testing.T) {
|
t.Run("duplicating resulting fields", func(t *testing.T) {
|
||||||
check := func(t *testing.T, packageName string, autogen bool, expectedError string) {
|
check := func(t *testing.T, packageName string, autogen bool, expectedError string) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
@ -687,16 +662,14 @@ func TestGenerateRPCBindings_Errors(t *testing.T) {
|
||||||
if autogen {
|
if autogen {
|
||||||
cmd = append(cmd, "--guess-eventtypes")
|
cmd = append(cmd, "--guess-eventtypes")
|
||||||
}
|
}
|
||||||
require.NoError(t, app.Run(cmd))
|
e.Run(t, cmd...)
|
||||||
|
|
||||||
cmds := []string{"", "contract", "generate-rpcwrapper",
|
cmds := []string{"", "contract", "generate-rpcwrapper",
|
||||||
"--config", bindingF,
|
"--config", bindingF,
|
||||||
"--manifest", manifestF,
|
"--manifest", manifestF,
|
||||||
"--out", out,
|
"--out", out,
|
||||||
}
|
}
|
||||||
err := app.Run(cmds)
|
e.RunWithErrorCheckExit(t, expectedError, cmds...)
|
||||||
require.Error(t, err)
|
|
||||||
require.True(t, strings.Contains(err.Error(), expectedError), err.Error())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("event", func(t *testing.T) {
|
t.Run("event", func(t *testing.T) {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package smartcontract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -13,34 +12,30 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"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/smartcontract/nef"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func manifestAddGroup(ctx *cli.Context) error {
|
func manifestAddGroup(ctx *cli.Context) error {
|
||||||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
if err := cmdargs.EnsureNone(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
sender, err := flags.ParseAddress(ctx.String("sender"))
|
sender := ctx.Generic("sender").(*flags.Address)
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("invalid sender: %w", err), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
nf, _, err := readNEFFile(ctx.String("nef"))
|
nf, _, err := readNEFFile(ctx.String("nef"))
|
||||||
if err != nil {
|
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")
|
mPath := ctx.String("manifest")
|
||||||
m, _, err := readManifest(mPath, util.Uint160{})
|
m, _, err := readManifest(mPath, util.Uint160{})
|
||||||
if err != nil {
|
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)
|
h := state.CreateContractHash(sender.Uint160(), nf.Checksum, m.Name)
|
||||||
|
|
||||||
gAcc, w, err := options.GetAccFromContext(ctx)
|
gAcc, w, err := options.GetAccFromContext(ctx)
|
||||||
if err != nil {
|
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()
|
defer w.Close()
|
||||||
|
|
||||||
|
@ -64,21 +59,17 @@ func manifestAddGroup(ctx *cli.Context) error {
|
||||||
|
|
||||||
rawM, err := json.Marshal(m)
|
rawM, err := json.Marshal(m)
|
||||||
if err != nil {
|
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)
|
err = os.WriteFile(mPath, rawM, os.ModePerm)
|
||||||
if err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readNEFFile(filename string) (*nef.File, []byte, error) {
|
func readNEFFile(filename string) (*nef.File, []byte, error) {
|
||||||
if len(filename) == 0 {
|
|
||||||
return nil, nil, errors.New("no nef file was provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.ReadFile(filename)
|
f, err := os.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
@ -96,10 +87,6 @@ func readNEFFile(filename string) (*nef.File, []byte, error) {
|
||||||
// it for validness against the provided contract hash. If empty hash is specified
|
// it for validness against the provided contract hash. If empty hash is specified
|
||||||
// then no hash-related manifest groups check is performed.
|
// then no hash-related manifest groups check is performed.
|
||||||
func readManifest(filename string, hash util.Uint160) (*manifest.Manifest, []byte, error) {
|
func readManifest(filename string, hash util.Uint160) (*manifest.Manifest, []byte, error) {
|
||||||
if len(filename) == 0 {
|
|
||||||
return nil, nil, errNoManifestFile
|
|
||||||
}
|
|
||||||
|
|
||||||
manifestBytes, err := os.ReadFile(filename)
|
manifestBytes, err := os.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
|
@ -27,25 +27,27 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// addressFlagName is a flag name used for address-related operations. It should be
|
// addressFlagName and addressFlagAlias are a flag name and its alias
|
||||||
// the same within the smartcontract package, thus, use this constant.
|
// used for address-related operations. It should be the same within
|
||||||
const addressFlagName = "address, a"
|
// the smartcontract package, thus, use this constant.
|
||||||
|
const (
|
||||||
|
addressFlagName = "address"
|
||||||
|
addressFlagAlias = "a"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errNoInput = errors.New("no input file was found, specify an input file with the '--in or -i' flag")
|
|
||||||
errNoConfFile = errors.New("no config file was found, specify a config file with the '--config' or '-c' flag")
|
errNoConfFile = errors.New("no config file was found, specify a config file with the '--config' or '-c' flag")
|
||||||
errNoManifestFile = errors.New("no manifest file was found, specify manifest file with '--manifest' or '-m' flag")
|
|
||||||
errNoMethod = errors.New("no method specified for function invocation command")
|
errNoMethod = errors.New("no method specified for function invocation command")
|
||||||
errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument")
|
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")
|
errFileExist = errors.New("A file with given smart-contract name already exists")
|
||||||
addressFlag = flags.AddressFlag{
|
addressFlag = &flags.AddressFlag{
|
||||||
Name: addressFlagName,
|
Name: addressFlagName,
|
||||||
Usage: "address to use as transaction signee (and gas source)",
|
Aliases: []string{addressFlagAlias},
|
||||||
|
Usage: "Address to use as transaction signee (and gas source)",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -74,11 +76,14 @@ func RuntimeNotify(args []any) {
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCommands returns 'contract' command.
|
// NewCommands returns 'contract' command.
|
||||||
func NewCommands() []cli.Command {
|
func NewCommands() []*cli.Command {
|
||||||
testInvokeScriptFlags := []cli.Flag{
|
testInvokeScriptFlags := []cli.Flag{
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "in, i",
|
Name: "in",
|
||||||
|
Aliases: []string{"i"},
|
||||||
|
Required: true,
|
||||||
Usage: "Input location of the .nef file that needs to be invoked",
|
Usage: "Input location of the .nef file that needs to be invoked",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("in"),
|
||||||
},
|
},
|
||||||
options.Historic,
|
options.Historic,
|
||||||
}
|
}
|
||||||
|
@ -96,40 +101,56 @@ func NewCommands() []cli.Command {
|
||||||
invokeFunctionFlags = append(invokeFunctionFlags, options.Wallet...)
|
invokeFunctionFlags = append(invokeFunctionFlags, options.Wallet...)
|
||||||
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
|
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
|
||||||
deployFlags := append(invokeFunctionFlags, []cli.Flag{
|
deployFlags := append(invokeFunctionFlags, []cli.Flag{
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "in, i",
|
Name: "in",
|
||||||
|
Aliases: []string{"i"},
|
||||||
|
Required: true,
|
||||||
Usage: "Input file for the smart contract (*.nef)",
|
Usage: "Input file for the smart contract (*.nef)",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("in"),
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "manifest, m",
|
Name: "manifest",
|
||||||
|
Aliases: []string{"m"},
|
||||||
|
Required: true,
|
||||||
Usage: "Manifest input file (*.manifest.json)",
|
Usage: "Manifest input file (*.manifest.json)",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("manifest"),
|
||||||
},
|
},
|
||||||
}...)
|
}...)
|
||||||
manifestAddGroupFlags := append([]cli.Flag{
|
manifestAddGroupFlags := append([]cli.Flag{
|
||||||
cli.StringFlag{
|
&flags.AddressFlag{
|
||||||
Name: "sender, s",
|
Name: "sender",
|
||||||
Usage: "deploy transaction sender",
|
Aliases: []string{"s"},
|
||||||
|
Required: true,
|
||||||
|
Usage: "Deploy transaction sender",
|
||||||
},
|
},
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: addressFlagName, // use the same name for handler code unification.
|
Name: addressFlagName, // use the same name for handler code unification.
|
||||||
Usage: "account to sign group with",
|
Aliases: []string{addressFlagAlias},
|
||||||
|
Required: true,
|
||||||
|
Usage: "Account to sign group with",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "nef, n",
|
Name: "nef",
|
||||||
Usage: "path to the NEF file",
|
Aliases: []string{"n"},
|
||||||
|
Required: true,
|
||||||
|
Usage: "Path to the NEF file",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("nef"),
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "manifest, m",
|
Name: "manifest",
|
||||||
Usage: "path to the manifest",
|
Aliases: []string{"m"},
|
||||||
|
Required: true,
|
||||||
|
Usage: "Path to the manifest",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("manifest"),
|
||||||
},
|
},
|
||||||
}, options.Wallet...)
|
}, options.Wallet...)
|
||||||
return []cli.Command{{
|
return []*cli.Command{{
|
||||||
Name: "contract",
|
Name: "contract",
|
||||||
Usage: "compile - debug - deploy smart contracts",
|
Usage: "Compile - debug - deploy smart contracts",
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "compile",
|
Name: "compile",
|
||||||
Usage: "compile a smart contract to a .nef file",
|
Usage: "Compile a smart contract to a .nef file",
|
||||||
UsageText: "neo-go contract compile -i path [-o nef] [-v] [-d] [-m manifest] [-c yaml] [--bindings file] [--no-standards] [--no-events] [--no-permissions] [--guess-eventtypes]",
|
UsageText: "neo-go contract compile -i path [-o nef] [-v] [-d] [-m manifest] [-c yaml] [--bindings file] [--no-standards] [--no-events] [--no-permissions] [--guess-eventtypes]",
|
||||||
Description: `Compiles given smart contract to a .nef file and emits other associated
|
Description: `Compiles given smart contract to a .nef file and emits other associated
|
||||||
information (manifest, bindings configuration, debug information files) if
|
information (manifest, bindings configuration, debug information files) if
|
||||||
|
@ -141,55 +162,63 @@ func NewCommands() []cli.Command {
|
||||||
`,
|
`,
|
||||||
Action: contractCompile,
|
Action: contractCompile,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "in, i",
|
Name: "in",
|
||||||
|
Aliases: []string{"i"},
|
||||||
|
Required: true,
|
||||||
Usage: "Input file for the smart contract to be compiled (*.go file or directory)",
|
Usage: "Input file for the smart contract to be compiled (*.go file or directory)",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("in"),
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "out, o",
|
Name: "out",
|
||||||
|
Aliases: []string{"o"},
|
||||||
Usage: "Output of the compiled contract",
|
Usage: "Output of the compiled contract",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "verbose, v",
|
Name: "verbose",
|
||||||
|
Aliases: []string{"v"},
|
||||||
Usage: "Print out additional information after a compiling",
|
Usage: "Print out additional information after a compiling",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "debug, d",
|
Name: "debug",
|
||||||
|
Aliases: []string{"d"},
|
||||||
Usage: "Emit debug info in a separate file",
|
Usage: "Emit debug info in a separate file",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "manifest, m",
|
Name: "manifest",
|
||||||
|
Aliases: []string{"m"},
|
||||||
Usage: "Emit contract manifest (*.manifest.json) file into separate file using configuration input file (*.yml)",
|
Usage: "Emit contract manifest (*.manifest.json) file into separate file using configuration input file (*.yml)",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "config, c",
|
Name: "config",
|
||||||
|
Aliases: []string{"c"},
|
||||||
Usage: "Configuration input file (*.yml)",
|
Usage: "Configuration input file (*.yml)",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "no-standards",
|
Name: "no-standards",
|
||||||
Usage: "do not check compliance with supported standards",
|
Usage: "Do not check compliance with supported standards",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "no-events",
|
Name: "no-events",
|
||||||
Usage: "do not check emitted events with the manifest",
|
Usage: "Do not check emitted events with the manifest",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "no-permissions",
|
Name: "no-permissions",
|
||||||
Usage: "do not check if invoked contracts are allowed in manifest",
|
Usage: "Do not check if invoked contracts are allowed in manifest",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "guess-eventtypes",
|
Name: "guess-eventtypes",
|
||||||
Usage: "guess event types for smart-contract bindings configuration from the code usages",
|
Usage: "Guess event types for smart-contract bindings configuration from the code usages",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "bindings",
|
Name: "bindings",
|
||||||
Usage: "output file for smart-contract bindings configuration",
|
Usage: "Output file for smart-contract bindings configuration",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "deploy",
|
Name: "deploy",
|
||||||
Usage: "deploy a smart contract (.nef with description)",
|
Usage: "Deploy a smart contract (.nef with description)",
|
||||||
UsageText: "neo-go contract deploy -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] --in contract.nef --manifest contract.manifest.json [--out file] [--force] [--await] [data]",
|
UsageText: "neo-go contract deploy -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] --in contract.nef --manifest contract.manifest.json [--out file] [--force] [--await] [data]",
|
||||||
Description: `Deploys given contract into the chain. The gas parameter is for additional
|
Description: `Deploys given contract into the chain. The gas parameter is for additional
|
||||||
gas to be added as a network fee to prioritize the transaction. The data
|
gas to be added as a network fee to prioritize the transaction. The data
|
||||||
|
@ -204,7 +233,7 @@ func NewCommands() []cli.Command {
|
||||||
generateRPCWrapperCmd,
|
generateRPCWrapperCmd,
|
||||||
{
|
{
|
||||||
Name: "invokefunction",
|
Name: "invokefunction",
|
||||||
Usage: "invoke deployed contract on the blockchain",
|
Usage: "Invoke deployed contract on the blockchain",
|
||||||
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] [--out file] [--force] [--await] scripthash [method] [arguments...] [--] [signers...]",
|
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] [--out file] [--force] [--await] scripthash [method] [arguments...] [--] [signers...]",
|
||||||
Description: `Executes given (as a script hash) deployed script with the given method,
|
Description: `Executes given (as a script hash) deployed script with the given method,
|
||||||
arguments and signers. Sender is included in the list of signers by default
|
arguments and signers. Sender is included in the list of signers by default
|
||||||
|
@ -219,7 +248,7 @@ func NewCommands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "testinvokefunction",
|
Name: "testinvokefunction",
|
||||||
Usage: "invoke deployed contract on the blockchain (test mode)",
|
Usage: "Invoke deployed contract on the blockchain (test mode)",
|
||||||
UsageText: "neo-go contract testinvokefunction -r endpoint [--historic index/hash] scripthash [method] [arguments...] [--] [signers...]",
|
UsageText: "neo-go contract testinvokefunction -r endpoint [--historic index/hash] scripthash [method] [arguments...] [--] [signers...]",
|
||||||
Description: `Executes given (as a script hash) deployed script with the given method,
|
Description: `Executes given (as a script hash) deployed script with the given method,
|
||||||
arguments and signers (sender is not included by default). If no method is given
|
arguments and signers (sender is not included by default). If no method is given
|
||||||
|
@ -250,63 +279,78 @@ func NewCommands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "init",
|
Name: "init",
|
||||||
Usage: "initialize a new smart-contract in a directory with boiler plate code",
|
Usage: "Initialize a new smart-contract in a directory with boiler plate code",
|
||||||
UsageText: "neo-go contract init -n name [--skip-details]",
|
UsageText: "neo-go contract init -n name [--skip-details]",
|
||||||
Action: initSmartContract,
|
Action: initSmartContract,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name, n",
|
Name: "name",
|
||||||
Usage: "name of the smart-contract to be initialized",
|
Aliases: []string{"n"},
|
||||||
|
Required: true,
|
||||||
|
Usage: "Name of the smart-contract to be initialized",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("name"),
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "skip-details, skip",
|
Name: "skip-details",
|
||||||
Usage: "skip filling in the projects and contract details",
|
Aliases: []string{"skip"},
|
||||||
|
Usage: "Skip filling in the projects and contract details",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "inspect",
|
Name: "inspect",
|
||||||
Usage: "creates a user readable dump of the program instructions",
|
Usage: "Creates a user readable dump of the program instructions",
|
||||||
UsageText: "neo-go contract inspect -i file [-c]",
|
UsageText: "neo-go contract inspect -i file [-c]",
|
||||||
Action: inspect,
|
Action: inspect,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "compile, c",
|
Name: "compile",
|
||||||
Usage: "compile input file (it should be go code then)",
|
Aliases: []string{"c"},
|
||||||
|
Usage: "Compile input file (it should be go code then)",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "in, i",
|
Name: "in",
|
||||||
Usage: "input file of the program (either .go or .nef)",
|
Aliases: []string{"i"},
|
||||||
|
Required: true,
|
||||||
|
Usage: "Input file of the program (either .go or .nef)",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("in"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "calc-hash",
|
Name: "calc-hash",
|
||||||
Usage: "calculates hash of a contract after deployment",
|
Usage: "Calculates hash of a contract after deployment",
|
||||||
UsageText: "neo-go contract calc-hash -i nef -m manifest -s address",
|
UsageText: "neo-go contract calc-hash -i nef -m manifest -s address",
|
||||||
Action: calcHash,
|
Action: calcHash,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "sender, s",
|
Name: "sender",
|
||||||
Usage: "sender script hash or address",
|
Aliases: []string{"s"},
|
||||||
|
Required: true,
|
||||||
|
Usage: "Sender script hash or address",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "in",
|
Name: "in",
|
||||||
Usage: "path to NEF file",
|
Required: true,
|
||||||
|
Usage: "Path to NEF file",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("in"),
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "manifest, m",
|
Name: "manifest",
|
||||||
Usage: "path to manifest file",
|
Aliases: []string{"m"},
|
||||||
|
Required: true,
|
||||||
|
Usage: "Path to manifest file",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("manifest"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "manifest",
|
Name: "manifest",
|
||||||
Usage: "manifest-related commands",
|
Usage: "Manifest-related commands",
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "add-group",
|
Name: "add-group",
|
||||||
Usage: "adds group to the manifest",
|
Usage: "Adds group to the manifest",
|
||||||
UsageText: "neo-go contract manifest add-group -w wallet [--wallet-config path] -n nef -m manifest -a address -s address",
|
UsageText: "neo-go contract manifest add-group -w wallet [--wallet-config path] -n nef -m manifest -a address -s address",
|
||||||
Action: manifestAddGroup,
|
Action: manifestAddGroup,
|
||||||
Flags: manifestAddGroupFlags,
|
Flags: manifestAddGroupFlags,
|
||||||
|
@ -323,13 +367,10 @@ func initSmartContract(ctx *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
contractName := ctx.String("name")
|
contractName := ctx.String("name")
|
||||||
if contractName == "" {
|
|
||||||
return cli.NewExitError(errNoSmartContractName, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the file already exists, if yes, exit
|
// Check if the file already exists, if yes, exit
|
||||||
if _, err := os.Stat(contractName); err == nil {
|
if _, err := os.Stat(contractName); err == nil {
|
||||||
return cli.NewExitError(errFileExist, 1)
|
return cli.Exit(errFileExist, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
basePath := contractName
|
basePath := contractName
|
||||||
|
@ -338,7 +379,7 @@ func initSmartContract(ctx *cli.Context) error {
|
||||||
|
|
||||||
// create base directory
|
// create base directory
|
||||||
if err := os.Mkdir(basePath, os.ModePerm); err != nil {
|
if err := os.Mkdir(basePath, os.ModePerm); err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
m := ProjectConfig{
|
m := ProjectConfig{
|
||||||
|
@ -363,10 +404,10 @@ func initSmartContract(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
b, err := yaml.Marshal(m)
|
b, err := yaml.Marshal(m)
|
||||||
if err != nil {
|
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 {
|
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
|
ver := ModVersion
|
||||||
|
@ -382,12 +423,12 @@ require (
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop ` + ver + `
|
github.com/nspcc-dev/neo-go/pkg/interop ` + ver + `
|
||||||
)`)
|
)`)
|
||||||
if err := os.WriteFile(filepath.Join(basePath, "go.mod"), gm, 0644); err != nil {
|
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))
|
data := []byte(fmt.Sprintf(smartContractTmpl, contractName))
|
||||||
if err := os.WriteFile(filepath.Join(basePath, fileName), data, 0644); err != nil {
|
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)
|
fmt.Fprintf(ctx.App.Writer, "Successfully initialized smart contract [%s]\n", contractName)
|
||||||
|
@ -400,16 +441,13 @@ func contractCompile(ctx *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
src := ctx.String("in")
|
src := ctx.String("in")
|
||||||
if len(src) == 0 {
|
|
||||||
return cli.NewExitError(errNoInput, 1)
|
|
||||||
}
|
|
||||||
manifestFile := ctx.String("manifest")
|
manifestFile := ctx.String("manifest")
|
||||||
confFile := ctx.String("config")
|
confFile := ctx.String("config")
|
||||||
debugFile := ctx.String("debug")
|
debugFile := ctx.String("debug")
|
||||||
out := ctx.String("out")
|
out := ctx.String("out")
|
||||||
bindings := ctx.String("bindings")
|
bindings := ctx.String("bindings")
|
||||||
if len(confFile) == 0 && (len(manifestFile) != 0 || len(debugFile) != 0 || len(bindings) != 0) {
|
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 &&
|
autocomplete := len(manifestFile) == 0 &&
|
||||||
len(confFile) == 0 &&
|
len(confFile) == 0 &&
|
||||||
|
@ -419,7 +457,7 @@ func contractCompile(ctx *cli.Context) error {
|
||||||
var root string
|
var root string
|
||||||
fileInfo, err := os.Stat(src)
|
fileInfo, err := os.Stat(src)
|
||||||
if err != nil {
|
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() {
|
if fileInfo.IsDir() {
|
||||||
base := filepath.Base(fileInfo.Name())
|
base := filepath.Base(fileInfo.Name())
|
||||||
|
@ -470,7 +508,7 @@ func contractCompile(ctx *cli.Context) error {
|
||||||
|
|
||||||
result, err := compiler.CompileAndSave(src, o)
|
result, err := compiler.CompileAndSave(src, o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if ctx.Bool("verbose") {
|
if ctx.Bool("verbose") {
|
||||||
fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(result))
|
fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(result))
|
||||||
|
@ -484,34 +522,25 @@ func calcHash(ctx *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
sender := ctx.Generic("sender").(*flags.Address)
|
sender := ctx.Generic("sender").(*flags.Address)
|
||||||
if !sender.IsSet {
|
|
||||||
return cli.NewExitError("sender is not set", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
p := ctx.String("in")
|
p := ctx.String("in")
|
||||||
if p == "" {
|
|
||||||
return cli.NewExitError(errors.New("no .nef file was provided"), 1)
|
|
||||||
}
|
|
||||||
mpath := ctx.String("manifest")
|
mpath := ctx.String("manifest")
|
||||||
if mpath == "" {
|
|
||||||
return cli.NewExitError(errors.New("no manifest file provided"), 1)
|
|
||||||
}
|
|
||||||
f, err := os.ReadFile(p)
|
f, err := os.ReadFile(p)
|
||||||
if err != nil {
|
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)
|
nefFile, err := nef.FileFromBytes(f)
|
||||||
if err != nil {
|
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)
|
manifestBytes, err := os.ReadFile(mpath)
|
||||||
if err != nil {
|
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{}
|
m := &manifest.Manifest{}
|
||||||
err = json.Unmarshal(manifestBytes, m)
|
err = json.Unmarshal(manifestBytes, m)
|
||||||
if err != nil {
|
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())
|
fmt.Fprintln(ctx.App.Writer, "Contract hash:", state.CreateContractHash(sender.Uint160(), nefFile.Checksum, m.Name).StringLE())
|
||||||
return nil
|
return nil
|
||||||
|
@ -528,7 +557,7 @@ func invokeFunction(ctx *cli.Context) error {
|
||||||
func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
exitErr *cli.ExitError
|
exitErr cli.ExitCoder
|
||||||
operation string
|
operation string
|
||||||
params []any
|
params []any
|
||||||
paramsStart = 1
|
paramsStart = 1
|
||||||
|
@ -539,22 +568,23 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
||||||
|
|
||||||
args := ctx.Args()
|
args := ctx.Args()
|
||||||
if !args.Present() {
|
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 {
|
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 {
|
if len(argsSlice) <= 1 {
|
||||||
return cli.NewExitError(errNoMethod, 1)
|
return cli.Exit(errNoMethod, 1)
|
||||||
}
|
}
|
||||||
operation = args[1]
|
operation = argsSlice[1]
|
||||||
paramsStart++
|
paramsStart++
|
||||||
|
|
||||||
if len(args) > paramsStart {
|
if len(argsSlice) > paramsStart {
|
||||||
cosignersOffset, scParams, err = cmdargs.ParseParams(args[paramsStart:], true)
|
cosignersOffset, scParams, err = cmdargs.ParseParams(argsSlice[paramsStart:], true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
params = make([]any, len(scParams))
|
params = make([]any, len(scParams))
|
||||||
for i := range scParams {
|
for i := range scParams {
|
||||||
|
@ -575,7 +605,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
||||||
if signAndPush {
|
if signAndPush {
|
||||||
acc, w, err = options.GetAccFromContext(ctx)
|
acc, w, err = options.GetAccFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer w.Close()
|
defer w.Close()
|
||||||
}
|
}
|
||||||
|
@ -595,7 +625,7 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
||||||
if signAndPush {
|
if signAndPush {
|
||||||
signersAccounts, err = cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.None)
|
signersAccounts, err = cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.None)
|
||||||
if err != nil {
|
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)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
@ -615,12 +645,12 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
||||||
out := ctx.String("out")
|
out := ctx.String("out")
|
||||||
resp, err = inv.Call(script, operation, params...)
|
resp, err = inv.Call(script, operation, params...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if resp.State != "HALT" {
|
if resp.State != "HALT" {
|
||||||
errText := fmt.Sprintf("Warning: %s VM state returned from the RPC node: %s", resp.State, resp.FaultException)
|
errText := fmt.Sprintf("Warning: %s VM state returned from the RPC node: %s", resp.State, resp.FaultException)
|
||||||
if !signAndPush {
|
if !signAndPush {
|
||||||
return cli.NewExitError(errText, 1)
|
return cli.Exit(errText, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
action := "send"
|
action := "send"
|
||||||
|
@ -630,42 +660,38 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
||||||
process = "Saving"
|
process = "Saving"
|
||||||
}
|
}
|
||||||
if !ctx.Bool("force") {
|
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...")
|
fmt.Fprintln(ctx.App.Writer, errText+".\n"+process+" transaction...")
|
||||||
}
|
}
|
||||||
if !signAndPush {
|
if !signAndPush {
|
||||||
b, err := json.MarshalIndent(resp, "", " ")
|
b, err := json.MarshalIndent(resp, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(ctx.App.Writer, string(b))
|
fmt.Fprintln(ctx.App.Writer, string(b))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if len(resp.Script) == 0 {
|
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)
|
tx, err := act.MakeUnsignedUncheckedRun(resp.Script, resp.GasConsumed, nil)
|
||||||
if err != 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)
|
return txctx.SignAndSend(ctx, act, acc, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInvokeScript(ctx *cli.Context) error {
|
func testInvokeScript(ctx *cli.Context) error {
|
||||||
src := ctx.String("in")
|
src := ctx.String("in")
|
||||||
if len(src) == 0 {
|
|
||||||
return cli.NewExitError(errNoInput, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := os.ReadFile(src)
|
b, err := os.ReadFile(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
nefFile, err := nef.FileFromBytes(b)
|
nefFile, err := nef.FileFromBytes(b)
|
||||||
if err != nil {
|
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)
|
signers, exitErr := cmdargs.GetSignersFromContext(ctx, 0)
|
||||||
|
@ -683,12 +709,12 @@ func testInvokeScript(ctx *cli.Context) error {
|
||||||
|
|
||||||
resp, err := inv.Run(nefFile.Script)
|
resp, err := inv.Run(nefFile.Script)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err = json.MarshalIndent(resp, "", " ")
|
b, err = json.MarshalIndent(resp, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(ctx.App.Writer, string(b))
|
fmt.Fprintln(ctx.App.Writer, string(b))
|
||||||
|
@ -714,9 +740,6 @@ func inspect(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
in := ctx.String("in")
|
in := ctx.String("in")
|
||||||
compile := ctx.Bool("compile")
|
compile := ctx.Bool("compile")
|
||||||
if len(in) == 0 {
|
|
||||||
return cli.NewExitError(errNoInput, 1)
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
b []byte
|
b []byte
|
||||||
err error
|
err error
|
||||||
|
@ -724,16 +747,16 @@ func inspect(ctx *cli.Context) error {
|
||||||
if compile {
|
if compile {
|
||||||
b, err = compiler.Compile(in, nil)
|
b, err = compiler.Compile(in, nil)
|
||||||
if err != 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 {
|
} else {
|
||||||
f, err := os.ReadFile(in)
|
f, err := os.ReadFile(in)
|
||||||
if err != nil {
|
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)
|
nefFile, err := nef.FileFromBytes(f)
|
||||||
if err != nil {
|
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
|
b = nefFile.Script
|
||||||
}
|
}
|
||||||
|
@ -748,22 +771,22 @@ func inspect(ctx *cli.Context) error {
|
||||||
func contractDeploy(ctx *cli.Context) error {
|
func contractDeploy(ctx *cli.Context) error {
|
||||||
nefFile, f, err := readNEFFile(ctx.String("in"))
|
nefFile, f, err := readNEFFile(ctx.String("in"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
m, manifestBytes, err := readManifest(ctx.String("manifest"), util.Uint160{})
|
m, manifestBytes, err := readManifest(ctx.String("manifest"), util.Uint160{})
|
||||||
if err != nil {
|
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}
|
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 {
|
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 {
|
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 {
|
if len(data) != 0 {
|
||||||
appCallParams = append(appCallParams, data[0])
|
appCallParams = append(appCallParams, data[0])
|
||||||
|
@ -771,7 +794,7 @@ func contractDeploy(ctx *cli.Context) error {
|
||||||
|
|
||||||
acc, w, err := options.GetAccFromContext(ctx)
|
acc, w, err := options.GetAccFromContext(ctx)
|
||||||
if err != nil {
|
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()
|
defer w.Close()
|
||||||
sender := acc.ScriptHash()
|
sender := acc.ScriptHash()
|
||||||
|
@ -801,12 +824,12 @@ func ParseContractConfig(confFile string) (ProjectConfig, error) {
|
||||||
conf := ProjectConfig{}
|
conf := ProjectConfig{}
|
||||||
confBytes, err := os.ReadFile(confFile)
|
confBytes, err := os.ReadFile(confFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return conf, cli.NewExitError(err, 1)
|
return conf, cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = yaml.Unmarshal(confBytes, &conf)
|
err = yaml.Unmarshal(confBytes, &conf)
|
||||||
if err != nil {
|
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
|
return conf, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -16,34 +16,36 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// GasFlag is a flag used for the additional network fee.
|
// GasFlag is a flag used for the additional network fee.
|
||||||
GasFlag = flags.Fixed8Flag{
|
GasFlag = &flags.Fixed8Flag{
|
||||||
Name: "gas, g",
|
Name: "gas",
|
||||||
Usage: "network fee to add to the transaction (prioritizing it)",
|
Aliases: []string{"g"},
|
||||||
|
Usage: "Network fee to add to the transaction (prioritizing it)",
|
||||||
}
|
}
|
||||||
// SysGasFlag is a flag used for the additional system fee.
|
// SysGasFlag is a flag used for the additional system fee.
|
||||||
SysGasFlag = flags.Fixed8Flag{
|
SysGasFlag = &flags.Fixed8Flag{
|
||||||
Name: "sysgas, e",
|
Name: "sysgas",
|
||||||
Usage: "system fee to add to the transaction (compensating for execution)",
|
Aliases: []string{"e"},
|
||||||
|
Usage: "System fee to add to the transaction (compensating for execution)",
|
||||||
}
|
}
|
||||||
// OutFlag is a flag used for file output.
|
// OutFlag is a flag used for file output.
|
||||||
OutFlag = cli.StringFlag{
|
OutFlag = &cli.StringFlag{
|
||||||
Name: "out",
|
Name: "out",
|
||||||
Usage: "file (JSON) to put signature context with a transaction to",
|
Usage: "File (JSON) to put signature context with a transaction to",
|
||||||
}
|
}
|
||||||
// ForceFlag is a flag used to force transaction send.
|
// ForceFlag is a flag used to force transaction send.
|
||||||
ForceFlag = cli.BoolFlag{
|
ForceFlag = &cli.BoolFlag{
|
||||||
Name: "force",
|
Name: "force",
|
||||||
Usage: "Do not ask for a confirmation (and ignore errors)",
|
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 is a flag used to wait for the transaction to be included in a block.
|
||||||
AwaitFlag = cli.BoolFlag{
|
AwaitFlag = &cli.BoolFlag{
|
||||||
Name: "await",
|
Name: "await",
|
||||||
Usage: "wait for the transaction to be included in a block",
|
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()
|
promptTime := time.Now()
|
||||||
err := input.ConfirmTx(ctx.App.Writer, tx)
|
err := input.ConfirmTx(ctx.App.Writer, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
waitTime := time.Since(promptTime)
|
waitTime := time.Since(promptTime)
|
||||||
// Compensate for confirmation waiting.
|
// 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)
|
resTx, vub, err = act.SignAndSend(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if ctx.Bool("await") {
|
if ctx.Bool("await") {
|
||||||
aer, err = act.Wait(resTx, vub, err)
|
aer, err = act.Wait(resTx, vub, err)
|
||||||
if err != nil {
|
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 {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
DumpTransactionInfo(ctx.App.Writer, tx.Hash(), aer)
|
DumpTransactionInfo(ctx.App.Writer, tx.Hash(), aer)
|
||||||
|
|
|
@ -16,20 +16,20 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func cancelTx(ctx *cli.Context) error {
|
func cancelTx(ctx *cli.Context) error {
|
||||||
args := ctx.Args()
|
args := ctx.Args().Slice()
|
||||||
if len(args) == 0 {
|
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 {
|
} 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"))
|
txHash, err := util.Uint256DecodeStringLE(strings.TrimPrefix(args[0], "0x"))
|
||||||
if err != nil {
|
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)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
@ -37,13 +37,13 @@ func cancelTx(ctx *cli.Context) error {
|
||||||
|
|
||||||
acc, w, err := options.GetAccFromContext(ctx)
|
acc, w, err := options.GetAccFromContext(ctx)
|
||||||
if err != nil {
|
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()
|
defer w.Close()
|
||||||
|
|
||||||
signers, err := cmdargs.GetSignersAccounts(acc, w, nil, transaction.CalledByEntry)
|
signers, err := cmdargs.GetSignersAccounts(acc, w, nil, transaction.CalledByEntry)
|
||||||
if err != nil {
|
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)
|
c, a, exitErr := options.GetRPCWithActor(gctx, ctx, signers)
|
||||||
if exitErr != nil {
|
if exitErr != nil {
|
||||||
|
@ -52,11 +52,11 @@ func cancelTx(ctx *cli.Context) error {
|
||||||
|
|
||||||
mainTx, _ := c.GetRawTransactionVerbose(txHash)
|
mainTx, _ := c.GetRawTransactionVerbose(txHash)
|
||||||
if mainTx != nil && !mainTx.Blockhash.Equals(util.Uint256{}) {
|
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()) {
|
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 {
|
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
|
return nil
|
||||||
})
|
})
|
||||||
if err != 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
|
var res *state.AppExecResult
|
||||||
if ctx.Bool("await") {
|
if ctx.Bool("await") {
|
||||||
|
@ -82,19 +82,19 @@ func cancelTx(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, waiter.ErrTxNotAccepted) {
|
if errors.Is(err, waiter.ErrTxNotAccepted) {
|
||||||
if mainTx == nil {
|
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)
|
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 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) {
|
if txHash.Equals(res.Container) {
|
||||||
tx, err := c.GetRawTransactionVerbose(txHash)
|
tx, err := c.GetRawTransactionVerbose(txHash)
|
||||||
if err != nil {
|
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")
|
fmt.Fprintln(ctx.App.Writer, "Conflicting transaction accepted")
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,27 +11,32 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/txctx"
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
vmcli "github.com/nspcc-dev/neo-go/cli/vm"
|
vmcli "github.com/nspcc-dev/neo-go/cli/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/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.
|
// NewCommands returns util commands for neo-go CLI.
|
||||||
func NewCommands() []cli.Command {
|
func NewCommands() []*cli.Command {
|
||||||
txDumpFlags := append([]cli.Flag{}, options.RPC...)
|
// By default, RPC flag is required. sendtx and txdump may be called without provided rpc-endpoint.
|
||||||
|
rpcFlagOriginal, _ := options.RPC[0].(*cli.StringFlag)
|
||||||
|
rpcFlag := *rpcFlagOriginal
|
||||||
|
rpcFlag.Required = false
|
||||||
|
txDumpFlags := append([]cli.Flag{&rpcFlag}, options.RPC[1:]...)
|
||||||
txSendFlags := append(txDumpFlags, txctx.AwaitFlag)
|
txSendFlags := append(txDumpFlags, txctx.AwaitFlag)
|
||||||
txCancelFlags := append([]cli.Flag{
|
txCancelFlags := append([]cli.Flag{
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address",
|
||||||
Usage: "address to use as conflicting transaction signee (and gas source)",
|
Aliases: []string{"a"},
|
||||||
|
Usage: "Address to use as conflicting transaction signee (and gas source)",
|
||||||
},
|
},
|
||||||
txctx.GasFlag,
|
txctx.GasFlag,
|
||||||
txctx.AwaitFlag,
|
txctx.AwaitFlag,
|
||||||
}, options.RPC...)
|
}, options.RPC...)
|
||||||
txCancelFlags = append(txCancelFlags, options.Wallet...)
|
txCancelFlags = append(txCancelFlags, options.Wallet...)
|
||||||
return []cli.Command{
|
return []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "util",
|
Name: "util",
|
||||||
Usage: "Various helper commands",
|
Usage: "Various helper commands",
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "convert",
|
Name: "convert",
|
||||||
Usage: "Convert provided argument into other possible formats",
|
Usage: "Convert provided argument into other possible formats",
|
||||||
|
@ -44,7 +49,7 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "sendtx",
|
Name: "sendtx",
|
||||||
Usage: "Send complete transaction stored in a context file",
|
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
|
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
|
completely signed and ready. This command expects a ContractParametersContext
|
||||||
JSON file for input, it can't handle binary (or hex- or base64-encoded)
|
JSON file for input, it can't handle binary (or hex- or base64-encoded)
|
||||||
|
@ -57,7 +62,7 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "canceltx",
|
Name: "canceltx",
|
||||||
Usage: "Cancel transaction by sending conflicting transaction",
|
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> [--address <account>] [--wallet-config <path>] [--gas <gas>] [--await] <txid>",
|
||||||
Description: `Aims to prevent a transaction from being added to the blockchain by dispatching a more
|
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
|
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
|
be the transaction hash. If another account is not specified, the conflicting transaction is
|
||||||
|
@ -90,16 +95,17 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "ops",
|
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.",
|
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,
|
Action: handleOps,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "in, i",
|
Name: "in",
|
||||||
Usage: "input file containing base64- or hex- encoded script representation",
|
Aliases: []string{"i"},
|
||||||
|
Usage: "Input file containing base64- or hex- encoded script representation",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "hex",
|
Name: "hex",
|
||||||
Usage: "use hex encoding and do not check base64",
|
Usage: "Use hex encoding and do not check base64",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -109,9 +115,9 @@ func NewCommands() []cli.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleParse(ctx *cli.Context) error {
|
func handleParse(ctx *cli.Context) error {
|
||||||
res, err := vmcli.Parse(ctx.Args())
|
res, err := vmcli.Parse(ctx.Args().Slice())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
fmt.Fprint(ctx.App.Writer, res)
|
fmt.Fprint(ctx.App.Writer, res)
|
||||||
return nil
|
return nil
|
||||||
|
@ -127,21 +133,21 @@ func handleOps(ctx *cli.Context) error {
|
||||||
if len(in) != 0 {
|
if len(in) != 0 {
|
||||||
b, err := os.ReadFile(in)
|
b, err := os.ReadFile(in)
|
||||||
if err != nil {
|
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)
|
s = string(b)
|
||||||
} else {
|
} else {
|
||||||
if !ctx.Args().Present() {
|
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)
|
b, err = base64.StdEncoding.DecodeString(s)
|
||||||
if err != nil || ctx.Bool("hex") {
|
if err != nil || ctx.Bool("hex") {
|
||||||
b, err = hex.DecodeString(s)
|
b, err = hex.DecodeString(s)
|
||||||
}
|
}
|
||||||
if err != nil {
|
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 := vm.New()
|
||||||
v.LoadScript(b)
|
v.LoadScript(b)
|
||||||
|
|
|
@ -8,30 +8,30 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
||||||
"github.com/nspcc-dev/neo-go/cli/query"
|
"github.com/nspcc-dev/neo-go/cli/query"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func txDump(ctx *cli.Context) error {
|
func txDump(ctx *cli.Context) error {
|
||||||
args := ctx.Args()
|
args := ctx.Args().Slice()
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return cli.NewExitError("missing input file", 1)
|
return cli.Exit("missing input file", 1)
|
||||||
} else if len(args) > 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])
|
c, err := paramcontext.Read(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, ok := c.Verifiable.(*transaction.Transaction)
|
tx, ok := c.Verifiable.(*transaction.Transaction)
|
||||||
if !ok {
|
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)
|
err = query.DumpApplicationLog(ctx, nil, tx, nil, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.String(options.RPCEndpointFlag) != "" {
|
if ctx.String(options.RPCEndpointFlag) != "" {
|
||||||
|
@ -41,15 +41,15 @@ func txDump(ctx *cli.Context) error {
|
||||||
var err error
|
var err error
|
||||||
cl, err := options.GetRPCClient(gctx, ctx)
|
cl, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
res, err := cl.InvokeScript(tx.Script, tx.Signers)
|
res, err := cl.InvokeScript(tx.Script, tx.Signers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
resS, err := json.MarshalIndent(res, "", " ")
|
resS, err := json.MarshalIndent(res, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
fmt.Fprintln(ctx.App.Writer, string(resS))
|
fmt.Fprintln(ctx.App.Writer, string(resS))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,25 +8,25 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/txctx"
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func sendTx(ctx *cli.Context) error {
|
func sendTx(ctx *cli.Context) error {
|
||||||
args := ctx.Args()
|
args := ctx.Args().Slice()
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return cli.NewExitError("missing input file", 1)
|
return cli.Exit("missing input file", 1)
|
||||||
} else if len(args) > 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])
|
pc, err := paramcontext.Read(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, err := pc.GetCompleteTransaction()
|
tx, err := pc.GetCompleteTransaction()
|
||||||
if err != nil {
|
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)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
@ -34,18 +34,18 @@ func sendTx(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
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)
|
res, err := c.SendRawTransaction(tx)
|
||||||
if err != nil {
|
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
|
var aer *state.AppExecResult
|
||||||
if ctx.Bool("await") {
|
if ctx.Bool("await") {
|
||||||
version, err := c.GetVersion()
|
version, err := c.GetVersion()
|
||||||
aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err)
|
aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err)
|
||||||
if err != nil {
|
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)
|
txctx.DumpTransactionInfo(ctx.App.Writer, res, aer)
|
||||||
|
|
|
@ -44,7 +44,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
"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"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"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"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
)
|
)
|
||||||
|
@ -70,22 +70,22 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
historicFlag = cli.IntFlag{
|
historicFlag = &cli.IntFlag{
|
||||||
Name: historicFlagFullName,
|
Name: historicFlagFullName,
|
||||||
Usage: "Height for historic script invocation (for MPT-enabled blockchain configuration with KeepOnlyLatestState setting disabled). " +
|
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.",
|
"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,
|
Name: gasFlagFullName,
|
||||||
Usage: "GAS limit for this execution (integer number, satoshi).",
|
Usage: "GAS limit for this execution (integer number, satoshi).",
|
||||||
}
|
}
|
||||||
hashFlag = cli.StringFlag{
|
hashFlag = &flags.AddressFlag{
|
||||||
Name: hashFlagFullName,
|
Name: hashFlagFullName,
|
||||||
Usage: "Smart-contract hash in LE form or address",
|
Usage: "Smart-contract hash in LE form or address",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var commands = []cli.Command{
|
var commands = []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "exit",
|
Name: "exit",
|
||||||
Usage: "Exit the VM prompt",
|
Usage: "Exit the VM prompt",
|
||||||
|
@ -339,8 +339,9 @@ Example:
|
||||||
Usage: "Dump state of the chain that is used for VM CLI invocations (use -v for verbose node configuration)",
|
Usage: "Dump state of the chain that is used for VM CLI invocations (use -v for verbose node configuration)",
|
||||||
UsageText: `env [-v]`,
|
UsageText: `env [-v]`,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: verboseFlagFullName + ",v",
|
Name: verboseFlagFullName,
|
||||||
|
Aliases: []string{"v"},
|
||||||
Usage: "Print the whole blockchain node configuration.",
|
Usage: "Print the whole blockchain node configuration.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -353,14 +354,16 @@ Example:
|
||||||
{
|
{
|
||||||
Name: "storage",
|
Name: "storage",
|
||||||
Usage: "Dump storage of the contract with the specified hash, address or ID as is at the current stage of script invocation",
|
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{
|
Flags: []cli.Flag{
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: backwardsFlagFullName + ",b",
|
Name: backwardsFlagFullName,
|
||||||
|
Aliases: []string{"b"},
|
||||||
Usage: "Backwards traversal direction",
|
Usage: "Backwards traversal direction",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: diffFlagFullName + ",d",
|
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.",
|
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.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -400,7 +403,7 @@ func init() {
|
||||||
if !c.Hidden {
|
if !c.Hidden {
|
||||||
var flagsItems []readline.PrefixCompleterInterface
|
var flagsItems []readline.PrefixCompleterInterface
|
||||||
for _, f := range c.Flags {
|
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]))
|
flagsItems = append(flagsItems, readline.PcItem("--"+names[0]))
|
||||||
}
|
}
|
||||||
pcItems = append(pcItems, readline.PcItem(c.Name, flagsItems...))
|
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)
|
log, _, logCloser, err := options.HandleLoggingParams(false, cfg.ApplicationConfiguration)
|
||||||
if err != nil {
|
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 {
|
filter := zap.WrapCore(func(z zapcore.Core) zapcore.Core {
|
||||||
return options.NewFilteringCore(z, func(entry zapcore.Entry) bool {
|
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)
|
chain, err := core.NewBlockchain(store, cfg.Blockchain(), fLog)
|
||||||
if err != nil {
|
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.
|
// Do not run chain, we need only state-related functionality from it.
|
||||||
ic, err := chain.GetTestVM(trigger.Application, nil, nil)
|
ic, err := chain.GetTestVM(trigger.Application, nil, nil)
|
||||||
if err != 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{
|
vmcli := CLI{
|
||||||
|
@ -610,7 +613,7 @@ func handleJump(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getInstructionParameter(c *cli.Context) (int, error) {
|
func getInstructionParameter(c *cli.Context) (int, error) {
|
||||||
args := c.Args()
|
args := c.Args().Slice()
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
return 0, fmt.Errorf("%w: <ip>", ErrMissingParameter)
|
return 0, fmt.Errorf("%w: <ip>", ErrMissingParameter)
|
||||||
}
|
}
|
||||||
|
@ -682,15 +685,12 @@ func getHashFlag(c *cli.Context) (util.Uint160, error) {
|
||||||
if !c.IsSet(hashFlagFullName) {
|
if !c.IsSet(hashFlagFullName) {
|
||||||
return util.Uint160{}, nil
|
return util.Uint160{}, nil
|
||||||
}
|
}
|
||||||
h, err := flags.ParseAddress(c.String(hashFlagFullName))
|
h := c.Generic(hashFlagFullName).(*flags.Address)
|
||||||
if err != nil {
|
return h.Uint160(), nil
|
||||||
return util.Uint160{}, fmt.Errorf("failed to parse contract hash: %w", err)
|
|
||||||
}
|
|
||||||
return h, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleLoadNEF(c *cli.Context) error {
|
func handleLoadNEF(c *cli.Context) error {
|
||||||
args := c.Args()
|
args := c.Args().Slice()
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return fmt.Errorf("%w: <nef> is required", ErrMissingParameter)
|
return fmt.Errorf("%w: <nef> is required", ErrMissingParameter)
|
||||||
}
|
}
|
||||||
|
@ -734,7 +734,7 @@ func handleLoadNEF(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
var signers []transaction.Signer
|
var signers []transaction.Signer
|
||||||
if signersStartOffset != 0 && len(args) > signersStartOffset {
|
if signersStartOffset != 0 && len(args) > signersStartOffset {
|
||||||
signers, err = cmdargs.ParseSigners(c.Args()[signersStartOffset:])
|
signers, err = cmdargs.ParseSigners(args[signersStartOffset:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: failed to parse signers: %w", ErrInvalidParameter, err)
|
return fmt.Errorf("%w: failed to parse signers: %w", ErrInvalidParameter, err)
|
||||||
}
|
}
|
||||||
|
@ -761,7 +761,7 @@ func handleLoadNEF(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleLoadBase64(c *cli.Context) error {
|
func handleLoadBase64(c *cli.Context) error {
|
||||||
args := c.Args()
|
args := c.Args().Slice()
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return fmt.Errorf("%w: <string>", ErrMissingParameter)
|
return fmt.Errorf("%w: <string>", ErrMissingParameter)
|
||||||
}
|
}
|
||||||
|
@ -801,7 +801,7 @@ func createFakeTransaction(script []byte, signers []transaction.Signer) *transac
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleLoadHex(c *cli.Context) error {
|
func handleLoadHex(c *cli.Context) error {
|
||||||
args := c.Args()
|
args := c.Args().Slice()
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return fmt.Errorf("%w: <string>", ErrMissingParameter)
|
return fmt.Errorf("%w: <string>", ErrMissingParameter)
|
||||||
}
|
}
|
||||||
|
@ -833,7 +833,7 @@ func handleLoadHex(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleLoadGo(c *cli.Context) error {
|
func handleLoadGo(c *cli.Context) error {
|
||||||
args := c.Args()
|
args := c.Args().Slice()
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return fmt.Errorf("%w: <file>", ErrMissingParameter)
|
return fmt.Errorf("%w: <file>", ErrMissingParameter)
|
||||||
}
|
}
|
||||||
|
@ -885,7 +885,7 @@ func handleLoadGo(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleLoadTx(c *cli.Context) error {
|
func handleLoadTx(c *cli.Context) error {
|
||||||
args := c.Args()
|
args := c.Args().Slice()
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return fmt.Errorf("%w: <file-or-hash>", ErrMissingParameter)
|
return fmt.Errorf("%w: <file-or-hash>", ErrMissingParameter)
|
||||||
}
|
}
|
||||||
|
@ -933,7 +933,7 @@ func handleLoadDeployed(c *cli.Context) error {
|
||||||
if !c.Args().Present() {
|
if !c.Args().Present() {
|
||||||
return errors.New("contract hash, address or ID is mandatory argument")
|
return errors.New("contract hash, address or ID is mandatory argument")
|
||||||
}
|
}
|
||||||
args := c.Args()
|
args := c.Args().Slice()
|
||||||
hashOrID := args[0]
|
hashOrID := args[0]
|
||||||
ic := getInteropContextFromContext(c.App)
|
ic := getInteropContextFromContext(c.App)
|
||||||
h, err := flags.ParseAddress(hashOrID)
|
h, err := flags.ParseAddress(hashOrID)
|
||||||
|
@ -1062,7 +1062,7 @@ func getManifestFromFile(name string) (*manifest.Manifest, error) {
|
||||||
func handleRun(c *cli.Context) error {
|
func handleRun(c *cli.Context) error {
|
||||||
v := getVMFromContext(c.App)
|
v := getVMFromContext(c.App)
|
||||||
cs := getContractStateFromContext(c.App)
|
cs := getContractStateFromContext(c.App)
|
||||||
args := c.Args()
|
args := c.Args().Slice()
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
var (
|
var (
|
||||||
params []stackitem.Item
|
params []stackitem.Item
|
||||||
|
@ -1181,7 +1181,7 @@ func handleStep(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
v := getVMFromContext(c.App)
|
v := getVMFromContext(c.App)
|
||||||
args := c.Args()
|
args := c.Args().Slice()
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
n, err = strconv.Atoi(args[0])
|
n, err = strconv.Atoi(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1422,7 +1422,7 @@ func (c *CLI) Run() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleParse(c *cli.Context) error {
|
func handleParse(c *cli.Context) error {
|
||||||
res, err := Parse(c.Args())
|
res, err := Parse(c.Args().Slice())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1188,7 +1188,7 @@ func TestDumpStorage(t *testing.T) {
|
||||||
"storage "+address.Uint160ToString(h),
|
"storage "+address.Uint160ToString(h),
|
||||||
"storage 1",
|
"storage 1",
|
||||||
"storage 1 "+hex.EncodeToString(expected[0].Key),
|
"storage 1 "+hex.EncodeToString(expected[0].Key),
|
||||||
"storage 1 --backwards",
|
"storage --backwards 1",
|
||||||
"exit",
|
"exit",
|
||||||
)
|
)
|
||||||
e.checkStorage(t, expected...)
|
e.checkStorage(t, expected...)
|
||||||
|
@ -1214,11 +1214,11 @@ func TestDumpStorageDiff(t *testing.T) {
|
||||||
diff := storage.KeyValue{Key: []byte{3}, Value: []byte{3}}
|
diff := storage.KeyValue{Key: []byte{3}, Value: []byte{3}}
|
||||||
e.runProg(t,
|
e.runProg(t,
|
||||||
"storage 1",
|
"storage 1",
|
||||||
"storage 1 --diff",
|
"storage --diff 1",
|
||||||
"loadhex "+hex.EncodeToString(script.Bytes()),
|
"loadhex "+hex.EncodeToString(script.Bytes()),
|
||||||
"run",
|
"run",
|
||||||
"storage 1",
|
"storage 1",
|
||||||
"storage 1 --diff",
|
"storage --diff 1",
|
||||||
"exit",
|
"exit",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
12
cli/vm/vm.go
12
cli/vm/vm.go
|
@ -8,16 +8,16 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
|
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCommands returns 'vm' command.
|
// NewCommands returns 'vm' command.
|
||||||
func NewCommands() []cli.Command {
|
func NewCommands() []*cli.Command {
|
||||||
cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
|
cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
|
||||||
cfgFlags = append(cfgFlags, options.Network...)
|
cfgFlags = append(cfgFlags, options.Network...)
|
||||||
return []cli.Command{{
|
return []*cli.Command{{
|
||||||
Name: "vm",
|
Name: "vm",
|
||||||
Usage: "start the virtual machine",
|
Usage: "Start the virtual machine",
|
||||||
Action: startVMPrompt,
|
Action: startVMPrompt,
|
||||||
Flags: cfgFlags,
|
Flags: cfgFlags,
|
||||||
}}
|
}}
|
||||||
|
@ -30,7 +30,7 @@ func startVMPrompt(ctx *cli.Context) error {
|
||||||
|
|
||||||
cfg, err := options.GetConfigFromContext(ctx)
|
cfg, err := options.GetConfigFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if ctx.NumFlags() == 0 {
|
if ctx.NumFlags() == 0 {
|
||||||
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.InMemoryDB
|
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)
|
p, err := NewWithConfig(true, os.Exit, &readline.Config{}, cfg)
|
||||||
if err != nil {
|
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()
|
return p.Run()
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ func TestRegisterCandidate(t *testing.T) {
|
||||||
e.CheckEOF(t)
|
e.CheckEOF(t)
|
||||||
|
|
||||||
// missing address
|
// missing address
|
||||||
e.RunWithError(t, "neo-go", "wallet", "candidate", "register",
|
e.RunWithErrorCheck(t, `Required flag "address" not set`, "neo-go", "wallet", "candidate", "register",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
"--wallet", testcli.ValidatorWallet)
|
"--wallet", testcli.ValidatorWallet)
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ func TestRegisterCandidate(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// missing address
|
// missing address
|
||||||
e.RunWithError(t, "neo-go", "wallet", "candidate", "unregister",
|
e.RunWithErrorCheck(t, `Required flag "address" not set`, "neo-go", "wallet", "candidate", "unregister",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
"--wallet", testcli.ValidatorWallet)
|
"--wallet", testcli.ValidatorWallet)
|
||||||
// additional argument
|
// additional argument
|
||||||
|
@ -153,7 +153,7 @@ func TestRegisterCandidate(t *testing.T) {
|
||||||
require.Equal(t, 0, len(vs))
|
require.Equal(t, 0, len(vs))
|
||||||
|
|
||||||
// query voter: missing address
|
// query voter: missing address
|
||||||
e.RunWithError(t, "neo-go", "query", "voter")
|
e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
|
||||||
// Excessive parameters.
|
// Excessive parameters.
|
||||||
e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress, validatorAddress)
|
e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress, validatorAddress)
|
||||||
e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something")
|
e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something")
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func signStoredTransaction(ctx *cli.Context) error {
|
func signStoredTransaction(ctx *cli.Context) error {
|
||||||
|
@ -28,52 +28,52 @@ func signStoredTransaction(ctx *cli.Context) error {
|
||||||
|
|
||||||
pc, err := paramcontext.Read(ctx.String("in"))
|
pc, err := paramcontext.Read(ctx.String("in"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !addrFlag.IsSet {
|
if !addrFlag.IsSet {
|
||||||
return cli.NewExitError("address was not provided", 1)
|
return cli.Exit("address was not provided", 1)
|
||||||
}
|
}
|
||||||
acc, _, err := options.GetAccFromContext(ctx)
|
acc, _, err := options.GetAccFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, ok := pc.Verifiable.(*transaction.Transaction)
|
tx, ok := pc.Verifiable.(*transaction.Transaction)
|
||||||
if !ok {
|
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()) {
|
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() {
|
if acc.CanSign() {
|
||||||
sign := acc.SignHashable(pc.Network, pc.Verifiable)
|
sign := acc.SignHashable(pc.Network, pc.Verifiable)
|
||||||
if err := pc.AddSignature(acc.ScriptHash(), acc.Contract, acc.PublicKey(), sign); err != nil {
|
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 == "" {
|
} 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.
|
// Not saving and not sending, print.
|
||||||
if out == "" && rpcNode == "" {
|
if out == "" && rpcNode == "" {
|
||||||
txt, err := json.MarshalIndent(pc, " ", " ")
|
txt, err := json.MarshalIndent(pc, " ", " ")
|
||||||
if err != nil {
|
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))
|
fmt.Fprintln(ctx.App.Writer, string(txt))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if out != "" {
|
if out != "" {
|
||||||
if err := paramcontext.Save(pc, out); err != nil {
|
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 != "" {
|
if rpcNode != "" {
|
||||||
tx, err = pc.GetCompleteTransaction()
|
tx, err = pc.GetCompleteTransaction()
|
||||||
if err != nil {
|
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)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
@ -82,17 +82,17 @@ func signStoredTransaction(ctx *cli.Context) error {
|
||||||
var err error // `GetRPCClient` returns specialized type.
|
var err error // `GetRPCClient` returns specialized type.
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
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)
|
res, err := c.SendRawTransaction(tx)
|
||||||
if err != nil {
|
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") {
|
if ctx.Bool("await") {
|
||||||
version, err := c.GetVersion()
|
version, err := c.GetVersion()
|
||||||
aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err)
|
aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err)
|
||||||
if err != nil {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,10 +79,10 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
"--out", txPath)
|
"--out", txPath)
|
||||||
|
|
||||||
// missing wallet
|
// missing wallet
|
||||||
e.RunWithError(t, "neo-go", "wallet", "sign")
|
e.RunWithErrorCheck(t, `Required flag "in" not set`, "neo-go", "wallet", "sign")
|
||||||
|
|
||||||
// missing in
|
// missing in
|
||||||
e.RunWithError(t, "neo-go", "wallet", "sign",
|
e.RunWithErrorCheck(t, `Required flag "in" not set`, "neo-go", "wallet", "sign",
|
||||||
"--wallet", wallet2Path)
|
"--wallet", wallet2Path)
|
||||||
|
|
||||||
// missing address
|
// missing address
|
||||||
|
|
|
@ -19,20 +19,22 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"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)
|
maxIters := strconv.Itoa(config.DefaultMaxIteratorResultItems)
|
||||||
tokenAddressFlag := flags.AddressFlag{
|
tokenAddressFlag := &flags.AddressFlag{
|
||||||
Name: "token",
|
Name: "token",
|
||||||
Usage: "Token contract address or hash in LE",
|
Usage: "Token contract address or hash in LE",
|
||||||
|
Required: true,
|
||||||
}
|
}
|
||||||
ownerAddressFlag := flags.AddressFlag{
|
ownerAddressFlag := &flags.AddressFlag{
|
||||||
Name: "address",
|
Name: "address",
|
||||||
Usage: "NFT owner address or hash in LE",
|
Usage: "NFT owner address or hash in LE",
|
||||||
|
Required: true,
|
||||||
}
|
}
|
||||||
tokenID := cli.StringFlag{
|
tokenID := &cli.StringFlag{
|
||||||
Name: "id",
|
Name: "id",
|
||||||
Usage: "Hex-encoded token ID",
|
Usage: "Hex-encoded token ID",
|
||||||
}
|
}
|
||||||
|
@ -45,10 +47,10 @@ func newNEP11Commands() []cli.Command {
|
||||||
copy(transferFlags, baseTransferFlags)
|
copy(transferFlags, baseTransferFlags)
|
||||||
transferFlags = append(transferFlags, tokenID)
|
transferFlags = append(transferFlags, tokenID)
|
||||||
transferFlags = append(transferFlags, options.RPC...)
|
transferFlags = append(transferFlags, options.RPC...)
|
||||||
return []cli.Command{
|
return []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "balance",
|
Name: "balance",
|
||||||
Usage: "get address balance",
|
Usage: "Get address balance",
|
||||||
UsageText: "balance -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] [--address <address>] [--token <hash-or-name>] [--id <token-id>]",
|
UsageText: "balance -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] [--address <address>] [--token <hash-or-name>] [--id <token-id>]",
|
||||||
Description: `Prints NEP-11 balances for address and assets/IDs specified. By default (no
|
Description: `Prints NEP-11 balances for address and assets/IDs specified. By default (no
|
||||||
address or token parameter) all tokens (NFT contracts) for all accounts in
|
address or token parameter) all tokens (NFT contracts) for all accounts in
|
||||||
|
@ -70,14 +72,14 @@ func newNEP11Commands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "import",
|
Name: "import",
|
||||||
Usage: "import NEP-11 token to a wallet",
|
Usage: "Import NEP-11 token to a wallet",
|
||||||
UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --token <hash>",
|
UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] --token <hash>",
|
||||||
Action: importNEP11Token,
|
Action: importNEP11Token,
|
||||||
Flags: importFlags,
|
Flags: importFlags,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "info",
|
Name: "info",
|
||||||
Usage: "print imported NEP-11 token info",
|
Usage: "Print imported NEP-11 token info",
|
||||||
UsageText: "print -w wallet [--wallet-config path] [--token <hash-or-name>]",
|
UsageText: "print -w wallet [--wallet-config path] [--token <hash-or-name>]",
|
||||||
Action: printNEP11Info,
|
Action: printNEP11Info,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -88,7 +90,7 @@ func newNEP11Commands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "remove",
|
Name: "remove",
|
||||||
Usage: "remove NEP-11 token from the wallet",
|
Usage: "Remove NEP-11 token from the wallet",
|
||||||
UsageText: "remove -w wallet [--wallet-config path] --token <hash-or-name>",
|
UsageText: "remove -w wallet [--wallet-config path] --token <hash-or-name>",
|
||||||
Action: removeNEP11Token,
|
Action: removeNEP11Token,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -100,8 +102,8 @@ func newNEP11Commands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "transfer",
|
Name: "transfer",
|
||||||
Usage: "transfer NEP-11 tokens",
|
Usage: "Transfer NEP-11 tokens",
|
||||||
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [--await] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
|
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [--await] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
|
||||||
Action: transferNEP11,
|
Action: transferNEP11,
|
||||||
Flags: transferFlags,
|
Flags: transferFlags,
|
||||||
Description: `Transfers specified NEP-11 token with optional cosigners list attached to
|
Description: `Transfers specified NEP-11 token with optional cosigners list attached to
|
||||||
|
@ -116,7 +118,7 @@ func newNEP11Commands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "properties",
|
Name: "properties",
|
||||||
Usage: "print properties of NEP-11 token",
|
Usage: "Print properties of NEP-11 token",
|
||||||
UsageText: "properties --rpc-endpoint <node> [--timeout <time>] --token <hash> --id <token-id> [--historic <block/hash>]",
|
UsageText: "properties --rpc-endpoint <node> [--timeout <time>] --token <hash> --id <token-id> [--historic <block/hash>]",
|
||||||
Action: printNEP11Properties,
|
Action: printNEP11Properties,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
|
@ -127,7 +129,7 @@ func newNEP11Commands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "ownerOf",
|
Name: "ownerOf",
|
||||||
Usage: "print owner of non-divisible NEP-11 token with the specified ID",
|
Usage: "Print owner of non-divisible NEP-11 token with the specified ID",
|
||||||
UsageText: "ownerOf --rpc-endpoint <node> [--timeout <time>] --token <hash> --id <token-id> [--historic <block/hash>]",
|
UsageText: "ownerOf --rpc-endpoint <node> [--timeout <time>] --token <hash> --id <token-id> [--historic <block/hash>]",
|
||||||
Action: printNEP11NDOwner,
|
Action: printNEP11NDOwner,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
|
@ -138,7 +140,7 @@ func newNEP11Commands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "ownerOfD",
|
Name: "ownerOfD",
|
||||||
Usage: "print set of owners of divisible NEP-11 token with the specified ID (" + maxIters + " will be printed at max)",
|
Usage: "Print set of owners of divisible NEP-11 token with the specified ID (" + maxIters + " will be printed at max)",
|
||||||
UsageText: "ownerOfD --rpc-endpoint <node> [--timeout <time>] --token <hash> --id <token-id> [--historic <block/hash>]",
|
UsageText: "ownerOfD --rpc-endpoint <node> [--timeout <time>] --token <hash> --id <token-id> [--historic <block/hash>]",
|
||||||
Action: printNEP11DOwner,
|
Action: printNEP11DOwner,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
|
@ -149,7 +151,7 @@ func newNEP11Commands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "tokensOf",
|
Name: "tokensOf",
|
||||||
Usage: "print list of tokens IDs for the specified NFT owner (" + maxIters + " will be printed at max)",
|
Usage: "Print list of tokens IDs for the specified NFT owner (" + maxIters + " will be printed at max)",
|
||||||
UsageText: "tokensOf --rpc-endpoint <node> [--timeout <time>] --token <hash> --address <addr> [--historic <block/hash>]",
|
UsageText: "tokensOf --rpc-endpoint <node> [--timeout <time>] --token <hash> --address <addr> [--historic <block/hash>]",
|
||||||
Action: printNEP11TokensOf,
|
Action: printNEP11TokensOf,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
|
@ -160,7 +162,7 @@ func newNEP11Commands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "tokens",
|
Name: "tokens",
|
||||||
Usage: "print list of tokens IDs minted by the specified NFT (optional method; " + maxIters + " will be printed at max)",
|
Usage: "Print list of tokens IDs minted by the specified NFT (optional method; " + maxIters + " will be printed at max)",
|
||||||
UsageText: "tokens --rpc-endpoint <node> [--timeout <time>] --token <hash> [--historic <block/hash>]",
|
UsageText: "tokens --rpc-endpoint <node> [--timeout <time>] --token <hash> [--historic <block/hash>]",
|
||||||
Action: printNEP11Tokens,
|
Action: printNEP11Tokens,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
|
@ -246,17 +248,13 @@ func printNEP11Owner(ctx *cli.Context, divisible bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tokenHash := ctx.Generic("token").(*flags.Address)
|
tokenHash := ctx.Generic("token").(*flags.Address)
|
||||||
if !tokenHash.IsSet {
|
|
||||||
return cli.NewExitError("token contract hash was not set", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenID := ctx.String("id")
|
tokenID := ctx.String("id")
|
||||||
if tokenID == "" {
|
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)
|
tokenIDBytes, err := hex.DecodeString(tokenID)
|
||||||
if err != nil {
|
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)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
@ -271,7 +269,7 @@ func printNEP11Owner(ctx *cli.Context, divisible bool) error {
|
||||||
n11 := nep11.NewDivisibleReader(inv, tokenHash.Uint160())
|
n11 := nep11.NewDivisibleReader(inv, tokenHash.Uint160())
|
||||||
result, err := n11.OwnerOfExpanded(tokenIDBytes, config.DefaultMaxIteratorResultItems)
|
result, err := n11.OwnerOfExpanded(tokenIDBytes, config.DefaultMaxIteratorResultItems)
|
||||||
if err != nil {
|
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 {
|
for _, h := range result {
|
||||||
fmt.Fprintln(ctx.App.Writer, address.Uint160ToString(h))
|
fmt.Fprintln(ctx.App.Writer, address.Uint160ToString(h))
|
||||||
|
@ -280,7 +278,7 @@ func printNEP11Owner(ctx *cli.Context, divisible bool) error {
|
||||||
n11 := nep11.NewNonDivisibleReader(inv, tokenHash.Uint160())
|
n11 := nep11.NewNonDivisibleReader(inv, tokenHash.Uint160())
|
||||||
result, err := n11.OwnerOf(tokenIDBytes)
|
result, err := n11.OwnerOf(tokenIDBytes)
|
||||||
if err != nil {
|
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))
|
fmt.Fprintln(ctx.App.Writer, address.Uint160ToString(result))
|
||||||
}
|
}
|
||||||
|
@ -291,15 +289,7 @@ func printNEP11Owner(ctx *cli.Context, divisible bool) error {
|
||||||
func printNEP11TokensOf(ctx *cli.Context) error {
|
func printNEP11TokensOf(ctx *cli.Context) error {
|
||||||
var err error
|
var err error
|
||||||
tokenHash := ctx.Generic("token").(*flags.Address)
|
tokenHash := ctx.Generic("token").(*flags.Address)
|
||||||
if !tokenHash.IsSet {
|
|
||||||
return cli.NewExitError("token contract hash was not set", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
acc := ctx.Generic("address").(*flags.Address)
|
acc := ctx.Generic("address").(*flags.Address)
|
||||||
if !acc.IsSet {
|
|
||||||
return cli.NewExitError("owner address flag was not set", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
@ -311,7 +301,7 @@ func printNEP11TokensOf(ctx *cli.Context) error {
|
||||||
n11 := nep11.NewBaseReader(inv, tokenHash.Uint160())
|
n11 := nep11.NewBaseReader(inv, tokenHash.Uint160())
|
||||||
result, err := n11.TokensOfExpanded(acc.Uint160(), config.DefaultMaxIteratorResultItems)
|
result, err := n11.TokensOfExpanded(acc.Uint160(), config.DefaultMaxIteratorResultItems)
|
||||||
if err != nil {
|
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 {
|
for i := range result {
|
||||||
|
@ -326,10 +316,6 @@ func printNEP11Tokens(ctx *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tokenHash := ctx.Generic("token").(*flags.Address)
|
tokenHash := ctx.Generic("token").(*flags.Address)
|
||||||
if !tokenHash.IsSet {
|
|
||||||
return cli.NewExitError("token contract hash was not set", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
@ -341,7 +327,7 @@ func printNEP11Tokens(ctx *cli.Context) error {
|
||||||
n11 := nep11.NewBaseReader(inv, tokenHash.Uint160())
|
n11 := nep11.NewBaseReader(inv, tokenHash.Uint160())
|
||||||
result, err := n11.TokensExpanded(config.DefaultMaxIteratorResultItems)
|
result, err := n11.TokensExpanded(config.DefaultMaxIteratorResultItems)
|
||||||
if err != nil {
|
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 {
|
for i := range result {
|
||||||
|
@ -356,17 +342,13 @@ func printNEP11Properties(ctx *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tokenHash := ctx.Generic("token").(*flags.Address)
|
tokenHash := ctx.Generic("token").(*flags.Address)
|
||||||
if !tokenHash.IsSet {
|
|
||||||
return cli.NewExitError("token contract hash was not set", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenID := ctx.String("id")
|
tokenID := ctx.String("id")
|
||||||
if tokenID == "" {
|
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)
|
tokenIDBytes, err := hex.DecodeString(tokenID)
|
||||||
if err != nil {
|
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)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
@ -380,12 +362,12 @@ func printNEP11Properties(ctx *cli.Context) error {
|
||||||
n11 := nep11.NewBaseReader(inv, tokenHash.Uint160())
|
n11 := nep11.NewBaseReader(inv, tokenHash.Uint160())
|
||||||
result, err := n11.Properties(tokenIDBytes)
|
result, err := n11.Properties(tokenIDBytes)
|
||||||
if err != nil {
|
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)
|
bytes, err := stackitem.ToJSON(result)
|
||||||
if err != nil {
|
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))
|
fmt.Fprintln(ctx.App.Writer, string(bytes))
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -27,7 +27,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"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.
|
// transferTarget represents target address, token amount and data for transfer.
|
||||||
|
@ -39,7 +39,7 @@ type transferTarget struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tokenFlag = cli.StringFlag{
|
tokenFlag = &cli.StringFlag{
|
||||||
Name: "token",
|
Name: "token",
|
||||||
Usage: "Token to use (hash or name (for NEO/GAS or imported tokens))",
|
Usage: "Token to use (hash or name (for NEO/GAS or imported tokens))",
|
||||||
}
|
}
|
||||||
|
@ -47,17 +47,19 @@ var (
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
tokenFlag,
|
tokenFlag,
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address",
|
||||||
|
Aliases: []string{"a"},
|
||||||
Usage: "Address to use",
|
Usage: "Address to use",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
importFlags = append([]cli.Flag{
|
importFlags = append([]cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "token",
|
Name: "token",
|
||||||
Usage: "Token contract address or hash in LE",
|
Usage: "Token contract address or hash in LE",
|
||||||
|
Required: true,
|
||||||
},
|
},
|
||||||
}, options.RPC...)
|
}, options.RPC...)
|
||||||
baseTransferFlags = []cli.Flag{
|
baseTransferFlags = []cli.Flag{
|
||||||
|
@ -71,7 +73,7 @@ var (
|
||||||
txctx.SysGasFlag,
|
txctx.SysGasFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
txctx.AwaitFlag,
|
txctx.AwaitFlag,
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "amount",
|
Name: "amount",
|
||||||
Usage: "Amount of asset to send",
|
Usage: "Amount of asset to send",
|
||||||
},
|
},
|
||||||
|
@ -88,17 +90,17 @@ var (
|
||||||
}, options.RPC...)
|
}, options.RPC...)
|
||||||
)
|
)
|
||||||
|
|
||||||
func newNEP17Commands() []cli.Command {
|
func newNEP17Commands() []*cli.Command {
|
||||||
balanceFlags := make([]cli.Flag, len(baseBalanceFlags))
|
balanceFlags := make([]cli.Flag, len(baseBalanceFlags))
|
||||||
copy(balanceFlags, baseBalanceFlags)
|
copy(balanceFlags, baseBalanceFlags)
|
||||||
balanceFlags = append(balanceFlags, options.RPC...)
|
balanceFlags = append(balanceFlags, options.RPC...)
|
||||||
transferFlags := make([]cli.Flag, len(baseTransferFlags))
|
transferFlags := make([]cli.Flag, len(baseTransferFlags))
|
||||||
copy(transferFlags, baseTransferFlags)
|
copy(transferFlags, baseTransferFlags)
|
||||||
transferFlags = append(transferFlags, options.RPC...)
|
transferFlags = append(transferFlags, options.RPC...)
|
||||||
return []cli.Command{
|
return []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "balance",
|
Name: "balance",
|
||||||
Usage: "get address balance",
|
Usage: "Get address balance",
|
||||||
UsageText: "balance -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] [--address <address>] [--token <hash-or-name>]",
|
UsageText: "balance -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] [--address <address>] [--token <hash-or-name>]",
|
||||||
Description: `Prints NEP-17 balances for address and tokens specified. By default (no
|
Description: `Prints NEP-17 balances for address and tokens specified. By default (no
|
||||||
address or token parameter) all tokens for all accounts in the specified wallet
|
address or token parameter) all tokens for all accounts in the specified wallet
|
||||||
|
@ -118,14 +120,14 @@ func newNEP17Commands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "import",
|
Name: "import",
|
||||||
Usage: "import NEP-17 token to a wallet",
|
Usage: "Import NEP-17 token to a wallet",
|
||||||
UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --token <hash>",
|
UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] --token <hash>",
|
||||||
Action: importNEP17Token,
|
Action: importNEP17Token,
|
||||||
Flags: importFlags,
|
Flags: importFlags,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "info",
|
Name: "info",
|
||||||
Usage: "print imported NEP-17 token info",
|
Usage: "Print imported NEP-17 token info",
|
||||||
UsageText: "print -w wallet [--wallet-config path] [--token <hash-or-name>]",
|
UsageText: "print -w wallet [--wallet-config path] [--token <hash-or-name>]",
|
||||||
Action: printNEP17Info,
|
Action: printNEP17Info,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -136,7 +138,7 @@ func newNEP17Commands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "remove",
|
Name: "remove",
|
||||||
Usage: "remove NEP-17 token from the wallet",
|
Usage: "Remove NEP-17 token from the wallet",
|
||||||
UsageText: "remove -w wallet [--wallet-config path] --token <hash-or-name>",
|
UsageText: "remove -w wallet [--wallet-config path] --token <hash-or-name>",
|
||||||
Action: removeNEP17Token,
|
Action: removeNEP17Token,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -148,8 +150,8 @@ func newNEP17Commands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "transfer",
|
Name: "transfer",
|
||||||
Usage: "transfer NEP-17 tokens",
|
Usage: "Transfer NEP-17 tokens",
|
||||||
UsageText: "transfer -w wallet [--wallet-config path] [--await] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
|
UsageText: "transfer -w wallet [--wallet-config path] [--await] --rpc-endpoint <node> [--timeout <time>] --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
|
||||||
Action: transferNEP17,
|
Action: transferNEP17,
|
||||||
Flags: transferFlags,
|
Flags: transferFlags,
|
||||||
Description: `Transfers specified NEP-17 token amount with optional 'data' parameter and cosigners
|
Description: `Transfers specified NEP-17 token amount with optional 'data' parameter and cosigners
|
||||||
|
@ -163,7 +165,7 @@ func newNEP17Commands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "multitransfer",
|
Name: "multitransfer",
|
||||||
Usage: "transfer NEP-17 tokens to multiple recipients",
|
Usage: "Transfer NEP-17 tokens to multiple recipients",
|
||||||
UsageText: `multitransfer -w wallet [--wallet-config path] [--await] --rpc-endpoint <node> --timeout <time> --from <addr>` +
|
UsageText: `multitransfer -w wallet [--wallet-config path] [--await] --rpc-endpoint <node> --timeout <time> --from <addr>` +
|
||||||
` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]] [-- <cosigner1:Scope> [<cosigner2> [...]]]`,
|
` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]] [-- <cosigner1:Scope> [<cosigner2> [...]]]`,
|
||||||
Action: multiTransferNEP17,
|
Action: multiTransferNEP17,
|
||||||
|
@ -222,7 +224,7 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte
|
||||||
}
|
}
|
||||||
wall, _, err := readWallet(ctx)
|
wall, _, err := readWallet(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("bad wallet: %w", err), 1)
|
return cli.Exit(fmt.Errorf("bad wallet: %w", err), 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
|
@ -231,12 +233,12 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte
|
||||||
addrHash := addrFlag.Uint160()
|
addrHash := addrFlag.Uint160()
|
||||||
acc := wall.GetAccount(addrHash)
|
acc := wall.GetAccount(addrHash)
|
||||||
if acc == nil {
|
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)
|
accounts = append(accounts, acc)
|
||||||
} else {
|
} else {
|
||||||
if len(wall.Accounts) == 0 {
|
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
|
accounts = wall.Accounts
|
||||||
}
|
}
|
||||||
|
@ -246,7 +248,7 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
name := ctx.String("token")
|
name := ctx.String("token")
|
||||||
|
@ -274,7 +276,7 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte
|
||||||
// But if we have an exact hash, it must be correct.
|
// But if we have an exact hash, it must be correct.
|
||||||
token, err = getTokenWithStandard(c, h, standard)
|
token, err = getTokenWithStandard(c, h, standard)
|
||||||
if err != nil {
|
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 +286,7 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte
|
||||||
if len(tokenID) > 0 {
|
if len(tokenID) > 0 {
|
||||||
_, err = hex.DecodeString(tokenID)
|
_, err = hex.DecodeString(tokenID)
|
||||||
if err != nil {
|
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 +298,7 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte
|
||||||
|
|
||||||
err = accHandler(ctx, c, acc.ScriptHash(), name, token, tokenID)
|
err = accHandler(ctx, c, acc.ScriptHash(), name, token, tokenID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -388,20 +390,17 @@ func importNEPToken(ctx *cli.Context, standard string) error {
|
||||||
}
|
}
|
||||||
wall, _, err := openWallet(ctx, true)
|
wall, _, err := openWallet(ctx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
tokenHashFlag := ctx.Generic("token").(*flags.Address)
|
tokenHashFlag := ctx.Generic("token").(*flags.Address)
|
||||||
if !tokenHashFlag.IsSet {
|
|
||||||
return cli.NewExitError("token contract hash was not set", 1)
|
|
||||||
}
|
|
||||||
tokenHash := tokenHashFlag.Uint160()
|
tokenHash := tokenHashFlag.Uint160()
|
||||||
|
|
||||||
for _, t := range wall.Extra.Tokens {
|
for _, t := range wall.Extra.Tokens {
|
||||||
if t.Hash.Equals(tokenHash) && t.Standard == standard {
|
if t.Hash.Equals(tokenHash) && t.Standard == standard {
|
||||||
printTokenInfo(ctx, t)
|
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 +409,17 @@ func importNEPToken(ctx *cli.Context, standard string) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
tok, err := getTokenWithStandard(c, tokenHash, standard)
|
tok, err := getTokenWithStandard(c, tokenHash, standard)
|
||||||
if err != nil {
|
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)
|
wall.AddToken(tok)
|
||||||
if err := wall.Save(); err != nil {
|
if err := wall.Save(); err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
printTokenInfo(ctx, tok)
|
printTokenInfo(ctx, tok)
|
||||||
return nil
|
return nil
|
||||||
|
@ -457,14 +456,14 @@ func printNEPInfo(ctx *cli.Context, standard string) error {
|
||||||
}
|
}
|
||||||
wall, _, err := readWallet(ctx)
|
wall, _, err := readWallet(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
if name := ctx.String("token"); name != "" {
|
if name := ctx.String("token"); name != "" {
|
||||||
token, err := getMatchingToken(ctx, wall, name, standard)
|
token, err := getMatchingToken(ctx, wall, name, standard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
printTokenInfo(ctx, token)
|
printTokenInfo(ctx, token)
|
||||||
return nil
|
return nil
|
||||||
|
@ -493,13 +492,13 @@ func removeNEPToken(ctx *cli.Context, standard string) error {
|
||||||
}
|
}
|
||||||
wall, _, err := openWallet(ctx, true)
|
wall, _, err := openWallet(ctx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
token, err := getMatchingToken(ctx, wall, ctx.String("token"), standard)
|
token, err := getMatchingToken(ctx, wall, ctx.String("token"), standard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if !ctx.Bool("force") {
|
if !ctx.Bool("force") {
|
||||||
if ok := askForConsent(ctx.App.Writer); !ok {
|
if ok := askForConsent(ctx.App.Writer); !ok {
|
||||||
|
@ -507,9 +506,9 @@ func removeNEPToken(ctx *cli.Context, standard string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := wall.RemoveToken(token.Hash); err != nil {
|
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 {
|
} 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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -517,25 +516,25 @@ func removeNEPToken(ctx *cli.Context, standard string) error {
|
||||||
func multiTransferNEP17(ctx *cli.Context) error {
|
func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
wall, pass, err := readWallet(ctx)
|
wall, pass, err := readWallet(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
fromFlag := ctx.Generic("from").(*flags.Address)
|
fromFlag := ctx.Generic("from").(*flags.Address)
|
||||||
from, err := getDefaultAddress(fromFlag, wall)
|
from, err := getDefaultAddress(fromFlag, wall)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
acc, err := options.GetUnlockedAccount(wall, from, pass)
|
acc, err := options.GetUnlockedAccount(wall, from, pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if ctx.NArg() == 0 {
|
if ctx.NArg() == 0 {
|
||||||
return cli.NewExitError("empty recipients list", 1)
|
return cli.Exit("empty recipients list", 1)
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
recipients []transferTarget
|
recipients []transferTarget
|
||||||
|
@ -554,7 +553,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
|
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
|
||||||
if err != nil {
|
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)
|
c, act, exitErr := options.GetRPCWithActor(gctx, ctx, signersAccounts)
|
||||||
if exitErr != nil {
|
if exitErr != nil {
|
||||||
|
@ -566,7 +565,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
arg := ctx.Args().Get(i)
|
arg := ctx.Args().Get(i)
|
||||||
ss := strings.SplitN(arg, ":", 3)
|
ss := strings.SplitN(arg, ":", 3)
|
||||||
if len(ss) != 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]]
|
token, ok := cache[ss[0]]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -574,18 +573,18 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
token, err = getMatchingTokenRPC(ctx, c, from, ss[0], manifest.NEP17StandardName)
|
token, err = getMatchingTokenRPC(ctx, c, from, ss[0], manifest.NEP17StandardName)
|
||||||
if err != nil {
|
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
|
cache[ss[0]] = token
|
||||||
addr, err := address.StringToUint160(ss[1])
|
addr, err := address.StringToUint160(ss[1])
|
||||||
if err != nil {
|
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))
|
amount, err := fixedn.FromString(ss[2], int(token.Decimals))
|
||||||
if err != nil {
|
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{
|
recipients = append(recipients, transferTarget{
|
||||||
Token: token.Hash,
|
Token: token.Hash,
|
||||||
|
@ -597,7 +596,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
|
|
||||||
tx, err := makeMultiTransferNEP17(act, recipients)
|
tx, err := makeMultiTransferNEP17(act, recipients)
|
||||||
if err != nil {
|
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)
|
return txctx.SignAndSend(ctx, act, acc, tx)
|
||||||
}
|
}
|
||||||
|
@ -611,18 +610,18 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
|
|
||||||
wall, pass, err := readWallet(ctx)
|
wall, pass, err := readWallet(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
fromFlag := ctx.Generic("from").(*flags.Address)
|
fromFlag := ctx.Generic("from").(*flags.Address)
|
||||||
from, err := getDefaultAddress(fromFlag, wall)
|
from, err := getDefaultAddress(fromFlag, wall)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
acc, err := options.GetUnlockedAccount(wall, from, pass)
|
acc, err := options.GetUnlockedAccount(wall, from, pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
@ -638,7 +637,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
}
|
}
|
||||||
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
|
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
|
||||||
if err != nil {
|
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)
|
c, act, exitErr := options.GetRPCWithActor(gctx, ctx, signersAccounts)
|
||||||
|
@ -647,15 +646,12 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
toFlag := ctx.Generic("to").(*flags.Address)
|
toFlag := ctx.Generic("to").(*flags.Address)
|
||||||
if !toFlag.IsSet {
|
|
||||||
return cli.NewExitError(errors.New("missing receiver address (--to)"), 1)
|
|
||||||
}
|
|
||||||
to := toFlag.Uint160()
|
to := toFlag.Uint160()
|
||||||
token, err := getMatchingToken(ctx, wall, ctx.String("token"), standard)
|
token, err := getMatchingToken(ctx, wall, ctx.String("token"), standard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
token, err = getMatchingTokenRPC(ctx, c, from, ctx.String("token"), standard)
|
token, err = getMatchingTokenRPC(ctx, c, from, ctx.String("token"), standard)
|
||||||
if err != nil {
|
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 +659,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
amount, err := fixedn.FromString(amountArg, int(token.Decimals))
|
amount, err := fixedn.FromString(amountArg, int(token.Decimals))
|
||||||
// It's OK for NEP-11 transfer to not have amount set.
|
// It's OK for NEP-11 transfer to not have amount set.
|
||||||
if err != nil && (standard == manifest.NEP17StandardName || amountArg != "") {
|
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 {
|
switch standard {
|
||||||
case manifest.NEP17StandardName:
|
case manifest.NEP17StandardName:
|
||||||
|
@ -672,11 +668,11 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
case manifest.NEP11StandardName:
|
case manifest.NEP11StandardName:
|
||||||
tokenID := ctx.String("id")
|
tokenID := ctx.String("id")
|
||||||
if tokenID == "" {
|
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)
|
tokenIDBytes, terr := hex.DecodeString(tokenID)
|
||||||
if terr != nil {
|
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 == "" {
|
if amountArg == "" {
|
||||||
n11 := nep11.NewNonDivisible(act, token.Hash)
|
n11 := nep11.NewNonDivisible(act, token.Hash)
|
||||||
|
@ -686,10 +682,10 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
tx, err = n11.TransferDUnsigned(act.Sender(), to, amount, tokenIDBytes, data)
|
tx, err = n11.TransferDUnsigned(act.Sender(), to, amount, tokenIDBytes, data)
|
||||||
}
|
}
|
||||||
default:
|
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 {
|
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)
|
return txctx.SignAndSend(ctx, act, acc, tx)
|
||||||
|
|
|
@ -12,15 +12,15 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newValidatorCommands() []cli.Command {
|
func newValidatorCommands() []*cli.Command {
|
||||||
return []cli.Command{
|
return []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "register",
|
Name: "register",
|
||||||
Usage: "register as a new candidate",
|
Usage: "Register as a new candidate",
|
||||||
UsageText: "register -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
|
UsageText: "register -w <path> -r <rpc> [-s timeout] -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
|
||||||
Action: handleRegister,
|
Action: handleRegister,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
|
@ -30,16 +30,18 @@ func newValidatorCommands() []cli.Command {
|
||||||
txctx.OutFlag,
|
txctx.OutFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
txctx.AwaitFlag,
|
txctx.AwaitFlag,
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address",
|
||||||
|
Aliases: []string{"a"},
|
||||||
|
Required: true,
|
||||||
Usage: "Address to register",
|
Usage: "Address to register",
|
||||||
},
|
},
|
||||||
}, options.RPC...),
|
}, options.RPC...),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "unregister",
|
Name: "unregister",
|
||||||
Usage: "unregister self as a candidate",
|
Usage: "Unregister self as a candidate",
|
||||||
UsageText: "unregister -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
|
UsageText: "unregister -w <path> -r <rpc> [-s timeout] -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
|
||||||
Action: handleUnregister,
|
Action: handleUnregister,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
|
@ -49,15 +51,17 @@ func newValidatorCommands() []cli.Command {
|
||||||
txctx.OutFlag,
|
txctx.OutFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
txctx.AwaitFlag,
|
txctx.AwaitFlag,
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address",
|
||||||
|
Required: true,
|
||||||
|
Aliases: []string{"a"},
|
||||||
Usage: "Address to unregister",
|
Usage: "Address to unregister",
|
||||||
},
|
},
|
||||||
}, options.RPC...),
|
}, options.RPC...),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "vote",
|
Name: "vote",
|
||||||
Usage: "vote for a validator",
|
Usage: "Vote for a validator",
|
||||||
UsageText: "vote -w <path> -r <rpc> [-s <timeout>] [-g gas] [-e sysgas] -a <addr> [-c <public key>] [--out file] [--force] [--await]",
|
UsageText: "vote -w <path> -r <rpc> [-s <timeout>] [-g gas] [-e sysgas] -a <addr> [-c <public key>] [--out file] [--force] [--await]",
|
||||||
Description: `Votes for a validator by calling "vote" method of a NEO native
|
Description: `Votes for a validator by calling "vote" method of a NEO native
|
||||||
contract. Do not provide candidate argument to perform unvoting. If --await flag is
|
contract. Do not provide candidate argument to perform unvoting. If --await flag is
|
||||||
|
@ -72,12 +76,15 @@ func newValidatorCommands() []cli.Command {
|
||||||
txctx.OutFlag,
|
txctx.OutFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
txctx.AwaitFlag,
|
txctx.AwaitFlag,
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address",
|
||||||
|
Required: true,
|
||||||
|
Aliases: []string{"a"},
|
||||||
Usage: "Address to vote from",
|
Usage: "Address to vote from",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "candidate, c",
|
Name: "candidate",
|
||||||
|
Aliases: []string{"c"},
|
||||||
Usage: "Public key of candidate to vote for",
|
Usage: "Public key of candidate to vote for",
|
||||||
},
|
},
|
||||||
}, options.RPC...),
|
}, options.RPC...),
|
||||||
|
@ -103,18 +110,15 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
|
||||||
}
|
}
|
||||||
wall, pass, err := readWallet(ctx)
|
wall, pass, err := readWallet(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
addrFlag := ctx.Generic("address").(*flags.Address)
|
addrFlag := ctx.Generic("address").(*flags.Address)
|
||||||
if !addrFlag.IsSet {
|
|
||||||
return cli.NewExitError("address was not provided", 1)
|
|
||||||
}
|
|
||||||
addr := addrFlag.Uint160()
|
addr := addrFlag.Uint160()
|
||||||
acc, err := options.GetUnlockedAccount(wall, addr, pass)
|
acc, err := options.GetUnlockedAccount(wall, addr, pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
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)
|
signers, err := cmdargs.GetSignersAccounts(acc, wall, nil, transaction.CalledByEntry)
|
||||||
if err != nil {
|
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)
|
_, act, exitErr := options.GetRPCWithActor(gctx, ctx, signers)
|
||||||
if exitErr != nil {
|
if exitErr != nil {
|
||||||
|
@ -132,7 +136,7 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
|
||||||
contract := neo.New(act)
|
contract := neo.New(act)
|
||||||
tx, err := mkTx(contract, addr, acc)
|
tx, err := mkTx(contract, addr, acc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
return txctx.SignAndSend(ctx, act, acc, tx)
|
return txctx.SignAndSend(ctx, act, acc, tx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -47,38 +47,43 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
walletPathFlag = cli.StringFlag{
|
walletPathFlag = &cli.StringFlag{
|
||||||
Name: "wallet, w",
|
Name: "wallet",
|
||||||
|
Aliases: []string{"w"},
|
||||||
Usage: "Path to the wallet file ('-' to read from stdin); conflicts with --wallet-config flag.",
|
Usage: "Path to the wallet file ('-' to read from stdin); conflicts with --wallet-config flag.",
|
||||||
}
|
}
|
||||||
walletConfigFlag = cli.StringFlag{
|
walletConfigFlag = &cli.StringFlag{
|
||||||
Name: "wallet-config",
|
Name: "wallet-config",
|
||||||
Usage: "Path to the wallet config file; conflicts with --wallet flag.",
|
Usage: "Path to the wallet config file; conflicts with --wallet flag.",
|
||||||
}
|
}
|
||||||
wifFlag = cli.StringFlag{
|
wifFlag = &cli.StringFlag{
|
||||||
Name: "wif",
|
Name: "wif",
|
||||||
Usage: "WIF to import",
|
Usage: "WIF to import",
|
||||||
}
|
}
|
||||||
decryptFlag = cli.BoolFlag{
|
decryptFlag = &cli.BoolFlag{
|
||||||
Name: "decrypt, d",
|
Name: "decrypt",
|
||||||
|
Aliases: []string{"d"},
|
||||||
Usage: "Decrypt encrypted keys.",
|
Usage: "Decrypt encrypted keys.",
|
||||||
}
|
}
|
||||||
inFlag = cli.StringFlag{
|
inFlag = &cli.StringFlag{
|
||||||
Name: "in",
|
Name: "in",
|
||||||
Usage: "file with JSON transaction",
|
Required: true,
|
||||||
|
Usage: "File with JSON transaction",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("in"),
|
||||||
}
|
}
|
||||||
fromAddrFlag = flags.AddressFlag{
|
fromAddrFlag = &flags.AddressFlag{
|
||||||
Name: "from",
|
Name: "from",
|
||||||
Usage: "Address to send an asset from",
|
Usage: "Address to send an asset from",
|
||||||
}
|
}
|
||||||
toAddrFlag = flags.AddressFlag{
|
toAddrFlag = &flags.AddressFlag{
|
||||||
Name: "to",
|
Name: "to",
|
||||||
Usage: "Address to send an asset to",
|
Usage: "Address to send an asset to",
|
||||||
|
Required: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCommands returns 'wallet' command.
|
// NewCommands returns 'wallet' command.
|
||||||
func NewCommands() []cli.Command {
|
func NewCommands() []*cli.Command {
|
||||||
claimFlags := []cli.Flag{
|
claimFlags := []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
|
@ -87,8 +92,10 @@ func NewCommands() []cli.Command {
|
||||||
txctx.OutFlag,
|
txctx.OutFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
txctx.AwaitFlag,
|
txctx.AwaitFlag,
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address",
|
||||||
|
Aliases: []string{"a"},
|
||||||
|
Required: true,
|
||||||
Usage: "Address to claim GAS for",
|
Usage: "Address to claim GAS for",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -99,67 +106,78 @@ func NewCommands() []cli.Command {
|
||||||
txctx.OutFlag,
|
txctx.OutFlag,
|
||||||
txctx.AwaitFlag,
|
txctx.AwaitFlag,
|
||||||
inFlag,
|
inFlag,
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address",
|
||||||
|
Aliases: []string{"a"},
|
||||||
Usage: "Address to use",
|
Usage: "Address to use",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
signFlags = append(signFlags, options.RPC...)
|
// By default, RPC flag is required. signtx may be called without provided rpc-endpoint.
|
||||||
return []cli.Command{{
|
rpcFlagOriginal, _ := options.RPC[0].(*cli.StringFlag)
|
||||||
|
rpcFlag := *rpcFlagOriginal
|
||||||
|
rpcFlag.Required = false
|
||||||
|
signFlags = append(signFlags, &rpcFlag)
|
||||||
|
signFlags = append(signFlags, options.RPC[1:]...)
|
||||||
|
return []*cli.Command{{
|
||||||
Name: "wallet",
|
Name: "wallet",
|
||||||
Usage: "create, open and manage a Neo wallet",
|
Usage: "Create, open and manage a Neo wallet",
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "claim",
|
Name: "claim",
|
||||||
Usage: "claim GAS",
|
Usage: "Claim GAS",
|
||||||
UsageText: "neo-go wallet claim -w wallet [--wallet-config path] [-g gas] [-e sysgas] -a address -r endpoint [-s timeout] [--out file] [--force] [--await]",
|
UsageText: "neo-go wallet claim -w wallet [--wallet-config path] [-g gas] [-e sysgas] -a address -r endpoint [-s timeout] [--out file] [--force] [--await]",
|
||||||
Action: claimGas,
|
Action: claimGas,
|
||||||
Flags: claimFlags,
|
Flags: claimFlags,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "init",
|
Name: "init",
|
||||||
Usage: "create a new wallet",
|
Usage: "Create a new wallet",
|
||||||
UsageText: "neo-go wallet init -w wallet [--wallet-config path] [-a]",
|
UsageText: "neo-go wallet init -w wallet [--wallet-config path] [-a]",
|
||||||
Action: createWallet,
|
Action: createWallet,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "account, a",
|
Name: "account",
|
||||||
|
Aliases: []string{"a"},
|
||||||
Usage: "Create a new account",
|
Usage: "Create a new account",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "change-password",
|
Name: "change-password",
|
||||||
Usage: "change password for accounts",
|
Usage: "Change password for accounts",
|
||||||
UsageText: "neo-go wallet change-password -w wallet -a address",
|
UsageText: "neo-go wallet change-password -w wallet [-a address]",
|
||||||
Action: changePassword,
|
Action: changePassword,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address",
|
||||||
Usage: "address to change password for",
|
Aliases: []string{"a"},
|
||||||
|
Usage: "Address to change password for",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "convert",
|
Name: "convert",
|
||||||
Usage: "convert addresses from existing Neo Legacy NEP6-wallet to Neo N3 format",
|
Usage: "Convert addresses from existing Neo Legacy NEP6-wallet to Neo N3 format",
|
||||||
UsageText: "neo-go wallet convert -w legacywallet [--wallet-config path] -o n3wallet",
|
UsageText: "neo-go wallet convert -w legacywallet [--wallet-config path] -o n3wallet",
|
||||||
Action: convertWallet,
|
Action: convertWallet,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "out, o",
|
Name: "out",
|
||||||
Usage: "where to write converted wallet",
|
Aliases: []string{"o"},
|
||||||
|
Required: true,
|
||||||
|
Usage: "Where to write converted wallet",
|
||||||
|
Action: cmdargs.EnsureNotEmpty("out"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "create",
|
Name: "create",
|
||||||
Usage: "add an account to the existing wallet",
|
Usage: "Add an account to the existing wallet",
|
||||||
UsageText: "neo-go wallet create -w wallet [--wallet-config path]",
|
UsageText: "neo-go wallet create -w wallet [--wallet-config path]",
|
||||||
Action: addAccount,
|
Action: addAccount,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -169,7 +187,7 @@ func NewCommands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "dump",
|
Name: "dump",
|
||||||
Usage: "check and dump an existing Neo wallet",
|
Usage: "Check and dump an existing Neo wallet",
|
||||||
UsageText: "neo-go wallet dump -w wallet [--wallet-config path] [-d]",
|
UsageText: "neo-go wallet dump -w wallet [--wallet-config path] [-d]",
|
||||||
Description: `Prints the given wallet (via -w option or via wallet configuration file) in JSON
|
Description: `Prints the given wallet (via -w option or via wallet configuration file) in JSON
|
||||||
format to the standard output. If -d is given, private keys are unencrypted and
|
format to the standard output. If -d is given, private keys are unencrypted and
|
||||||
|
@ -185,21 +203,22 @@ func NewCommands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "dump-keys",
|
Name: "dump-keys",
|
||||||
Usage: "dump public keys for account",
|
Usage: "Dump public keys for account",
|
||||||
UsageText: "neo-go wallet dump-keys -w wallet [--wallet-config path] [-a address]",
|
UsageText: "neo-go wallet dump-keys -w wallet [--wallet-config path] [-a address]",
|
||||||
Action: dumpKeys,
|
Action: dumpKeys,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address",
|
||||||
Usage: "address to print public keys for",
|
Aliases: []string{"a"},
|
||||||
|
Usage: "Address to print public keys for",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "export",
|
Name: "export",
|
||||||
Usage: "export keys for address",
|
Usage: "Export keys for address",
|
||||||
UsageText: "export -w wallet [--wallet-config path] [--decrypt] [<address>]",
|
UsageText: "export -w wallet [--wallet-config path] [--decrypt] [<address>]",
|
||||||
Description: `Prints the key for the given account to the standard output. It uses NEP-2
|
Description: `Prints the key for the given account to the standard output. It uses NEP-2
|
||||||
encrypted format by default (the way NEP-6 wallets store it) or WIF format if
|
encrypted format by default (the way NEP-6 wallets store it) or WIF format if
|
||||||
|
@ -216,18 +235,19 @@ func NewCommands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "import",
|
Name: "import",
|
||||||
Usage: "import WIF of a standard signature contract",
|
Usage: "Import WIF of a standard signature contract",
|
||||||
UsageText: "import -w wallet [--wallet-config path] --wif <wif> [--name <account_name>]",
|
UsageText: "import -w wallet [--wallet-config path] --wif <wif> [--name <account_name>]",
|
||||||
Action: importWallet,
|
Action: importWallet,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
wifFlag,
|
wifFlag,
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name, n",
|
Name: "name",
|
||||||
|
Aliases: []string{"n"},
|
||||||
Usage: "Optional account name",
|
Usage: "Optional account name",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "contract",
|
Name: "contract",
|
||||||
Usage: "Verification script for custom contracts",
|
Usage: "Verification script for custom contracts",
|
||||||
},
|
},
|
||||||
|
@ -235,7 +255,7 @@ func NewCommands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "import-multisig",
|
Name: "import-multisig",
|
||||||
Usage: "import multisig contract",
|
Usage: "Import multisig contract",
|
||||||
UsageText: "import-multisig -w wallet [--wallet-config path] [--wif <wif>] [--name <account_name>] --min <m>" +
|
UsageText: "import-multisig -w wallet [--wallet-config path] [--wif <wif>] [--name <account_name>] --min <m>" +
|
||||||
" [<pubkey1> [<pubkey2> [...]]]",
|
" [<pubkey1> [<pubkey2> [...]]]",
|
||||||
Description: `Imports a standard multisignature contract with "m out of n" signatures required where "m" is
|
Description: `Imports a standard multisignature contract with "m out of n" signatures required where "m" is
|
||||||
|
@ -250,53 +270,60 @@ func NewCommands() []cli.Command {
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
wifFlag,
|
wifFlag,
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name, n",
|
Name: "name",
|
||||||
|
Aliases: []string{"n"},
|
||||||
Usage: "Optional account name",
|
Usage: "Optional account name",
|
||||||
},
|
},
|
||||||
cli.IntFlag{
|
&cli.IntFlag{
|
||||||
Name: "min, m",
|
Name: "min",
|
||||||
|
Aliases: []string{"m"},
|
||||||
Usage: "Minimal number of signatures",
|
Usage: "Minimal number of signatures",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "import-deployed",
|
Name: "import-deployed",
|
||||||
Usage: "import deployed contract",
|
Usage: "Import deployed contract",
|
||||||
UsageText: "import-deployed -w wallet [--wallet-config path] --wif <wif> --contract <hash> [--name <account_name>]",
|
UsageText: "import-deployed -w wallet [--wallet-config path] --wif <wif> --contract <hash> --rpc-endpoint <endpoint> [-s <timeout>] [--name <account_name>]",
|
||||||
Action: importDeployed,
|
Action: importDeployed,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
wifFlag,
|
wifFlag,
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name, n",
|
Name: "name",
|
||||||
|
Aliases: []string{"n"},
|
||||||
Usage: "Optional account name",
|
Usage: "Optional account name",
|
||||||
},
|
},
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "contract, c",
|
Name: "contract",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Required: true,
|
||||||
Usage: "Contract hash or address",
|
Usage: "Contract hash or address",
|
||||||
},
|
},
|
||||||
}, options.RPC...),
|
}, options.RPC...),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "remove",
|
Name: "remove",
|
||||||
Usage: "remove an account from the wallet",
|
Usage: "Remove an account from the wallet",
|
||||||
UsageText: "remove -w wallet [--wallet-config path] [--force] --address <addr>",
|
UsageText: "remove -w wallet [--wallet-config path] [--force] --address <addr>",
|
||||||
Action: removeAccount,
|
Action: removeAccount,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
flags.AddressFlag{
|
&flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address",
|
||||||
|
Aliases: []string{"a"},
|
||||||
|
Required: true,
|
||||||
Usage: "Account address or hash in LE form to be removed",
|
Usage: "Account address or hash in LE form to be removed",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "sign",
|
Name: "sign",
|
||||||
Usage: "cosign transaction with multisig/contract/additional account",
|
Usage: "Cosign transaction with multisig/contract/additional account",
|
||||||
UsageText: "sign -w wallet [--wallet-config path] --address <address> --in <file.in> [--out <file.out>] [-r <endpoint>] [--await]",
|
UsageText: "sign -w wallet [--wallet-config path] --address <address> --in <file.in> [--out <file.out>] [-r <endpoint>] [--await]",
|
||||||
Description: `Signs the given (in file.in) context (which must be a transaction
|
Description: `Signs the given (in file.in) context (which must be a transaction
|
||||||
signing context) for the given address using the given wallet. This command can
|
signing context) for the given address using the given wallet. This command can
|
||||||
|
@ -312,7 +339,7 @@ func NewCommands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "strip-keys",
|
Name: "strip-keys",
|
||||||
Usage: "remove private keys for all accounts",
|
Usage: "Remove private keys for all accounts",
|
||||||
UsageText: "neo-go wallet strip-keys -w wallet [--wallet-config path] [--force]",
|
UsageText: "neo-go wallet strip-keys -w wallet [--wallet-config path] [--force]",
|
||||||
Description: `Removes private keys for all accounts from the given wallet. Notice,
|
Description: `Removes private keys for all accounts from the given wallet. Notice,
|
||||||
this is a very dangerous action (you can lose keys if you don't have a wallet
|
this is a very dangerous action (you can lose keys if you don't have a wallet
|
||||||
|
@ -329,17 +356,17 @@ func NewCommands() []cli.Command {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "nep17",
|
Name: "nep17",
|
||||||
Usage: "work with NEP-17 contracts",
|
Usage: "Work with NEP-17 contracts",
|
||||||
Subcommands: newNEP17Commands(),
|
Subcommands: newNEP17Commands(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "nep11",
|
Name: "nep11",
|
||||||
Usage: "work with NEP-11 contracts",
|
Usage: "Work with NEP-11 contracts",
|
||||||
Subcommands: newNEP11Commands(),
|
Subcommands: newNEP11Commands(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "candidate",
|
Name: "candidate",
|
||||||
Usage: "work with candidates",
|
Usage: "Work with candidates",
|
||||||
Subcommands: newValidatorCommands(),
|
Subcommands: newValidatorCommands(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -358,24 +385,24 @@ func changePassword(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
wall, _, err := openWallet(ctx, false)
|
wall, _, err := openWallet(ctx, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
if len(wall.Accounts) == 0 {
|
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)
|
addrFlag := ctx.Generic("address").(*flags.Address)
|
||||||
if addrFlag.IsSet {
|
if addrFlag.IsSet {
|
||||||
// Check for account presence first before asking for password.
|
// Check for account presence first before asking for password.
|
||||||
acc := wall.GetAccount(addrFlag.Uint160())
|
acc := wall.GetAccount(addrFlag.Uint160())
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
return cli.NewExitError("account is missing", 1)
|
return cli.Exit("account is missing", 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
oldPass, err := input.ReadPassword(EnterOldPasswordPrompt)
|
oldPass, err := input.ReadPassword(EnterOldPasswordPrompt)
|
||||||
if err != nil {
|
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 {
|
for i := range wall.Accounts {
|
||||||
|
@ -384,13 +411,13 @@ func changePassword(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
err := wall.Accounts[i].Decrypt(oldPass, wall.Scrypt)
|
err := wall.Accounts[i].Decrypt(oldPass, wall.Scrypt)
|
||||||
if err != nil {
|
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()
|
pass, err := readNewPassword()
|
||||||
if err != nil {
|
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 {
|
for i := range wall.Accounts {
|
||||||
if addrFlag.IsSet && wall.Accounts[i].Address != addrFlag.String() {
|
if addrFlag.IsSet && wall.Accounts[i].Address != addrFlag.String() {
|
||||||
|
@ -398,12 +425,12 @@ func changePassword(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
err := wall.Accounts[i].Encrypt(pass, wall.Scrypt)
|
err := wall.Accounts[i].Encrypt(pass, wall.Scrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = wall.Save()
|
err = wall.Save()
|
||||||
if err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -414,16 +441,13 @@ func convertWallet(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
wall, pass, err := newWalletV2FromFile(ctx.String("wallet"), ctx.String("wallet-config"))
|
wall, pass, err := newWalletV2FromFile(ctx.String("wallet"), ctx.String("wallet-config"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
out := ctx.String("out")
|
out := ctx.String("out")
|
||||||
if len(out) == 0 {
|
|
||||||
return cli.NewExitError("missing out path", 1)
|
|
||||||
}
|
|
||||||
newWallet, err := wallet.NewWallet(out)
|
newWallet, err := wallet.NewWallet(out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
newWallet.Scrypt = wall.Scrypt
|
newWallet.Scrypt = wall.Scrypt
|
||||||
|
|
||||||
|
@ -431,19 +455,19 @@ func convertWallet(ctx *cli.Context) error {
|
||||||
if len(wall.Accounts) != 1 || pass == nil {
|
if len(wall.Accounts) != 1 || pass == nil {
|
||||||
password, err := input.ReadPassword(fmt.Sprintf("Enter password for account %s (label '%s') > ", acc.Address, acc.Label))
|
password, err := input.ReadPassword(fmt.Sprintf("Enter password for account %s (label '%s') > ", acc.Address, acc.Label))
|
||||||
if err != nil {
|
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
|
pass = &password
|
||||||
}
|
}
|
||||||
|
|
||||||
newAcc, err := acc.convert(*pass, wall.Scrypt)
|
newAcc, err := acc.convert(*pass, wall.Scrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
newWallet.AddAccount(newAcc)
|
newWallet.AddAccount(newAcc)
|
||||||
}
|
}
|
||||||
if err := newWallet.Save(); err != nil {
|
if err := newWallet.Save(); err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -454,12 +478,12 @@ func addAccount(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
wall, pass, err := openWallet(ctx, true)
|
wall, pass, err := openWallet(ctx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
if err := createAccount(wall, pass); err != nil {
|
if err := createAccount(wall, pass); err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -468,7 +492,7 @@ func addAccount(ctx *cli.Context) error {
|
||||||
func exportKeys(ctx *cli.Context) error {
|
func exportKeys(ctx *cli.Context) error {
|
||||||
wall, pass, err := readWallet(ctx)
|
wall, pass, err := readWallet(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
|
@ -476,13 +500,13 @@ func exportKeys(ctx *cli.Context) error {
|
||||||
|
|
||||||
decrypt := ctx.Bool("decrypt")
|
decrypt := ctx.Bool("decrypt")
|
||||||
if ctx.NArg() == 0 && 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 {
|
} else if ctx.NArg() > 0 {
|
||||||
// check address format just to catch possible typos
|
// check address format just to catch possible typos
|
||||||
addr = ctx.Args().First()
|
addr = ctx.Args().First()
|
||||||
_, err := address.StringToUint160(addr)
|
_, err := address.StringToUint160(addr)
|
||||||
if err != nil {
|
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 +532,14 @@ loop:
|
||||||
if pass == nil {
|
if pass == nil {
|
||||||
password, err := input.ReadPassword(EnterPasswordPrompt)
|
password, err := input.ReadPassword(EnterPasswordPrompt)
|
||||||
if err != nil {
|
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
|
pass = &password
|
||||||
}
|
}
|
||||||
|
|
||||||
pk, err := keys.NEP2Decrypt(wif, *pass, wall.Scrypt)
|
pk, err := keys.NEP2Decrypt(wif, *pass, wall.Scrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
wif = pk.WIF()
|
wif = pk.WIF()
|
||||||
|
@ -536,22 +560,22 @@ func importMultisig(ctx *cli.Context) error {
|
||||||
|
|
||||||
wall, pass, err := openWallet(ctx, true)
|
wall, pass, err := openWallet(ctx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
m := ctx.Int("min")
|
m := ctx.Int("min")
|
||||||
if ctx.NArg() < m {
|
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))
|
pubs := make([]*keys.PublicKey, len(args))
|
||||||
|
|
||||||
for i := range args {
|
for i := range args {
|
||||||
pubs[i], err = keys.NewPublicKeyFromString(args[i])
|
pubs[i], err = keys.NewPublicKeyFromString(args[i])
|
||||||
if err != nil {
|
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 +603,31 @@ loop:
|
||||||
if acc != nil {
|
if acc != nil {
|
||||||
err = acc.ConvertMultisigEncrypted(accPub, m, pubs)
|
err = acc.ConvertMultisigEncrypted(accPub, m, pubs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if label != nil {
|
if label != nil {
|
||||||
acc.Label = *label
|
acc.Label = *label
|
||||||
}
|
}
|
||||||
if err := addAccountAndSave(wall, acc); err != nil {
|
if err := addAccountAndSave(wall, acc); err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.IsSet("wif") {
|
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)
|
acc, err = newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := acc.ConvertMultisig(m, pubs); err != nil {
|
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 {
|
if err := addAccountAndSave(wall, acc); err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -615,14 +639,11 @@ func importDeployed(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
wall, pass, err := openWallet(ctx, true)
|
wall, pass, err := openWallet(ctx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
rawHash := ctx.Generic("contract").(*flags.Address)
|
rawHash := ctx.Generic("contract").(*flags.Address)
|
||||||
if !rawHash.IsSet {
|
|
||||||
return cli.NewExitError("contract hash was not provided", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var label *string
|
var label *string
|
||||||
if ctx.IsSet("name") {
|
if ctx.IsSet("name") {
|
||||||
|
@ -631,7 +652,7 @@ func importDeployed(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass)
|
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
@ -639,16 +660,16 @@ func importDeployed(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
cs, err := c.GetContractStateByHash(rawHash.Uint160())
|
cs, err := c.GetContractStateByHash(rawHash.Uint160())
|
||||||
if err != nil {
|
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)
|
md := cs.Manifest.ABI.GetMethod(manifest.MethodVerify, -1)
|
||||||
if md == nil || md.ReturnType != smartcontract.BoolType {
|
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)
|
acc.Address = address.Uint160ToString(cs.Hash)
|
||||||
// Explicitly overwrite single signature script of the provided WIF since the contract is known to be deployed.
|
// Explicitly overwrite single signature script of the provided WIF since the contract is known to be deployed.
|
||||||
|
@ -663,7 +684,7 @@ func importDeployed(ctx *cli.Context) error {
|
||||||
acc.Contract.Deployed = true
|
acc.Contract.Deployed = true
|
||||||
|
|
||||||
if err := addAccountAndSave(wall, acc); err != nil {
|
if err := addAccountAndSave(wall, acc); err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -675,7 +696,7 @@ func importWallet(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
wall, pass, err := openWallet(ctx, true)
|
wall, pass, err := openWallet(ctx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
|
@ -687,19 +708,19 @@ func importWallet(ctx *cli.Context) error {
|
||||||
|
|
||||||
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass)
|
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctrFlag := ctx.String("contract"); ctrFlag != "" {
|
if ctrFlag := ctx.String("contract"); ctrFlag != "" {
|
||||||
ctr, err := hex.DecodeString(ctrFlag)
|
ctr, err := hex.DecodeString(ctrFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError("invalid contract", 1)
|
return cli.Exit("invalid contract", 1)
|
||||||
}
|
}
|
||||||
acc.Contract.Script = ctr
|
acc.Contract.Script = ctr
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := addAccountAndSave(wall, acc); err != nil {
|
if err := addAccountAndSave(wall, acc); err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -711,17 +732,14 @@ func removeAccount(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
wall, _, err := openWallet(ctx, true)
|
wall, _, err := openWallet(ctx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
|
|
||||||
addr := ctx.Generic("address").(*flags.Address)
|
addr := ctx.Generic("address").(*flags.Address)
|
||||||
if !addr.IsSet {
|
|
||||||
return cli.NewExitError("valid account address must be provided", 1)
|
|
||||||
}
|
|
||||||
acc := wall.GetAccount(addr.Uint160())
|
acc := wall.GetAccount(addr.Uint160())
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
return cli.NewExitError("account wasn't found", 1)
|
return cli.Exit("account wasn't found", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.Bool("force") {
|
if !ctx.Bool("force") {
|
||||||
|
@ -732,10 +750,10 @@ func removeAccount(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := wall.RemoveAccount(acc.Address); err != nil {
|
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 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -758,14 +776,14 @@ func dumpWallet(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
wall, pass, err := readWallet(ctx)
|
wall, pass, err := readWallet(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
if ctx.Bool("decrypt") {
|
if ctx.Bool("decrypt") {
|
||||||
if pass == nil {
|
if pass == nil {
|
||||||
password, err := input.ReadPassword(EnterPasswordPrompt)
|
password, err := input.ReadPassword(EnterPasswordPrompt)
|
||||||
if err != nil {
|
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
|
pass = &password
|
||||||
}
|
}
|
||||||
|
@ -773,7 +791,7 @@ func dumpWallet(ctx *cli.Context) error {
|
||||||
// Just testing the decryption here.
|
// Just testing the decryption here.
|
||||||
err := wall.Accounts[i].Decrypt(*pass, wall.Scrypt)
|
err := wall.Accounts[i].Decrypt(*pass, wall.Scrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -787,7 +805,7 @@ func dumpKeys(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
wall, _, err := readWallet(ctx)
|
wall, _, err := readWallet(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
accounts := wall.Accounts
|
accounts := wall.Accounts
|
||||||
|
@ -796,7 +814,7 @@ func dumpKeys(ctx *cli.Context) error {
|
||||||
if addrFlag.IsSet {
|
if addrFlag.IsSet {
|
||||||
acc := wall.GetAccount(addrFlag.Uint160())
|
acc := wall.GetAccount(addrFlag.Uint160())
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
return cli.NewExitError("account is missing", 1)
|
return cli.Exit("account is missing", 1)
|
||||||
}
|
}
|
||||||
accounts = []*wallet.Account{acc}
|
accounts = []*wallet.Account{acc}
|
||||||
}
|
}
|
||||||
|
@ -826,7 +844,7 @@ func dumpKeys(ctx *cli.Context) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if addrFlag.IsSet {
|
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
|
return nil
|
||||||
|
@ -838,7 +856,7 @@ func stripKeys(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
wall, _, err := readWallet(ctx)
|
wall, _, err := readWallet(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
if !ctx.Bool("force") {
|
if !ctx.Bool("force") {
|
||||||
|
@ -851,7 +869,7 @@ func stripKeys(ctx *cli.Context) error {
|
||||||
a.EncryptedWIF = ""
|
a.EncryptedWIF = ""
|
||||||
}
|
}
|
||||||
if err := wall.Save(); err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -867,28 +885,28 @@ func createWallet(ctx *cli.Context) error {
|
||||||
return errConflictingWalletFlags
|
return errConflictingWalletFlags
|
||||||
}
|
}
|
||||||
if len(path) == 0 && len(configPath) == 0 {
|
if len(path) == 0 && len(configPath) == 0 {
|
||||||
return cli.NewExitError(errNoPath, 1)
|
return cli.Exit(errNoPath, 1)
|
||||||
}
|
}
|
||||||
var pass *string
|
var pass *string
|
||||||
if len(configPath) != 0 {
|
if len(configPath) != 0 {
|
||||||
cfg, err := options.ReadWalletConfig(configPath)
|
cfg, err := options.ReadWalletConfig(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
path = cfg.Path
|
path = cfg.Path
|
||||||
pass = &cfg.Password
|
pass = &cfg.Password
|
||||||
}
|
}
|
||||||
wall, err := wallet.NewWallet(path)
|
wall, err := wallet.NewWallet(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
if err := wall.Save(); err != nil {
|
if err := wall.Save(); err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.Bool("account") {
|
if ctx.Bool("account") {
|
||||||
if err := createAccount(wall, pass); err != nil {
|
if err := createAccount(wall, pass); err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.Exit(err, 1)
|
||||||
}
|
}
|
||||||
defer wall.Close()
|
defer wall.Close()
|
||||||
}
|
}
|
||||||
|
@ -949,14 +967,14 @@ func createAccount(wall *wallet.Wallet, pass *string) error {
|
||||||
func openWallet(ctx *cli.Context, canUseWalletConfig bool) (*wallet.Wallet, *string, error) {
|
func openWallet(ctx *cli.Context, canUseWalletConfig bool) (*wallet.Wallet, *string, error) {
|
||||||
path, pass, err := getWalletPathAndPass(ctx, canUseWalletConfig)
|
path, pass, err := getWalletPathAndPass(ctx, canUseWalletConfig)
|
||||||
if err != nil {
|
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 == "-" {
|
if path == "-" {
|
||||||
return nil, nil, errNoStdin
|
return nil, nil, errNoStdin
|
||||||
}
|
}
|
||||||
w, err := wallet.NewWalletFromFile(path)
|
w, err := wallet.NewWalletFromFile(path)
|
||||||
if err != nil {
|
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
|
return w, pass, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,10 +40,10 @@ func TestWalletAccountRemove(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("missing wallet", func(t *testing.T) {
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "wallet", "remove")
|
e.RunWithErrorCheck(t, `Required flag "address" not set`, "neo-go", "wallet", "remove")
|
||||||
})
|
})
|
||||||
t.Run("missing address", func(t *testing.T) {
|
t.Run("missing address", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "wallet", "remove", "--wallet", walletPath)
|
e.RunWithErrorCheck(t, `Required flag "address" not set`, "neo-go", "wallet", "remove", "--wallet", walletPath)
|
||||||
})
|
})
|
||||||
t.Run("invalid address", func(t *testing.T) {
|
t.Run("invalid address", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "wallet", "remove", "--wallet", walletPath,
|
e.RunWithError(t, "neo-go", "wallet", "remove", "--wallet", walletPath,
|
||||||
|
@ -109,7 +109,7 @@ func TestWalletChangePassword(t *testing.T) {
|
||||||
e.In.WriteString("pass\r")
|
e.In.WriteString("pass\r")
|
||||||
e.In.WriteString("pass1\r")
|
e.In.WriteString("pass1\r")
|
||||||
e.In.WriteString("pass2\r")
|
e.In.WriteString("pass2\r")
|
||||||
e.RunWithError(t, "neo-go", "wallet", "change-password", "--wallet", walletPath)
|
e.RunWithError(t, "neo-go", "wallet", "change-password", "--wallet", walletPath, "--address", addr1)
|
||||||
})
|
})
|
||||||
t.Run("good, multiaccount", func(t *testing.T) {
|
t.Run("good, multiaccount", func(t *testing.T) {
|
||||||
e.In.WriteString("pass\r")
|
e.In.WriteString("pass\r")
|
||||||
|
@ -593,7 +593,7 @@ func TestWalletClaimGas(t *testing.T) {
|
||||||
"--address", testcli.TestWalletAccount)
|
"--address", testcli.TestWalletAccount)
|
||||||
})
|
})
|
||||||
t.Run("missing address", func(t *testing.T) {
|
t.Run("missing address", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "wallet", "claim",
|
e.RunWithErrorCheck(t, `Required flag "address" not set`, "neo-go", "wallet", "claim",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
"--wallet", testcli.TestWalletPath)
|
"--wallet", testcli.TestWalletPath)
|
||||||
})
|
})
|
||||||
|
@ -605,7 +605,7 @@ func TestWalletClaimGas(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("missing endpoint", func(t *testing.T) {
|
t.Run("missing endpoint", func(t *testing.T) {
|
||||||
e.In.WriteString("testpass\r")
|
e.In.WriteString("testpass\r")
|
||||||
e.RunWithError(t, "neo-go", "wallet", "claim",
|
e.RunWithErrorCheck(t, `Required flag "rpc-endpoint" not set`, "neo-go", "wallet", "claim",
|
||||||
"--wallet", testcli.TestWalletPath,
|
"--wallet", testcli.TestWalletPath,
|
||||||
"--address", testcli.TestWalletAccount)
|
"--address", testcli.TestWalletAccount)
|
||||||
})
|
})
|
||||||
|
@ -711,19 +711,19 @@ func TestWalletImportDeployed(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("missing wallet", func(t *testing.T) {
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "wallet", "import-deployed")
|
e.RunWithErrorCheck(t, `Required flag "contract" not set`, "neo-go", "wallet", "import-deployed", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
|
||||||
})
|
})
|
||||||
t.Run("missing contract sh", func(t *testing.T) {
|
t.Run("missing contract sh", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
|
e.RunWithErrorCheck(t, `Required flag "contract" not set`, "neo-go", "wallet", "import-deployed",
|
||||||
"--wallet", walletPath)
|
"--wallet", walletPath, "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
|
||||||
})
|
})
|
||||||
t.Run("missing WIF", func(t *testing.T) {
|
t.Run("missing WIF", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
|
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
|
||||||
"--wallet", walletPath, "--contract", h.StringLE())
|
"--wallet", walletPath, "--contract", h.StringLE(), "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
|
||||||
})
|
})
|
||||||
t.Run("missing endpoint", func(t *testing.T) {
|
t.Run("missing endpoint", func(t *testing.T) {
|
||||||
e.In.WriteString("acc\rpass\rpass\r")
|
e.In.WriteString("acc\rpass\rpass\r")
|
||||||
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
|
e.RunWithErrorCheck(t, `Required flag "rpc-endpoint" not set`, "neo-go", "wallet", "import-deployed",
|
||||||
"--wallet", walletPath, "--contract", h.StringLE(),
|
"--wallet", walletPath, "--contract", h.StringLE(),
|
||||||
"--wif", priv.WIF())
|
"--wif", priv.WIF())
|
||||||
})
|
})
|
||||||
|
@ -992,7 +992,7 @@ func TestOfflineSigning(t *testing.T) {
|
||||||
|
|
||||||
e.Run(t, "neo-go", "util", "sendtx",
|
e.Run(t, "neo-go", "util", "sendtx",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
txPath, "--await")
|
"--await", txPath)
|
||||||
e.CheckAwaitableTxPersisted(t)
|
e.CheckAwaitableTxPersisted(t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1107,11 +1107,11 @@ func TestWalletConvert(t *testing.T) {
|
||||||
outPath := filepath.Join(tmpDir, "wallet.json")
|
outPath := filepath.Join(tmpDir, "wallet.json")
|
||||||
cmd := []string{"neo-go", "wallet", "convert"}
|
cmd := []string{"neo-go", "wallet", "convert"}
|
||||||
t.Run("missing wallet", func(t *testing.T) {
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithErrorCheck(t, `Required flag "out" not set`, cmd...)
|
||||||
})
|
})
|
||||||
cmd = append(cmd, "--wallet", "testdata/testwallet_NEO2.json")
|
cmd = append(cmd, "--wallet", "testdata/testwallet_NEO2.json")
|
||||||
t.Run("missing out path", func(t *testing.T) {
|
t.Run("missing out path", func(t *testing.T) {
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithErrorCheck(t, `Required flag "out" not set`, cmd...)
|
||||||
})
|
})
|
||||||
t.Run("invalid out path", func(t *testing.T) {
|
t.Run("invalid out path", func(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
|
|
5
go.mod
5
go.mod
|
@ -25,7 +25,7 @@ require (
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954
|
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954
|
||||||
github.com/twmb/murmur3 v1.1.8
|
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.etcd.io/bbolt v1.3.9
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/crypto v0.21.0
|
golang.org/x/crypto v0.21.0
|
||||||
|
@ -42,7 +42,7 @@ require (
|
||||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/consensys/bavard v0.1.13 // 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/frankban/quicktest v1.14.5 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
|
@ -60,6 +60,7 @@ require (
|
||||||
github.com/rs/zerolog v1.30.0 // indirect
|
github.com/rs/zerolog v1.30.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // 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
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
|
||||||
golang.org/x/mod v0.16.0 // indirect
|
golang.org/x/mod v0.16.0 // indirect
|
||||||
|
|
15
go.sum
15
go.sum
|
@ -1,4 +1,3 @@
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4=
|
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
|
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=
|
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 h1:f0BMgIjhZy4lSRHCXFbQst85f5agZAjtDMixQqBWNpc=
|
||||||
github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
|
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/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.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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/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 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c=
|
||||||
github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w=
|
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 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
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 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
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 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs=
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
|
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 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
|
||||||
github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
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/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
|
||||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
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 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
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 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
|
||||||
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
|
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
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/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 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
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.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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
|
|
@ -34,7 +34,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zaptest"
|
"go.uber.org/zap/zaptest"
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
|
@ -273,13 +273,26 @@ func checkExit(t *testing.T, ch <-chan int, code int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunWithError runs command and checks that is exits with error.
|
// RunWithError runs command and checks that is exits with error and exit code 1.
|
||||||
func (e *Executor) RunWithError(t *testing.T, args ...string) {
|
func (e *Executor) RunWithError(t *testing.T, args ...string) {
|
||||||
ch := setExitFunc()
|
ch := setExitFunc()
|
||||||
require.Error(t, e.run(args...))
|
require.Error(t, e.run(args...))
|
||||||
checkExit(t, ch, 1)
|
checkExit(t, ch, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RunWithErrorCheckExit runs command and checks that is exits with error and exit code 1.
|
||||||
|
func (e *Executor) RunWithErrorCheckExit(t *testing.T, msg string, args ...string) {
|
||||||
|
ch := setExitFunc()
|
||||||
|
require.ErrorContains(t, e.run(args...), msg)
|
||||||
|
checkExit(t, ch, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunWithErrorCheck runs command and checks that there were errors with the specified message. Exit code is not checked.
|
||||||
|
func (e *Executor) RunWithErrorCheck(t *testing.T, msg string, args ...string) {
|
||||||
|
err := e.run(args...)
|
||||||
|
require.ErrorContains(t, err, msg)
|
||||||
|
}
|
||||||
|
|
||||||
// Run runs command and checks that there were no errors.
|
// Run runs command and checks that there were no errors.
|
||||||
func (e *Executor) Run(t *testing.T, args ...string) {
|
func (e *Executor) Run(t *testing.T, args ...string) {
|
||||||
ch := setExitFunc()
|
ch := setExitFunc()
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ledgerContractID = -4
|
var ledgerContractID = -4
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/pmezard/go-difflib/difflib"
|
"github.com/pmezard/go-difflib/difflib"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errStateMatches = errors.New("state matches")
|
var errStateMatches = errors.New("state matches")
|
||||||
|
@ -167,9 +167,10 @@ func main() {
|
||||||
ctl.Usage = "compare-states RPC_A RPC_B"
|
ctl.Usage = "compare-states RPC_A RPC_B"
|
||||||
ctl.Action = cliMain
|
ctl.Action = cliMain
|
||||||
ctl.Flags = []cli.Flag{
|
ctl.Flags = []cli.Flag{
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "ignore-height, g",
|
Name: "ignore-height",
|
||||||
Usage: "ignore height difference",
|
Aliases: []string{"h"},
|
||||||
|
Usage: "Ignore height difference",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue