cli: move cosigners parsing to a separate function

We have a lot of common code which is shared between `smartcontract` and
`wallet` cli packages. It's convinient to keep it in a separate helper
package in order to avoid functional cli packages dependencies.
This commit is contained in:
Anna Shaleva 2021-04-21 10:54:10 +03:00
parent 8407ae057c
commit 2ab420ed18
4 changed files with 111 additions and 87 deletions

49
cli/cmdargs/parser.go Normal file
View file

@ -0,0 +1,49 @@
package cmdargs
import (
"fmt"
"strings"
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/urfave/cli"
)
// GetSignersFromContext returns signers parsed from context args starting
// from the specified offset.
func GetSignersFromContext(ctx *cli.Context, offset int) ([]transaction.Signer, *cli.ExitError) {
args := ctx.Args()
var signers []transaction.Signer
if args.Present() && len(args) > offset {
for i, c := range args[offset:] {
cosigner, err := parseCosigner(c)
if err != nil {
return nil, cli.NewExitError(fmt.Errorf("failed to parse signer #%d: %w", i, err), 1)
}
signers = append(signers, cosigner)
}
}
return signers, nil
}
func parseCosigner(c string) (transaction.Signer, error) {
var (
err error
res = transaction.Signer{
Scopes: transaction.CalledByEntry,
}
)
data := strings.SplitN(c, ":", 2)
s := data[0]
res.Account, err = flags.ParseAddress(s)
if err != nil {
return res, err
}
if len(data) > 1 {
res.Scopes, err = transaction.ScopesFromString(data[1])
if err != nil {
return transaction.Signer{}, err
}
}
return res, nil
}

View file

@ -0,0 +1,54 @@
package cmdargs
import (
"testing"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/stretchr/testify/require"
)
func TestParseCosigner(t *testing.T) {
acc := util.Uint160{1, 3, 5, 7}
testCases := map[string]transaction.Signer{
acc.StringLE(): {
Account: acc,
Scopes: transaction.CalledByEntry,
},
"0x" + acc.StringLE(): {
Account: acc,
Scopes: transaction.CalledByEntry,
},
acc.StringLE() + ":Global": {
Account: acc,
Scopes: transaction.Global,
},
acc.StringLE() + ":CalledByEntry": {
Account: acc,
Scopes: transaction.CalledByEntry,
},
acc.StringLE() + ":None": {
Account: acc,
Scopes: transaction.None,
},
acc.StringLE() + ":CalledByEntry,CustomContracts": {
Account: acc,
Scopes: transaction.CalledByEntry | transaction.CustomContracts,
},
}
for s, expected := range testCases {
actual, err := parseCosigner(s)
require.NoError(t, err)
require.Equal(t, expected, actual)
}
errorCases := []string{
acc.StringLE() + "0",
acc.StringLE() + ":Unknown",
acc.StringLE() + ":Global,CustomContracts",
acc.StringLE() + ":Global,None",
}
for _, s := range errorCases {
_, err := parseCosigner(s)
require.Error(t, err)
}
}

View file

@ -11,6 +11,7 @@ import (
"path/filepath"
"strings"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options"
@ -513,6 +514,7 @@ func invokeFunction(ctx *cli.Context) error {
func invokeInternal(ctx *cli.Context, signAndPush bool) error {
var (
err error
exitErr *cli.ExitError
gas fixedn.Fixed8
operation string
params = make([]smartcontract.Parameter, 0)
@ -547,14 +549,9 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
}
cosignersStart := paramsStart + cosignersOffset
if len(args) > cosignersStart {
for i, c := range args[cosignersStart:] {
cosigner, err := parseCosigner(c)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to parse cosigner #%d: %w", i+1, err), 1)
}
cosigners = append(cosigners, cosigner)
}
cosigners, exitErr = cmdargs.GetSignersFromContext(ctx, cosignersStart)
if exitErr != nil {
return exitErr
}
if signAndPush {
@ -686,16 +683,9 @@ func testInvokeScript(ctx *cli.Context) error {
return cli.NewExitError(fmt.Errorf("failed to restore .nef file: %w", err), 1)
}
args := ctx.Args()
var signers []transaction.Signer
if args.Present() {
for i, c := range args[:] {
cosigner, err := parseCosigner(c)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to parse signer #%d: %w", i+1, err), 1)
}
signers = append(signers, cosigner)
}
signers, exitErr := cmdargs.GetSignersFromContext(ctx, 0)
if exitErr != nil {
return exitErr
}
gctx, cancel := options.GetTimeoutContext(ctx)
@ -932,25 +922,3 @@ func ParseContractConfig(confFile string) (ProjectConfig, error) {
}
return conf, nil
}
func parseCosigner(c string) (transaction.Signer, error) {
var (
err error
res = transaction.Signer{
Scopes: transaction.CalledByEntry,
}
)
data := strings.SplitN(c, ":", 2)
s := data[0]
res.Account, err = flags.ParseAddress(s)
if err != nil {
return res, err
}
if len(data) > 1 {
res.Scopes, err = transaction.ScopesFromString(data[1])
if err != nil {
return transaction.Signer{}, err
}
}
return res, nil
}

View file

@ -7,9 +7,7 @@ import (
"strings"
"testing"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/stretchr/testify/require"
"github.com/urfave/cli"
)
@ -69,51 +67,6 @@ events:
`, string(manifest))
}
func TestParseCosigner(t *testing.T) {
acc := util.Uint160{1, 3, 5, 7}
testCases := map[string]transaction.Signer{
acc.StringLE(): {
Account: acc,
Scopes: transaction.CalledByEntry,
},
"0x" + acc.StringLE(): {
Account: acc,
Scopes: transaction.CalledByEntry,
},
acc.StringLE() + ":Global": {
Account: acc,
Scopes: transaction.Global,
},
acc.StringLE() + ":CalledByEntry": {
Account: acc,
Scopes: transaction.CalledByEntry,
},
acc.StringLE() + ":None": {
Account: acc,
Scopes: transaction.None,
},
acc.StringLE() + ":CalledByEntry,CustomContracts": {
Account: acc,
Scopes: transaction.CalledByEntry | transaction.CustomContracts,
},
}
for s, expected := range testCases {
actual, err := parseCosigner(s)
require.NoError(t, err)
require.Equal(t, expected, actual)
}
errorCases := []string{
acc.StringLE() + "0",
acc.StringLE() + ":Unknown",
acc.StringLE() + ":Global,CustomContracts",
acc.StringLE() + ":Global,None",
}
for _, s := range errorCases {
_, err := parseCosigner(s)
require.Error(t, err)
}
}
func TestParseParams_CalledFromItself(t *testing.T) {
testCases := map[string]struct {
WordsRead int