2020-06-17 18:13:37 +00:00
|
|
|
/*
|
|
|
|
Package options contains a set of common CLI options and helper functions to use them.
|
|
|
|
*/
|
|
|
|
package options
|
|
|
|
|
|
|
|
import (
|
2020-06-17 21:15:13 +00:00
|
|
|
"context"
|
|
|
|
"errors"
|
2022-09-08 16:05:32 +00:00
|
|
|
"strconv"
|
2020-06-17 21:15:13 +00:00
|
|
|
"time"
|
|
|
|
|
2022-10-03 12:05:34 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
2020-06-17 18:13:37 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
2022-09-08 16:05:32 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
2022-07-21 19:39:53 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
2022-09-08 16:05:32 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2020-06-17 18:13:37 +00:00
|
|
|
"github.com/urfave/cli"
|
|
|
|
)
|
|
|
|
|
2020-06-17 21:15:13 +00:00
|
|
|
// DefaultTimeout is the default timeout used for RPC requests.
|
|
|
|
const DefaultTimeout = 10 * time.Second
|
|
|
|
|
2022-04-20 18:30:09 +00:00
|
|
|
// RPCEndpointFlag is a long flag name for an RPC endpoint. It can be used to
|
2020-06-17 21:15:13 +00:00
|
|
|
// check for flag presence in the context.
|
|
|
|
const RPCEndpointFlag = "rpc-endpoint"
|
|
|
|
|
2020-06-17 18:13:37 +00:00
|
|
|
// Network is a set of flags for choosing the network to operate on
|
|
|
|
// (privnet/mainnet/testnet).
|
2020-10-21 14:38:35 +00:00
|
|
|
var Network = []cli.Flag{
|
2022-08-05 13:04:56 +00:00
|
|
|
cli.BoolFlag{Name: "privnet, p", Usage: "use private network configuration"},
|
|
|
|
cli.BoolFlag{Name: "mainnet, m", Usage: "use mainnet network configuration"},
|
|
|
|
cli.BoolFlag{Name: "testnet, t", Usage: "use testnet network configuration"},
|
2020-10-21 14:38:35 +00:00
|
|
|
cli.BoolFlag{Name: "unittest", Hidden: true},
|
|
|
|
}
|
2020-06-17 18:13:37 +00:00
|
|
|
|
2020-06-17 21:15:13 +00:00
|
|
|
// RPC is a set of flags used for RPC connections (endpoint and timeout).
|
|
|
|
var RPC = []cli.Flag{
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: RPCEndpointFlag + ", r",
|
|
|
|
Usage: "RPC node address",
|
|
|
|
},
|
|
|
|
cli.DurationFlag{
|
2020-06-18 06:43:37 +00:00
|
|
|
Name: "timeout, s",
|
2022-03-25 08:50:55 +00:00
|
|
|
Value: DefaultTimeout,
|
|
|
|
Usage: "Timeout for the operation",
|
2020-06-17 21:15:13 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2022-09-08 16:05:32 +00:00
|
|
|
// Historic is a flag for commands that can perform historic invocations.
|
|
|
|
var Historic = cli.StringFlag{
|
|
|
|
Name: "historic",
|
|
|
|
Usage: "Use historic state (height, block hash or state root hash)",
|
|
|
|
}
|
|
|
|
|
2022-10-03 12:05:34 +00:00
|
|
|
// Config is a flag for commands that use node configuration.
|
|
|
|
var Config = cli.StringFlag{
|
|
|
|
Name: "config-path",
|
|
|
|
Usage: "path to directory with configuration files",
|
|
|
|
}
|
|
|
|
|
2020-06-17 21:15:13 +00:00
|
|
|
var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'")
|
2022-09-08 16:05:32 +00:00
|
|
|
var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash")
|
2020-06-17 21:15:13 +00:00
|
|
|
|
2020-06-17 18:13:37 +00:00
|
|
|
// GetNetwork examines Context's flags and returns the appropriate network. It
|
|
|
|
// defaults to PrivNet if no flags are given.
|
|
|
|
func GetNetwork(ctx *cli.Context) netmode.Magic {
|
|
|
|
var net = netmode.PrivNet
|
|
|
|
if ctx.Bool("testnet") {
|
|
|
|
net = netmode.TestNet
|
|
|
|
}
|
|
|
|
if ctx.Bool("mainnet") {
|
|
|
|
net = netmode.MainNet
|
|
|
|
}
|
2020-08-31 09:42:42 +00:00
|
|
|
if ctx.Bool("unittest") {
|
|
|
|
net = netmode.UnitTestNet
|
|
|
|
}
|
2020-06-17 18:13:37 +00:00
|
|
|
return net
|
|
|
|
}
|
2020-06-17 21:15:13 +00:00
|
|
|
|
2022-04-20 18:30:09 +00:00
|
|
|
// GetTimeoutContext returns a context.Context with the default or a user-set timeout.
|
2020-06-17 21:15:13 +00:00
|
|
|
func GetTimeoutContext(ctx *cli.Context) (context.Context, func()) {
|
|
|
|
dur := ctx.Duration("timeout")
|
|
|
|
if dur == 0 {
|
|
|
|
dur = DefaultTimeout
|
|
|
|
}
|
|
|
|
return context.WithTimeout(context.Background(), dur)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRPCClient returns an RPC client instance for the given Context.
|
2022-07-21 19:39:53 +00:00
|
|
|
func GetRPCClient(gctx context.Context, ctx *cli.Context) (*rpcclient.Client, cli.ExitCoder) {
|
2020-06-17 21:15:13 +00:00
|
|
|
endpoint := ctx.String(RPCEndpointFlag)
|
|
|
|
if len(endpoint) == 0 {
|
|
|
|
return nil, cli.NewExitError(errNoEndpoint, 1)
|
|
|
|
}
|
2022-07-21 19:39:53 +00:00
|
|
|
c, err := rpcclient.New(gctx, endpoint, rpcclient.Options{})
|
2020-10-14 15:13:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, cli.NewExitError(err, 1)
|
|
|
|
}
|
|
|
|
err = c.Init()
|
2020-06-17 21:15:13 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, cli.NewExitError(err, 1)
|
|
|
|
}
|
|
|
|
return c, nil
|
|
|
|
}
|
2022-09-08 16:05:32 +00:00
|
|
|
|
|
|
|
// GetInvoker returns an invoker using the given RPC client, context and signers.
|
|
|
|
// It parses "--historic" parameter to adjust it.
|
|
|
|
func GetInvoker(c *rpcclient.Client, ctx *cli.Context, signers []transaction.Signer) (*invoker.Invoker, cli.ExitCoder) {
|
|
|
|
historic := ctx.String("historic")
|
|
|
|
if historic == "" {
|
|
|
|
return invoker.New(c, signers), nil
|
|
|
|
}
|
|
|
|
if index, err := strconv.ParseUint(historic, 10, 32); err == nil {
|
|
|
|
return invoker.NewHistoricAtHeight(uint32(index), c, signers), nil
|
|
|
|
}
|
|
|
|
if u256, err := util.Uint256DecodeStringLE(historic); err == nil {
|
|
|
|
// Might as well be a block hash, but it makes no practical difference.
|
|
|
|
return invoker.NewHistoricWithState(u256, c, signers), nil
|
|
|
|
}
|
|
|
|
return nil, cli.NewExitError(errInvalidHistoric, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRPCWithInvoker combines GetRPCClient with GetInvoker for cases where it's
|
|
|
|
// appropriate to do so.
|
|
|
|
func GetRPCWithInvoker(gctx context.Context, ctx *cli.Context, signers []transaction.Signer) (*rpcclient.Client, *invoker.Invoker, cli.ExitCoder) {
|
|
|
|
c, err := GetRPCClient(gctx, ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
inv, err := GetInvoker(c, ctx, signers)
|
|
|
|
if err != nil {
|
|
|
|
c.Close()
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return c, inv, err
|
|
|
|
}
|
2022-10-03 12:05:34 +00:00
|
|
|
|
|
|
|
// GetConfigFromContext looks at the path and the mode flags in the given config and
|
|
|
|
// returns an appropriate config.
|
|
|
|
func GetConfigFromContext(ctx *cli.Context) (config.Config, error) {
|
|
|
|
configPath := "./config"
|
|
|
|
if argCp := ctx.String("config-path"); argCp != "" {
|
|
|
|
configPath = argCp
|
|
|
|
}
|
|
|
|
return config.Load(configPath, GetNetwork(ctx))
|
|
|
|
}
|