vm: simplify NEF loading by providing a special method

Offsets are still handled outside of VM to avoid introducing manifest
dependency (that's likely to be circular).
This commit is contained in:
Roman Khimov 2021-11-19 20:02:32 +03:00
parent 82d2231ea6
commit 29cda5112a
3 changed files with 34 additions and 20 deletions

View file

@ -2185,14 +2185,14 @@ func (bc *Blockchain) InitVerificationVM(v *vm.VM, getContract func(util.Uint160
if md == nil || md.ReturnType != smartcontract.BoolType {
return ErrInvalidVerificationContract
}
initMD := cs.Manifest.ABI.GetMethod(manifest.MethodInit, 0)
v.LoadScriptWithHash(cs.NEF.Script, hash, callflag.ReadOnly)
v.Context().NEF = &cs.NEF
v.Context().Jump(md.Offset)
if initMD != nil {
v.Call(initMD.Offset)
verifyOffset := md.Offset
initOffset := -1
md = cs.Manifest.ABI.GetMethod(manifest.MethodInit, 0)
if md != nil {
initOffset = md.Offset
}
v.LoadNEFMethod(&cs.NEF, util.Uint160{}, hash, callflag.ReadOnly,
true, verifyOffset, initOffset)
}
if len(witness.InvocationScript) != 0 {
err := vm.IsScriptCorrect(witness.InvocationScript, nil)

View file

@ -112,20 +112,19 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
return fmt.Errorf("invalid argument count: %d (expected %d)", len(args), len(md.Parameters))
}
methodOff := md.Offset
initOff := -1
md = cs.Manifest.ABI.GetMethod(manifest.MethodInit, 0)
if md != nil {
initOff = md.Offset
}
ic.VM.Invocations[cs.Hash]++
ic.VM.LoadScriptWithCallingHash(caller, cs.NEF.Script, cs.Hash, ic.VM.Context().GetCallFlags()&f, hasReturn)
ic.VM.Context().NEF = &cs.NEF
ic.VM.LoadNEFMethod(&cs.NEF, caller, cs.Hash, ic.VM.Context().GetCallFlags()&f,
hasReturn, methodOff, initOff)
for e, i := ic.VM.Estack(), len(args)-1; i >= 0; i-- {
e.PushItem(args[i])
}
// Move IP to the target method.
ic.VM.Context().Jump(md.Offset)
md = cs.Manifest.ABI.GetMethod(manifest.MethodInit, 0)
if md != nil {
ic.VM.Call(md.Offset)
}
return nil
}

View file

@ -297,12 +297,27 @@ func (v *VM) LoadScriptWithFlags(b []byte, f callflag.CallFlag) {
// each other.
func (v *VM) LoadScriptWithHash(b []byte, hash util.Uint160, f callflag.CallFlag) {
shash := v.GetCurrentScriptHash()
v.LoadScriptWithCallingHash(shash, b, hash, f, true)
v.loadScriptWithCallingHash(shash, b, hash, f, true)
}
// LoadScriptWithCallingHash is similar to LoadScriptWithHash but sets calling hash explicitly.
// LoadNEFMethod allows to create a context to execute a method from the NEF
// file with specified caller and executing hash, call flags, return value,
// method and _initialize offsets.
func (v *VM) LoadNEFMethod(exe *nef.File, caller util.Uint160, hash util.Uint160, f callflag.CallFlag,
hasReturn bool, methodOff int, initOff int) {
v.loadScriptWithCallingHash(caller, exe.Script, hash, f, hasReturn)
ctx := v.Context()
ctx.NEF = exe
// Move IP to the target method.
ctx.Jump(methodOff)
if initOff >= 0 {
v.Call(initOff)
}
}
// loadScriptWithCallingHash is similar to LoadScriptWithHash but sets calling hash explicitly.
// It should be used for calling from native contracts.
func (v *VM) LoadScriptWithCallingHash(caller util.Uint160, b []byte, hash util.Uint160,
func (v *VM) loadScriptWithCallingHash(caller util.Uint160, b []byte, hash util.Uint160,
f callflag.CallFlag, hasReturn bool) {
v.LoadScriptWithFlags(b, f)
ctx := v.Context()