mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-22 19:19:09 +00:00
cli: unify signers parsing
Share signers parsing code between 'contract invokefunction' and 'vm load*' commands, quite a useful thing when it comes to witness checks.
This commit is contained in:
parent
4dbaf2a123
commit
d09a0c18a7
4 changed files with 311 additions and 97 deletions
|
@ -96,25 +96,76 @@ const (
|
|||
* '[ a b [ c d ] e ]' is an array with 4 values: string 'a', string 'b',
|
||||
array of two strings 'c' and 'd', string 'e'
|
||||
* '[ ]' is an empty array`
|
||||
|
||||
// SignersParsingDoc is a documentation for signers parsing.
|
||||
SignersParsingDoc = ` Signers represent a set of Uint160 hashes with witness scopes and are used
|
||||
to verify hashes in System.Runtime.CheckWitness syscall. First signer is treated
|
||||
as a sender. To specify signers use signer[:scope] syntax where
|
||||
* 'signer' is a signer's address (as Neo address or hex-encoded 160 bit (20 byte)
|
||||
LE value with or without '0x' prefix).
|
||||
* 'scope' is a comma-separated set of cosigner's scopes, which could be:
|
||||
- 'None' - default witness scope which may be used for the sender
|
||||
to only pay fee for the transaction.
|
||||
- 'Global' - allows this witness in all contexts. This cannot be combined
|
||||
with other flags.
|
||||
- 'CalledByEntry' - means that this condition must hold: EntryScriptHash
|
||||
== CallingScriptHash. The witness/permission/signature
|
||||
given on first invocation will automatically expire if
|
||||
entering deeper internal invokes. This can be default
|
||||
safe choice for native NEO/GAS.
|
||||
- 'CustomContracts' - define valid custom contract hashes for witness check.
|
||||
Hashes are be provided as hex-encoded LE value string.
|
||||
At lest one hash must be provided. Multiple hashes
|
||||
are separated by ':'.
|
||||
- 'CustomGroups' - define custom public keys for group members. Public keys are
|
||||
provided as short-form (1-byte prefix + 32 bytes) hex-encoded
|
||||
values. At least one key must be provided. Multiple keys
|
||||
are separated by ':'.
|
||||
|
||||
If no scopes were specified, 'CalledByEntry' used as default. If no signers were
|
||||
specified, no array is passed. Note that scopes are properly handled by
|
||||
neo-go RPC server only. C# implementation does not support scopes capability.
|
||||
|
||||
Examples:
|
||||
* 'NNQk4QXsxvsrr3GSozoWBUxEmfag7B6hz5'
|
||||
* 'NVquyZHoPirw6zAEPvY1ZezxM493zMWQqs:Global'
|
||||
* '0x0000000009070e030d0f0e020d0c06050e030c02'
|
||||
* '0000000009070e030d0f0e020d0c06050e030c02:CalledByEntry,` +
|
||||
`CustomGroups:0206d7495ceb34c197093b5fc1cccf1996ada05e69ef67e765462a7f5d88ee14d0'
|
||||
* '0000000009070e030d0f0e020d0c06050e030c02:CalledByEntry,` +
|
||||
`CustomContracts:1011120009070e030d0f0e020d0c06050e030c02:0x1211100009070e030d0f0e020d0c06050e030c02'`
|
||||
)
|
||||
|
||||
// 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
|
||||
var (
|
||||
signers []transaction.Signer
|
||||
err error
|
||||
)
|
||||
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)
|
||||
signers, err = ParseSigners(args[offset:])
|
||||
if err != nil {
|
||||
return nil, cli.NewExitError(err, 1)
|
||||
}
|
||||
}
|
||||
return signers, nil
|
||||
}
|
||||
|
||||
// ParseSigners returns array of signers parsed from their string representation.
|
||||
func ParseSigners(args []string) ([]transaction.Signer, error) {
|
||||
var signers []transaction.Signer
|
||||
for i, c := range args {
|
||||
cosigner, err := parseCosigner(c)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse signer #%d: %w", i, err)
|
||||
}
|
||||
signers = append(signers, cosigner)
|
||||
}
|
||||
return signers, nil
|
||||
}
|
||||
|
||||
func parseCosigner(c string) (transaction.Signer, error) {
|
||||
var (
|
||||
err error
|
||||
|
|
|
@ -211,42 +211,7 @@ func NewCommands() []cli.Command {
|
|||
|
||||
` + cmdargs.ParamsParsingDoc + `
|
||||
|
||||
Signers represent a set of Uint160 hashes with witness scopes and are used
|
||||
to verify hashes in System.Runtime.CheckWitness syscall. First signer is treated
|
||||
as a sender. To specify signers use signer[:scope] syntax where
|
||||
* 'signer' is a signer's address (as Neo address or hex-encoded 160 bit (20 byte)
|
||||
LE value with or without '0x' prefix).
|
||||
* 'scope' is a comma-separated set of cosigner's scopes, which could be:
|
||||
- 'None' - default witness scope which may be used for the sender
|
||||
to only pay fee for the transaction.
|
||||
- 'Global' - allows this witness in all contexts. This cannot be combined
|
||||
with other flags.
|
||||
- 'CalledByEntry' - means that this condition must hold: EntryScriptHash
|
||||
== CallingScriptHash. The witness/permission/signature
|
||||
given on first invocation will automatically expire if
|
||||
entering deeper internal invokes. This can be default
|
||||
safe choice for native NEO/GAS.
|
||||
- 'CustomContracts' - define valid custom contract hashes for witness check.
|
||||
Hashes are be provided as hex-encoded LE value string.
|
||||
At lest one hash must be provided. Multiple hashes
|
||||
are separated by ':'.
|
||||
- 'CustomGroups' - define custom public keys for group members. Public keys are
|
||||
provided as short-form (1-byte prefix + 32 bytes) hex-encoded
|
||||
values. At least one key must be provided. Multiple keys
|
||||
are separated by ':'.
|
||||
|
||||
If no scopes were specified, 'CalledByEntry' used as default. If no signers were
|
||||
specified, no array is passed. Note that scopes are properly handled by
|
||||
neo-go RPC server only. C# implementation does not support scopes capability.
|
||||
|
||||
Examples:
|
||||
* 'NNQk4QXsxvsrr3GSozoWBUxEmfag7B6hz5'
|
||||
* 'NVquyZHoPirw6zAEPvY1ZezxM493zMWQqs:Global'
|
||||
* '0x0000000009070e030d0f0e020d0c06050e030c02'
|
||||
* '0000000009070e030d0f0e020d0c06050e030c02:CalledByEntry,` +
|
||||
`CustomGroups:0206d7495ceb34c197093b5fc1cccf1996ada05e69ef67e765462a7f5d88ee14d0'
|
||||
* '0000000009070e030d0f0e020d0c06050e030c02:CalledByEntry,` +
|
||||
`CustomContracts:1011120009070e030d0f0e020d0c06050e030c02:0x1211100009070e030d0f0e020d0c06050e030c02'
|
||||
` + cmdargs.SignersParsingDoc + `
|
||||
`,
|
||||
Action: testInvokeFunction,
|
||||
Flags: testInvokeFunctionFlags,
|
||||
|
|
165
cli/vm/cli.go
165
cli/vm/cli.go
|
@ -35,6 +35,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
"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/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
||||
|
@ -123,44 +124,57 @@ var commands = []cli.Command{
|
|||
},
|
||||
{
|
||||
Name: "loadnef",
|
||||
Usage: "Load a NEF-consistent script into the VM",
|
||||
UsageText: `loadnef <file> <manifest>`,
|
||||
Usage: "Load a NEF-consistent script into the VM optionally attaching to it provided signers with scopes",
|
||||
UsageText: `loadnef <file> <manifest> [<signer-with-scope>, ...]`,
|
||||
Flags: []cli.Flag{historicFlag},
|
||||
Description: `loadnef [--historic <height>] <file> <manifest>
|
||||
both parameters are mandatory, example:
|
||||
Description: `loadnef [--historic <height>] <file> <manifest> [<signer-with-scope>, ...]
|
||||
|
||||
<file> and <manifest> parameters are mandatory.
|
||||
` + cmdargs.SignersParsingDoc + `
|
||||
|
||||
Example:
|
||||
> loadnef /path/to/script.nef /path/to/manifest.json`,
|
||||
Action: handleLoadNEF,
|
||||
},
|
||||
{
|
||||
Name: "loadbase64",
|
||||
Usage: "Load a base64-encoded script string into the VM",
|
||||
UsageText: `loadbase64 [--historic <height>] <string>`,
|
||||
Usage: "Load a base64-encoded script string into the VM optionally attaching to it provided signers with scopes",
|
||||
UsageText: `loadbase64 [--historic <height>] <string> [<signer-with-scope>, ...]`,
|
||||
Flags: []cli.Flag{historicFlag},
|
||||
Description: `loadbase64 [--historic <height>] <string>
|
||||
Description: `loadbase64 [--historic <height>] <string> [<signer-with-scope>, ...]
|
||||
|
||||
<string> is mandatory parameter, example:
|
||||
<string> is mandatory parameter.
|
||||
` + cmdargs.SignersParsingDoc + `
|
||||
|
||||
Example:
|
||||
> loadbase64 AwAQpdToAAAADBQV9ehtQR1OrVZVhtHtoUHRfoE+agwUzmFvf3Rhfg/EuAVYOvJgKiON9j8TwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I4`,
|
||||
Action: handleLoadBase64,
|
||||
},
|
||||
{
|
||||
Name: "loadhex",
|
||||
Usage: "Load a hex-encoded script string into the VM",
|
||||
UsageText: `loadhex [--historic <height>] <string>`,
|
||||
Usage: "Load a hex-encoded script string into the VM optionally attaching to it provided signers with scopes",
|
||||
UsageText: `loadhex [--historic <height>] <string> [<signer-with-scope>, ...]`,
|
||||
Flags: []cli.Flag{historicFlag},
|
||||
Description: `loadhex [--historic <height>] <string>
|
||||
Description: `loadhex [--historic <height>] <string> [<signer-with-scope>, ...]
|
||||
|
||||
<string> is mandatory parameter, example:
|
||||
<string> is mandatory parameter.
|
||||
` + cmdargs.SignersParsingDoc + `
|
||||
|
||||
Example:
|
||||
> loadhex 0c0c48656c6c6f20776f726c6421`,
|
||||
Action: handleLoadHex,
|
||||
},
|
||||
{
|
||||
Name: "loadgo",
|
||||
Usage: "Compile and load a Go file with the manifest into the VM",
|
||||
UsageText: `loadgo [--historic <height>] <file>`,
|
||||
Usage: "Compile and load a Go file with the manifest into the VM optionally attaching to it provided signers with scopes",
|
||||
UsageText: `loadgo [--historic <height>] <file> [<signer-with-scope>, ...]`,
|
||||
Flags: []cli.Flag{historicFlag},
|
||||
Description: `loadgo [--historic <height>] <file>
|
||||
Description: `loadgo [--historic <height>] <file> [<signer-with-scope>, ...]
|
||||
|
||||
<file> is mandatory parameter, example:
|
||||
<file> is mandatory parameter.
|
||||
` + cmdargs.SignersParsingDoc + `
|
||||
|
||||
Example:
|
||||
> loadgo /path/to/file.go`,
|
||||
Action: handleLoadGo,
|
||||
},
|
||||
|
@ -181,14 +195,18 @@ The transaction script will be loaded into VM; the resulting execution context w
|
|||
},
|
||||
{
|
||||
Name: "loaddeployed",
|
||||
Usage: "Load deployed contract into the VM from chain. If '--historic' flag specified, then the historic contract state (historic script and manifest) will be loaded.",
|
||||
UsageText: `loaddeployed [--historic <height>] <hash-or-address-or-id>`,
|
||||
Usage: "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.",
|
||||
UsageText: `loaddeployed [--historic <height>] <hash-or-address-or-id> [<signer-with-scope>, ...]`,
|
||||
Flags: []cli.Flag{historicFlag},
|
||||
Description: `loaddeployed [--historic <height>] <hash-or-address-or-id>
|
||||
Description: `loaddeployed [--historic <height>] <hash-or-address-or-id> [<signer-with-scope>, ...]
|
||||
|
||||
Load deployed contract into the VM from chain. If '--historic' flag specified, then the historic contract state (historic script and manifest) will be loaded.
|
||||
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.
|
||||
|
||||
<hash-or-address-or-id> is mandatory parameter, example:
|
||||
<hash-or-address-or-id> is mandatory parameter.
|
||||
` + cmdargs.SignersParsingDoc + `
|
||||
|
||||
Example:
|
||||
> loaddeployed 0x0000000009070e030d0f0e020d0c06050e030c02`,
|
||||
Action: handleLoadDeployed,
|
||||
},
|
||||
|
@ -604,22 +622,35 @@ func prepareVM(c *cli.Context, tx *transaction.Transaction) error {
|
|||
}
|
||||
|
||||
func handleLoadNEF(c *cli.Context) error {
|
||||
err := prepareVM(c, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
args := c.Args()
|
||||
if len(args) < 2 {
|
||||
return fmt.Errorf("%w: <file> <manifest>", ErrMissingParameter)
|
||||
}
|
||||
if err := v.LoadFileWithFlags(args[0], callflag.All); err != nil {
|
||||
return fmt.Errorf("failed to read nef: %w", err)
|
||||
b, err := os.ReadFile(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nef, err := nef.FileFromBytes(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode NEF file: %w", err)
|
||||
}
|
||||
m, err := getManifestFromFile(args[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read manifest: %w", err)
|
||||
}
|
||||
var signers []transaction.Signer
|
||||
if len(args) > 2 {
|
||||
signers, err = cmdargs.ParseSigners(c.Args()[2:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %v", ErrInvalidParameter, err)
|
||||
}
|
||||
}
|
||||
err = prepareVM(c, createFakeTransaction(nef.Script, signers))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
v.LoadWithFlags(nef.Script, callflag.All)
|
||||
fmt.Fprintf(c.App.Writer, "READY: loaded %d instructions\n", v.Context().LenInstr())
|
||||
setManifestInContext(c.App, m)
|
||||
changePrompt(c.App)
|
||||
|
@ -627,11 +658,6 @@ func handleLoadNEF(c *cli.Context) error {
|
|||
}
|
||||
|
||||
func handleLoadBase64(c *cli.Context) error {
|
||||
err := prepareVM(c, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
args := c.Args()
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("%w: <string>", ErrMissingParameter)
|
||||
|
@ -640,18 +666,33 @@ func handleLoadBase64(c *cli.Context) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrInvalidParameter, err)
|
||||
}
|
||||
var signers []transaction.Signer
|
||||
if len(args) > 1 {
|
||||
signers, err = cmdargs.ParseSigners(args[1:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %v", ErrInvalidParameter, err)
|
||||
}
|
||||
}
|
||||
err = prepareVM(c, createFakeTransaction(b, signers))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
v.LoadWithFlags(b, callflag.All)
|
||||
fmt.Fprintf(c.App.Writer, "READY: loaded %d instructions\n", v.Context().LenInstr())
|
||||
changePrompt(c.App)
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleLoadHex(c *cli.Context) error {
|
||||
err := prepareVM(c, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
// createFakeTransaction creates fake transaction with prefilled script, VUB and signers.
|
||||
func createFakeTransaction(script []byte, signers []transaction.Signer) *transaction.Transaction {
|
||||
return &transaction.Transaction{
|
||||
Script: script,
|
||||
Signers: signers,
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
}
|
||||
|
||||
func handleLoadHex(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("%w: <string>", ErrMissingParameter)
|
||||
|
@ -660,6 +701,18 @@ func handleLoadHex(c *cli.Context) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrInvalidParameter, err)
|
||||
}
|
||||
var signers []transaction.Signer
|
||||
if len(args) > 1 {
|
||||
signers, err = cmdargs.ParseSigners(args[1:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %v", ErrInvalidParameter, err)
|
||||
}
|
||||
}
|
||||
err = prepareVM(c, createFakeTransaction(b, signers))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
v.LoadWithFlags(b, callflag.All)
|
||||
fmt.Fprintf(c.App.Writer, "READY: loaded %d instructions\n", v.Context().LenInstr())
|
||||
changePrompt(c.App)
|
||||
|
@ -667,11 +720,6 @@ func handleLoadHex(c *cli.Context) error {
|
|||
}
|
||||
|
||||
func handleLoadGo(c *cli.Context) error {
|
||||
err := prepareVM(c, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
args := c.Args()
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("%w: <file>", ErrMissingParameter)
|
||||
|
@ -688,8 +736,20 @@ func handleLoadGo(c *cli.Context) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("can't create manifest: %w", err)
|
||||
}
|
||||
setManifestInContext(c.App, m)
|
||||
var signers []transaction.Signer
|
||||
if len(args) > 1 {
|
||||
signers, err = cmdargs.ParseSigners(args[1:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %v", ErrInvalidParameter, err)
|
||||
}
|
||||
}
|
||||
|
||||
err = prepareVM(c, createFakeTransaction(b.Script, signers))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
setManifestInContext(c.App, m)
|
||||
v.LoadWithFlags(b.Script, callflag.All)
|
||||
fmt.Fprintf(c.App.Writer, "READY: loaded %d instructions\n", v.Context().LenInstr())
|
||||
changePrompt(c.App)
|
||||
|
@ -763,6 +823,17 @@ func handleLoadDeployed(c *cli.Context) error {
|
|||
return fmt.Errorf("contract %s not found: %w", h.StringLE(), err)
|
||||
}
|
||||
|
||||
var signers []transaction.Signer
|
||||
if len(c.Args()) > 1 {
|
||||
signers, err = cmdargs.ParseSigners(c.Args()[1:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %v", ErrInvalidParameter, err)
|
||||
}
|
||||
}
|
||||
err = prepareVM(c, createFakeTransaction(cs.NEF.Script, signers)) // prepare VM one more time for proper IC initialization.
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
v.LoadScriptWithHash(cs.NEF.Script, h, callflag.All)
|
||||
fmt.Fprintf(c.App.Writer, "READY: loaded %d instructions\n", v.Context().LenInstr())
|
||||
|
@ -796,11 +867,17 @@ func resetInteropContext(app *cli.App, tx *transaction.Transaction, height ...ui
|
|||
err error
|
||||
)
|
||||
if len(height) != 0 {
|
||||
if tx != nil {
|
||||
tx.ValidUntilBlock = height[0] + 1
|
||||
}
|
||||
newIc, err = bc.GetTestHistoricVM(trigger.Application, tx, height[0]+1)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create historic VM for height %d: %w", height[0], err)
|
||||
}
|
||||
} else {
|
||||
if tx != nil {
|
||||
tx.ValidUntilBlock = bc.BlockHeight() + 1
|
||||
}
|
||||
newIc, err = bc.GetTestVM(trigger.Application, tx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create VM: %w", err)
|
||||
|
|
|
@ -281,27 +281,79 @@ func (e *executor) checkSlot(t *testing.T, items ...interface{}) {
|
|||
|
||||
func TestLoad(t *testing.T) {
|
||||
script := []byte{byte(opcode.PUSH3), byte(opcode.PUSH4), byte(opcode.ADD)}
|
||||
|
||||
ownerAddress := "NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB"
|
||||
ownerAcc, err := address.StringToUint160(ownerAddress)
|
||||
require.NoError(t, err)
|
||||
sideAcc := util.Uint160{1, 2, 3}
|
||||
buff := io.NewBufBinWriter()
|
||||
emit.Bytes(buff.BinWriter, ownerAcc.BytesBE())
|
||||
emit.Syscall(buff.BinWriter, interopnames.SystemRuntimeCheckWitness)
|
||||
checkWitnessScript := buff.Bytes()
|
||||
|
||||
t.Run("loadhex", func(t *testing.T) {
|
||||
e := newTestVMCLI(t)
|
||||
e.runProg(t,
|
||||
"loadhex",
|
||||
"loadhex notahex",
|
||||
"loadhex "+hex.EncodeToString(script))
|
||||
"loadhex "+hex.EncodeToString(script),
|
||||
"loadhex "+hex.EncodeToString(checkWitnessScript)+" "+ownerAddress, // owner:DefaultScope => true
|
||||
"run",
|
||||
"loadhex "+hex.EncodeToString(checkWitnessScript)+" "+ownerAddress+":None", // owner:None => false
|
||||
"run",
|
||||
"loadhex "+hex.EncodeToString(checkWitnessScript)+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true
|
||||
"run",
|
||||
"loadhex "+hex.EncodeToString(checkWitnessScript)+" 0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true
|
||||
"run",
|
||||
"loadhex "+hex.EncodeToString(checkWitnessScript)+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false
|
||||
"run",
|
||||
)
|
||||
|
||||
e.checkError(t, ErrMissingParameter)
|
||||
e.checkError(t, ErrInvalidParameter)
|
||||
e.checkNextLine(t, "READY: loaded 3 instructions")
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, true)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, false)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, true)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, true)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, false)
|
||||
})
|
||||
t.Run("loadbase64", func(t *testing.T) {
|
||||
e := newTestVMCLI(t)
|
||||
e.runProg(t,
|
||||
"loadbase64",
|
||||
"loadbase64 not_a_base64",
|
||||
"loadbase64 "+base64.StdEncoding.EncodeToString(script))
|
||||
"loadbase64 "+base64.StdEncoding.EncodeToString(script),
|
||||
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+ownerAddress, // owner:DefaultScope => true
|
||||
"run",
|
||||
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+ownerAddress+":None", // owner:None => false
|
||||
"run",
|
||||
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true
|
||||
"run",
|
||||
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" 0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true
|
||||
"run",
|
||||
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false
|
||||
"run",
|
||||
)
|
||||
|
||||
e.checkError(t, ErrMissingParameter)
|
||||
e.checkError(t, ErrInvalidParameter)
|
||||
e.checkNextLine(t, "READY: loaded 3 instructions")
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, true)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, false)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, true)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, true)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, false)
|
||||
})
|
||||
|
||||
src := `package kek
|
||||
|
@ -343,14 +395,7 @@ go 1.17`)
|
|||
checkLoadgo(t, "simple", "vmtestcontract.go", "vmtestcontract_err.go")
|
||||
checkLoadgo(t, "utf-8 with spaces", "тестовый контракт.go", "тестовый контракт с ошибкой.go")
|
||||
|
||||
t.Run("loadgo, check calling flags", func(t *testing.T) {
|
||||
srcAllowNotify := `package kek
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||
func Main() int {
|
||||
runtime.Log("Hello, world!")
|
||||
return 1
|
||||
}
|
||||
`
|
||||
prepareLoadgoSrc := func(t *testing.T, srcAllowNotify string) string {
|
||||
filename := filepath.Join(tmpDir, "vmtestcontract.go")
|
||||
require.NoError(t, os.WriteFile(filename, []byte(srcAllowNotify), os.ModePerm))
|
||||
filename = "'" + filename + "'"
|
||||
|
@ -363,6 +408,17 @@ require (
|
|||
replace github.com/nspcc-dev/neo-go/pkg/interop => ` + filepath.Join(wd, "../../pkg/interop") + `
|
||||
go 1.17`)
|
||||
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "go.mod"), goMod, os.ModePerm))
|
||||
return filename
|
||||
}
|
||||
t.Run("loadgo, check calling flags", func(t *testing.T) {
|
||||
srcAllowNotify := `package kek
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||
func Main() int {
|
||||
runtime.Log("Hello, world!")
|
||||
return 1
|
||||
}
|
||||
`
|
||||
filename := prepareLoadgoSrc(t, srcAllowNotify)
|
||||
|
||||
e := newTestVMCLI(t)
|
||||
e.runProg(t,
|
||||
|
@ -371,6 +427,41 @@ go 1.17`)
|
|||
e.checkNextLine(t, "READY: loaded \\d* instructions")
|
||||
e.checkStack(t, 1)
|
||||
})
|
||||
t.Run("loadgo, check signers", func(t *testing.T) {
|
||||
srcCheckWitness := `package kek
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/util"
|
||||
)
|
||||
func Main() bool {
|
||||
var owner = util.FromAddress("` + ownerAddress + `")
|
||||
return runtime.CheckWitness(owner)
|
||||
}
|
||||
`
|
||||
filename := prepareLoadgoSrc(t, srcCheckWitness)
|
||||
e := newTestVMCLI(t)
|
||||
e.runProg(t,
|
||||
"loadgo "+filename+" "+ownerAddress, // owner:DefaultScope => true
|
||||
"run main",
|
||||
"loadgo "+filename+" "+ownerAddress+":None", // owner:None => false
|
||||
"run main",
|
||||
"loadgo "+filename+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true
|
||||
"run main",
|
||||
"loadgo "+filename+" 0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true
|
||||
"run main",
|
||||
"loadgo "+filename+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false
|
||||
"run main")
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, true)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, false)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, true)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, true)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, false)
|
||||
})
|
||||
t.Run("loadnef", func(t *testing.T) {
|
||||
config.Version = "0.92.0-test"
|
||||
|
||||
|
@ -1037,6 +1128,10 @@ func TestLoaddeployed(t *testing.T) {
|
|||
|
||||
h, err := e.cli.chain.GetContractScriptHash(1) // examples/storage/storage.go
|
||||
require.NoError(t, err)
|
||||
ownerAddress := "NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB" // owner of examples/runtime/runtime.go (taken from deployed contract with ID=2)
|
||||
ownerAcc, err := address.StringToUint160(ownerAddress)
|
||||
require.NoError(t, err)
|
||||
sideAcc := util.Uint160{1, 2, 3}
|
||||
|
||||
e.runProg(t,
|
||||
"loaddeployed "+h.StringLE(), // hash LE
|
||||
|
@ -1047,6 +1142,19 @@ func TestLoaddeployed(t *testing.T) {
|
|||
"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)
|
||||
"run checkWitness",
|
||||
"loaddeployed 2 "+ownerAddress+":None", // check witness (owner:None => false)
|
||||
"run checkWitness",
|
||||
"loaddeployed 2 "+ownerAddress+":CalledByEntry", // check witness (owner:CalledByEntry => true)
|
||||
"run checkWitness",
|
||||
"loaddeployed 2 "+ownerAcc.StringLE()+":CalledByEntry", // check witness (ownerLE:CalledByEntry => true)
|
||||
"run checkWitness",
|
||||
"loaddeployed 2 0x"+ownerAcc.StringLE()+":CalledByEntry", // check witness (owner0xLE:CalledByEntry => true)
|
||||
"run checkWitness",
|
||||
"loaddeployed 2 "+sideAcc.StringLE()+":Global", // check witness (sideLE:Global => false)
|
||||
"run checkWitness",
|
||||
"loaddeployed", // missing argument
|
||||
"exit",
|
||||
)
|
||||
|
@ -1058,5 +1166,18 @@ func TestLoaddeployed(t *testing.T) {
|
|||
e.checkStack(t, []byte{2})
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions")
|
||||
e.checkStack(t, []byte{1})
|
||||
// Check signers parsing:
|
||||
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
|
||||
e.checkStack(t, false)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions") // check witness of owner:CalledByEntry
|
||||
e.checkStack(t, true)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions") // check witness of ownerLE:CalledByEntry
|
||||
e.checkStack(t, true)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions") // check witness of owner0xLE:CalledByEntry
|
||||
e.checkStack(t, true)
|
||||
e.checkNextLine(t, "READY: loaded \\d+ instructions") // check witness of owner0xLE:CalledByEntry
|
||||
e.checkStack(t, false)
|
||||
e.checkError(t, errors.New("contract hash, address or ID is mandatory argument"))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue