diff --git a/pkg/vm/interop.go b/pkg/vm/interop.go deleted file mode 100644 index 27156b31f..000000000 --- a/pkg/vm/interop.go +++ /dev/null @@ -1,66 +0,0 @@ -package vm - -import ( - "errors" - "fmt" - "sort" - - "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" - "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" -) - -// interopIDFuncPrice adds an ID to the InteropFuncPrice. -type interopIDFuncPrice struct { - ID uint32 - Func func(vm *VM) error - Price int64 - RequiredFlags callflag.CallFlag -} - -var defaultVMInterops = []interopIDFuncPrice{ - {ID: interopnames.ToID([]byte(interopnames.SystemRuntimeLog)), - Func: runtimeLog, Price: 1 << 15, RequiredFlags: callflag.AllowNotify}, - {ID: interopnames.ToID([]byte(interopnames.SystemRuntimeNotify)), - Func: runtimeNotify, Price: 1 << 15, RequiredFlags: callflag.AllowNotify}, -} - -func init() { - sort.Slice(defaultVMInterops, func(i, j int) bool { return defaultVMInterops[i].ID < defaultVMInterops[j].ID }) -} - -func defaultSyscallHandler(v *VM, id uint32) error { - n := sort.Search(len(defaultVMInterops), func(i int) bool { - return defaultVMInterops[i].ID >= id - }) - if n >= len(defaultVMInterops) || defaultVMInterops[n].ID != id { - return errors.New("syscall not found") - } - d := defaultVMInterops[n] - ctxFlag := v.Context().sc.callFlag - if !ctxFlag.Has(d.RequiredFlags) { - return fmt.Errorf("missing call flags: %05b vs %05b", ctxFlag, d.RequiredFlags) - } - return d.Func(v) -} - -// runtimeLog handles the syscall "System.Runtime.Log" for printing and logging stuff. -func runtimeLog(vm *VM) error { - msg := vm.Estack().Pop().String() - fmt.Printf("NEO-GO-VM (log) > %s\n", msg) - return nil -} - -// runtimeNotify handles the syscall "System.Runtime.Notify" for printing and logging stuff. -func runtimeNotify(vm *VM) error { - name := vm.Estack().Pop().String() - item := vm.Estack().Pop() - fmt.Printf("NEO-GO-VM (notify) > [%s] %s\n", name, item.Value()) - return nil -} - -// init sorts the global defaultVMInterops value. -func init() { - sort.Slice(defaultVMInterops, func(i, j int) bool { - return defaultVMInterops[i].ID < defaultVMInterops[j].ID - }) -} diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index 44e3f50d5..1e4f88df7 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -108,8 +108,6 @@ func NewWithTrigger(t trigger.Type) *VM { vm := &VM{ state: vmstate.None, trigger: t, - - SyscallHandler: defaultSyscallHandler, } initStack(&vm.istack, "invocation", nil) @@ -1458,6 +1456,9 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro case opcode.SYSCALL: interopID := GetInteropID(parameter) + if v.SyscallHandler == nil { + panic("vm's SyscallHandler is not initialized") + } err := v.SyscallHandler(v, interopID) if err != nil { panic(fmt.Sprintf("failed to invoke syscall %d: %s", interopID, err)) diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index e3bd59256..48807040f 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -17,6 +17,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" @@ -2747,6 +2748,19 @@ func TestRemoveReferrer(t *testing.T) { assert.Equal(t, 0, int(vm.refs)) } +func TestUninitializedSyscallHandler(t *testing.T) { + v := newTestVM() + v.Reset(trigger.Application) // Reset SyscallHandler. + id := make([]byte, 4) + binary.LittleEndian.PutUint32(id, interopnames.ToID([]byte(interopnames.SystemRuntimeGasLeft))) + script := append([]byte{byte(opcode.SYSCALL)}, id...) + v.LoadScript(script) + err := v.Run() + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "SyscallHandler is not initialized"), err.Error()) + assert.Equal(t, true, v.HasFailed()) +} + func makeProgram(opcodes ...opcode.Opcode) []byte { prog := make([]byte, len(opcodes)+1) // RET for i := 0; i < len(opcodes); i++ {