From a79c80cb8d9ac7f35f26383de3fb09842bd7adf5 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Thu, 26 May 2022 11:44:26 +0300 Subject: [PATCH] vm: wrap cross-contract exceptions --- pkg/core/interop/contract/call.go | 9 ++++++--- pkg/vm/vm.go | 6 +++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/pkg/core/interop/contract/call.go b/pkg/core/interop/contract/call.go index 64e3c6731..41f2f588f 100644 --- a/pkg/core/interop/contract/call.go +++ b/pkg/core/interop/contract/call.go @@ -85,12 +85,12 @@ func callInternal(ic *interop.Context, cs *state.Contract, name string, f callfl } } } - return callExFromNative(ic, ic.VM.GetCurrentScriptHash(), cs, name, args, f, hasReturn, pushNullOnUnloading) + return callExFromNative(ic, ic.VM.GetCurrentScriptHash(), cs, name, args, f, hasReturn, pushNullOnUnloading, false) } // callExFromNative calls a contract with flags using the provided calling hash. func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contract, - name string, args []stackitem.Item, f callflag.CallFlag, hasReturn bool, pushNullOnUnloading bool) error { + name string, args []stackitem.Item, f callflag.CallFlag, hasReturn bool, pushNullOnUnloading bool, callFromNative bool) error { for _, nc := range ic.Natives { if nc.Metadata().Name == nativenames.Policy { var pch = nc.(policyChecker) @@ -140,6 +140,9 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra if pushNullOnUnloading && commit { ic.VM.Context().Estack().PushItem(stackitem.Null{}) // Must use current context stack. } + if callFromNative && !commit { + return fmt.Errorf("unhandled exception") + } return nil } ic.VM.LoadNEFMethod(&cs.NEF, caller, cs.Hash, f, @@ -157,7 +160,7 @@ var ErrNativeCall = errors.New("failed native call") // CallFromNative performs synchronous call from native contract. func CallFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contract, method string, args []stackitem.Item, hasReturn bool) error { startSize := ic.VM.Istack().Len() - if err := callExFromNative(ic, caller, cs, method, args, callflag.All, hasReturn, false); err != nil { + if err := callExFromNative(ic, caller, cs, method, args, callflag.All, hasReturn, false, true); err != nil { return err } diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index f73a6e7f6..c9843a48d 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -1595,7 +1595,11 @@ func (v *VM) unloadContext(ctx *Context) { if ctx.onUnload != nil { err := ctx.onUnload(v.uncaughtException == nil) if err != nil { - panic(fmt.Errorf("context unload callback failed: %w", err)) + errMessage := fmt.Sprintf("context unload callback failed: %s", err) + if v.uncaughtException != nil { + errMessage = fmt.Sprintf("%s, uncaught exception: %s", errMessage, v.uncaughtException) + } + panic(errors.New(errMessage)) } } }