diff --git a/cli/vm/cli.go b/cli/vm/cli.go index a8c246b66..7ee1cb366 100644 --- a/cli/vm/cli.go +++ b/cli/vm/cli.go @@ -151,7 +151,7 @@ Example: { Name: "loadnef", Usage: "Load a NEF-consistent script into the VM optionally attaching to it provided signers with scopes", - UsageText: `loadnef [--historic ] [--gas ] [, ...]`, + UsageText: `loadnef [--historic ] [--gas ] [-- , ...]`, Flags: []cli.Flag{historicFlag, gasFlag}, Description: ` and parameters are mandatory. @@ -164,7 +164,7 @@ Example: { Name: "loadbase64", Usage: "Load a base64-encoded script string into the VM optionally attaching to it provided signers with scopes", - UsageText: `loadbase64 [--historic ] [--gas ] [, ...]`, + UsageText: `loadbase64 [--historic ] [--gas ] [-- , ...]`, Flags: []cli.Flag{historicFlag, gasFlag}, Description: ` is mandatory parameter. @@ -177,7 +177,7 @@ Example: { Name: "loadhex", Usage: "Load a hex-encoded script string into the VM optionally attaching to it provided signers with scopes", - UsageText: `loadhex [--historic ] [--gas ] [, ...]`, + UsageText: `loadhex [--historic ] [--gas ] [-- , ...]`, Flags: []cli.Flag{historicFlag, gasFlag}, Description: ` is mandatory parameter. @@ -190,7 +190,7 @@ Example: { Name: "loadgo", Usage: "Compile and load a Go file with the manifest into the VM optionally attaching to it provided signers with scopes", - UsageText: `loadgo [--historic ] [--gas ] [, ...]`, + UsageText: `loadgo [--historic ] [--gas ] [-- , ...]`, Flags: []cli.Flag{historicFlag, gasFlag}, Description: ` is mandatory parameter. @@ -220,7 +220,7 @@ Example: { Name: "loaddeployed", Usage: "Load deployed contract into the VM from chain optionally attaching to it provided signers with scopes", - UsageText: `loaddeployed [--historic ] [--gas ] [, ...]`, + UsageText: `loaddeployed [--historic ] [--gas ] [-- , ...]`, Flags: []cli.Flag{historicFlag, gasFlag}, Description: `Load deployed contract into the VM from chain optionally attaching to it provided signers with scopes. If '--historic' flag specified, then the historic contract state (historic script and manifest) will be loaded. @@ -688,7 +688,13 @@ func handleLoadNEF(c *cli.Context) error { } var signers []transaction.Signer if len(args) > 2 { - signers, err = cmdargs.ParseSigners(c.Args()[2:]) + if args[2] != cmdargs.CosignersSeparator { + return fmt.Errorf("%w: `%s` was expected as the third parameter, got %s", ErrInvalidParameter, cmdargs.CosignersSeparator, args[2]) + } + if len(args) < 4 { + return fmt.Errorf("%w: signers expected after `%s`, got none", ErrInvalidParameter, cmdargs.CosignersSeparator) + } + signers, err = cmdargs.ParseSigners(c.Args()[3:]) if err != nil { return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors } @@ -715,7 +721,13 @@ func handleLoadBase64(c *cli.Context) error { } var signers []transaction.Signer if len(args) > 1 { - signers, err = cmdargs.ParseSigners(args[1:]) + if args[1] != cmdargs.CosignersSeparator { + return fmt.Errorf("%w: `%s` was expected as the second parameter, got %s", ErrInvalidParameter, cmdargs.CosignersSeparator, args[1]) + } + if len(args) < 3 { + return fmt.Errorf("%w: signers expected after `%s`, got none", ErrInvalidParameter, cmdargs.CosignersSeparator) + } + signers, err = cmdargs.ParseSigners(args[2:]) if err != nil { return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors } @@ -749,7 +761,13 @@ func handleLoadHex(c *cli.Context) error { } var signers []transaction.Signer if len(args) > 1 { - signers, err = cmdargs.ParseSigners(args[1:]) + if args[1] != cmdargs.CosignersSeparator { + return fmt.Errorf("%w: `%s` was expected as the second parameter, got %s", ErrInvalidParameter, cmdargs.CosignersSeparator, args[1]) + } + if len(args) < 3 { + return fmt.Errorf("%w: signers expected after `%s`, got none", ErrInvalidParameter, cmdargs.CosignersSeparator) + } + signers, err = cmdargs.ParseSigners(args[2:]) if err != nil { return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors } @@ -783,7 +801,13 @@ func handleLoadGo(c *cli.Context) error { } var signers []transaction.Signer if len(args) > 1 { - signers, err = cmdargs.ParseSigners(args[1:]) + if args[1] != cmdargs.CosignersSeparator { + return fmt.Errorf("%w: `%s` was expected as the second parameter, got %s", ErrInvalidParameter, cmdargs.CosignersSeparator, args[1]) + } + if len(args) < 3 { + return fmt.Errorf("%w: signers expected after `%s`, got none", ErrInvalidParameter, cmdargs.CosignersSeparator) + } + signers, err = cmdargs.ParseSigners(args[2:]) if err != nil { return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors } @@ -849,7 +873,8 @@ func handleLoadDeployed(c *cli.Context) error { if !c.Args().Present() { return errors.New("contract hash, address or ID is mandatory argument") } - hashOrID := c.Args().Get(0) + args := c.Args() + hashOrID := args[0] ic := getInteropContextFromContext(c.App) h, err := flags.ParseAddress(hashOrID) if err != nil { @@ -868,8 +893,14 @@ func handleLoadDeployed(c *cli.Context) error { } var signers []transaction.Signer - if len(c.Args()) > 1 { - signers, err = cmdargs.ParseSigners(c.Args()[1:]) + if len(args) > 1 { + if args[1] != cmdargs.CosignersSeparator { + return fmt.Errorf("%w: %s was expected as the second parameter, got %s", ErrInvalidParameter, cmdargs.CosignersSeparator, args[1]) + } + if len(args) < 3 { + return fmt.Errorf("%w: signers expected after `%s`, got none", ErrInvalidParameter, cmdargs.CosignersSeparator) + } + signers, err = cmdargs.ParseSigners(args[2:]) if err != nil { return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors } diff --git a/cli/vm/cli_test.go b/cli/vm/cli_test.go index 78f0c30d1..843782143 100644 --- a/cli/vm/cli_test.go +++ b/cli/vm/cli_test.go @@ -18,6 +18,7 @@ import ( "time" "github.com/chzyer/readline" + "github.com/nspcc-dev/neo-go/cli/cmdargs" "github.com/nspcc-dev/neo-go/cli/paramcontext" "github.com/nspcc-dev/neo-go/internal/basicchain" "github.com/nspcc-dev/neo-go/internal/random" @@ -298,21 +299,27 @@ func TestLoad(t *testing.T) { "loadhex", "loadhex notahex", "loadhex "+hex.EncodeToString(script), - "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+ownerAddress, // owner:DefaultScope => true + "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator, + "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+"not-a-separator", + "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+"not-a-signer", + "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+ownerAddress, // owner:DefaultScope => true "run", - "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+ownerAddress+":None", // owner:None => false + "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+ownerAddress+":None", // owner:None => false "run", - "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true + "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true "run", - "loadhex "+hex.EncodeToString(checkWitnessScript)+" 0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true + "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+"0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true "run", - "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false + "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false "run", ) e.checkError(t, ErrMissingParameter) e.checkError(t, ErrInvalidParameter) e.checkNextLine(t, "READY: loaded 3 instructions") + e.checkError(t, ErrInvalidParameter) + e.checkError(t, ErrInvalidParameter) + e.checkError(t, ErrInvalidParameter) e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkStack(t, true) e.checkNextLine(t, "READY: loaded \\d+ instructions") @@ -330,21 +337,27 @@ func TestLoad(t *testing.T) { "loadbase64", "loadbase64 not_a_base64", "loadbase64 "+base64.StdEncoding.EncodeToString(script), - "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+ownerAddress, // owner:DefaultScope => true + "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator, + "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+"not-a-separator", + "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" not-a-signer", + "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+ownerAddress, // owner:DefaultScope => true "run", - "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+ownerAddress+":None", // owner:None => false + "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+ownerAddress+":None", // owner:None => false "run", - "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true + "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true "run", - "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" 0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true + "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+"0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true "run", - "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false + "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false "run", ) e.checkError(t, ErrMissingParameter) e.checkError(t, ErrInvalidParameter) e.checkNextLine(t, "READY: loaded 3 instructions") + e.checkError(t, ErrInvalidParameter) + e.checkError(t, ErrInvalidParameter) + e.checkError(t, ErrInvalidParameter) e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkStack(t, true) e.checkNextLine(t, "READY: loaded \\d+ instructions") @@ -440,12 +453,23 @@ go 1.18`) } ` filename := prepareLoadgoSrc(t, srcCheckWitness) + t.Run("invalid", func(t *testing.T) { + e := newTestVMCLI(t) + e.runProg(t, + "loadgo "+filename+" "+cmdargs.CosignersSeparator, + "loadgo "+filename+" "+"not-a-separator", + "loadgo "+filename+" "+cmdargs.CosignersSeparator+" not-a-signer", + ) + e.checkError(t, ErrInvalidParameter) + e.checkError(t, ErrInvalidParameter) + e.checkError(t, ErrInvalidParameter) + }) t.Run("address", func(t *testing.T) { e := newTestVMCLI(t) e.runProg(t, - "loadgo "+filename+" "+ownerAddress, // owner:DefaultScope => true + "loadgo "+filename+" "+cmdargs.CosignersSeparator+" "+ownerAddress, // owner:DefaultScope => true "run main", - "loadgo "+filename+" "+ownerAddress+":None", // owner:None => false + "loadgo "+filename+" "+cmdargs.CosignersSeparator+" "+ownerAddress+":None", // owner:None => false "run main") e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkStack(t, true) @@ -455,9 +479,9 @@ go 1.18`) t.Run("string LE", func(t *testing.T) { e := newTestVMCLI(t) e.runProg(t, - "loadgo "+filename+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true + "loadgo "+filename+" "+cmdargs.CosignersSeparator+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true "run main", - "loadgo "+filename+" 0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true + "loadgo "+filename+" "+cmdargs.CosignersSeparator+" "+"0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true "run main") e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkStack(t, true) @@ -467,7 +491,7 @@ go 1.18`) t.Run("nonwitnessed signer", func(t *testing.T) { e := newTestVMCLI(t) e.runProg(t, - "loadgo "+filename+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false + "loadgo "+filename+" "+cmdargs.CosignersSeparator+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false "run main") e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkStack(t, false) @@ -1153,24 +1177,27 @@ func TestLoaddeployed(t *testing.T) { "run get 1", "loaddeployed --gas 420000 "+h.StringLE(), // gas-limited "run get 1", - "loaddeployed 0x"+h.StringLE(), // hash LE with 0x prefix + "loaddeployed "+"0x"+h.StringLE(), // hash LE with 0x prefix "run get 1", "loaddeployed 1", // contract ID "run get 1", "loaddeployed --historic 2 1", // historic state, check that hash is properly set "run get 1", // Check signers parsing: - "loaddeployed 2 "+ownerAddress, // check witness (owner:DefautScope => true) + "loaddeployed 2 "+cmdargs.CosignersSeparator, + "loaddeployed 2 "+"not-a-separator", + "loaddeployed 2 "+cmdargs.CosignersSeparator+" not-a-signer", + "loaddeployed 2 "+cmdargs.CosignersSeparator+" "+ownerAddress, // check witness (owner:DefautScope => true) "run checkWitness", - "loaddeployed 2 "+ownerAddress+":None", // check witness (owner:None => false) + "loaddeployed 2 "+cmdargs.CosignersSeparator+" "+ownerAddress+":None", // check witness (owner:None => false) "run checkWitness", - "loaddeployed 2 "+ownerAddress+":CalledByEntry", // check witness (owner:CalledByEntry => true) + "loaddeployed 2 "+cmdargs.CosignersSeparator+" "+ownerAddress+":CalledByEntry", // check witness (owner:CalledByEntry => true) "run checkWitness", - "loaddeployed 2 "+ownerAcc.StringLE()+":CalledByEntry", // check witness (ownerLE:CalledByEntry => true) + "loaddeployed 2 "+cmdargs.CosignersSeparator+" "+ownerAcc.StringLE()+":CalledByEntry", // check witness (ownerLE:CalledByEntry => true) "run checkWitness", - "loaddeployed 2 0x"+ownerAcc.StringLE()+":CalledByEntry", // check witness (owner0xLE:CalledByEntry => true) + "loaddeployed 2 "+cmdargs.CosignersSeparator+" "+"0x"+ownerAcc.StringLE()+":CalledByEntry", // check witness (owner0xLE:CalledByEntry => true) "run checkWitness", - "loaddeployed 2 "+sideAcc.StringLE()+":Global", // check witness (sideLE:Global => false) + "loaddeployed 2 "+cmdargs.CosignersSeparator+" "+sideAcc.StringLE()+":Global", // check witness (sideLE:Global => false) "run checkWitness", "loaddeployed", // missing argument "exit", @@ -1186,6 +1213,9 @@ func TestLoaddeployed(t *testing.T) { e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkStack(t, []byte{1}) // Check signers parsing: + e.checkError(t, ErrInvalidParameter) + e.checkError(t, ErrInvalidParameter) + e.checkError(t, ErrInvalidParameter) e.checkNextLine(t, "READY: loaded \\d+ instructions") // check witness of owner:DefaultScope e.checkStack(t, true) e.checkNextLine(t, "READY: loaded \\d+ instructions") // check witness of owner:None