diff --git a/pkg/core/interop/runtime/engine.go b/pkg/core/interop/runtime/engine.go index 95eadc05e..4735a3056 100644 --- a/pkg/core/interop/runtime/engine.go +++ b/pkg/core/interop/runtime/engine.go @@ -52,11 +52,11 @@ func GetTrigger(ic *interop.Context) error { // in neo-go the only meaningful thing to do here is to log. func Notify(ic *interop.Context) error { name := ic.VM.Estack().Pop().String() + elem := ic.VM.Estack().Pop() + args := elem.Array() if len(name) > MaxEventNameLen { return fmt.Errorf("event name must be less than %d", MaxEventNameLen) } - elem := ic.VM.Estack().Pop() - args := elem.Array() // But it has to be serializable, otherwise we either have some broken // (recursive) structure inside or an interop item that can't be used // outside of the interop subsystem anyway. diff --git a/pkg/core/interop/runtime/engine_test.go b/pkg/core/interop/runtime/engine_test.go index 87618e00d..27a2e98f9 100644 --- a/pkg/core/interop/runtime/engine_test.go +++ b/pkg/core/interop/runtime/engine_test.go @@ -142,7 +142,7 @@ func TestNotify(t *testing.T) { return ic } t.Run("big name", func(t *testing.T) { - ic := newIC(string(make([]byte, MaxEventNameLen+1)), []byte{42}) + ic := newIC(string(make([]byte, MaxEventNameLen+1)), stackitem.NewArray([]stackitem.Item{stackitem.Null{}})) require.Error(t, Notify(ic)) }) t.Run("recursive struct", func(t *testing.T) { diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index 2c887cb86..6391167ca 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -1304,7 +1304,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro interopID := GetInteropID(parameter) err := v.SyscallHandler(v, interopID) if err != nil { - panic(fmt.Sprintf("failed to invoke syscall: %s", err)) + panic(fmt.Sprintf("failed to invoke syscall %d: %s", interopID, err)) } case opcode.RET: @@ -1602,8 +1602,32 @@ func (v *VM) handleException() { } pop++ ictxv = ictxv.Next() + if ictxv == nil { + break + } ictx = ictxv.Value().(*Context) } + throwUnhandledException(v.uncaughtException) +} + +// throwUnhandledException gets exception message from the provided stackitem and panics. +func throwUnhandledException(item stackitem.Item) { + msg := "unhandled exception" + switch item.Type() { + case stackitem.ArrayT: + if arr := item.Value().([]stackitem.Item); len(arr) > 0 { + data, err := arr[0].TryBytes() + if err == nil { + msg = fmt.Sprintf("%s: %q", msg, string(data)) + } + } + default: + data, err := item.TryBytes() + if err == nil { + msg = fmt.Sprintf("%s: %q", msg, string(data)) + } + } + panic(msg) } // CheckMultisigPar checks if sigs contains sufficient valid signatures.