From 318ca559824121714dd04864ee14292d3a24f270 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 21 May 2020 12:13:52 +0300 Subject: [PATCH 1/3] vm/cli: add push command to push something to the estack --- pkg/vm/cli/cli.go | 98 +++++++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/pkg/vm/cli/cli.go b/pkg/vm/cli/cli.go index 2cef728fe..acbac0367 100644 --- a/pkg/vm/cli/cli.go +++ b/pkg/vm/cli/cli.go @@ -87,6 +87,16 @@ var commands = []*ishell.Cmd{ > load /path/to/file.go`, Func: handleLoadGo, }, + { + Name: "push", + Help: "Push given item to the estack", + LongHelp: `Usage: push + is mandatory, example: +> push methodstring + +See run command help for parameter syntax.`, + Func: handlePush, + }, { Name: "run", Help: "Execute the current loaded script", @@ -270,6 +280,20 @@ func handleLoadGo(c *ishell.Context) { changePrompt(c, v) } +func handlePush(c *ishell.Context) { + v := getVMFromContext(c) + if len(c.Args) == 0 { + c.Err(errors.New("missing parameter")) + return + } + param, err := parseArg(c.Args[0]) + if err != nil { + c.Err(err) + return + } + v.Estack().PushVal(param) +} + func handleRun(c *ishell.Context) { v := getVMFromContext(c) if len(c.Args) != 0 { @@ -408,43 +432,53 @@ func isMethodArg(s string) bool { func parseArgs(args []string) ([]vm.StackItem, error) { items := make([]vm.StackItem, len(args)) for i, arg := range args { - var typ, value string - typeAndVal := strings.Split(arg, ":") - if len(typeAndVal) < 2 { - if typeAndVal[0] == boolFalse || typeAndVal[0] == boolTrue { - typ = boolType - } else if _, err := strconv.Atoi(typeAndVal[0]); err == nil { - typ = intType - } else { - typ = stringType - } - value = typeAndVal[0] - } else { - typ = typeAndVal[0] - value = typeAndVal[1] + item, err := parseArg(arg) + if err != nil { + return nil, err } + items[i] = item + } + return items, nil +} - switch typ { - case boolType: - if value == boolFalse { - items[i] = vm.NewBoolItem(false) - } else if value == boolTrue { - items[i] = vm.NewBoolItem(true) - } else { - return nil, errors.New("failed to parse bool parameter") - } - case intType: - val, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return nil, err - } - items[i] = vm.NewBigIntegerItem(val) - case stringType: - items[i] = vm.NewByteArrayItem([]byte(value)) +func parseArg(arg string) (vm.StackItem, error) { + var typ, value string + var item vm.StackItem + + typeAndVal := strings.Split(arg, ":") + if len(typeAndVal) < 2 { + if typeAndVal[0] == boolFalse || typeAndVal[0] == boolTrue { + typ = boolType + } else if _, err := strconv.Atoi(typeAndVal[0]); err == nil { + typ = intType + } else { + typ = stringType } + value = typeAndVal[0] + } else { + typ = typeAndVal[0] + value = typeAndVal[1] } - return items, nil + switch typ { + case boolType: + if value == boolFalse { + item = vm.NewBoolItem(false) + } else if value == boolTrue { + item = vm.NewBoolItem(true) + } else { + return nil, errors.New("failed to parse bool parameter") + } + case intType: + val, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return nil, err + } + item = vm.NewBigIntegerItem(val) + case stringType: + item = vm.NewByteArrayItem([]byte(value)) + } + return item, nil } func printLogo(c *ishell.Shell) { From 328c6d7ce589a8d8dd28d00956daae500c9c01f2 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 21 May 2020 12:15:50 +0300 Subject: [PATCH 2/3] vm/cli: fix step command It was setting a (wrong) breakpoint and couldn't then break out of it. --- pkg/vm/cli/cli.go | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/pkg/vm/cli/cli.go b/pkg/vm/cli/cli.go index acbac0367..f056e10d8 100644 --- a/pkg/vm/cli/cli.go +++ b/pkg/vm/cli/cli.go @@ -321,7 +321,13 @@ func runVMWithHandling(c *ishell.Context, v *vm.VM) { c.Err(err) return } + checkAndPrintVMState(c, v) +} +// checkAndPrintVMState checks VM state and outputs it to the user if it's +// failed, halted or at breakpoint. No message is printed if VM is running +// normally. +func checkAndPrintVMState(c *ishell.Context, v *vm.VM) { var message string switch { case v.HasFailed(): @@ -364,8 +370,17 @@ func handleStep(c *ishell.Context) { return } } - v.AddBreakPointRel(n) - runVMWithHandling(c, v) + for i := 0; i < n; i++ { + err := v.Step() + if err != nil { + c.Err(err) + return + } + checkAndPrintVMState(c, v) + } + ctx := v.Context() + i, op := ctx.CurrInstr() + c.Printf("at %d (%s)\n", i, op.String()) changePrompt(c, v) } From 1721360dd125dc92ba8aada5a8b55d9afa8a2d67 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 21 May 2020 12:16:38 +0300 Subject: [PATCH 3/3] vm: limit types accepted for PICKITEM, fix #965 bafdb916a0bd9a5408e7d98b95c1a038305a8773 change was wrong (probably brought from neo-vm 3.0 at the state at which it existed back then), neo-vm 2.x doesn't allow PICKITEM for arbitrary types. --- pkg/vm/vm.go | 7 +------ pkg/vm/vm_test.go | 4 +--- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index aeb8b0180..9a022e75a 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -1029,12 +1029,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro } v.estack.Push(&Element{value: t.value[index].Value.Dup()}) default: - arr := obj.Bytes() - if index < 0 || index >= len(arr) { - panic("PICKITEM: invalid index") - } - item := arr[index] - v.estack.PushVal(int(item)) + panic("PICKITEM: unknown type") } case opcode.SETITEM: diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index aab31a408..34c5ddab2 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -1367,9 +1367,7 @@ func TestPICKITEMByteArray(t *testing.T) { vm := load(prog) vm.estack.PushVal([]byte{1, 2}) vm.estack.PushVal(1) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(2), vm.estack.Pop().value) + checkVMFailed(t, vm) } func TestPICKITEMDupArray(t *testing.T) {