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:
Anna Shaleva 2022-10-11 14:59:51 +03:00
parent 4dbaf2a123
commit d09a0c18a7
4 changed files with 311 additions and 97 deletions

View file

@ -96,22 +96,73 @@ 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:] {
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, cli.NewExitError(fmt.Errorf("failed to parse signer #%d: %w", i, err), 1)
return nil, fmt.Errorf("failed to parse signer #%d: %w", i, err)
}
signers = append(signers, cosigner)
}
}
return signers, nil
}

View file

@ -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,

View file

@ -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)

View file

@ -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"))
}