*: support invoking methods by offset

Allow to invoke methods by offset:
1. Every invoked contract must have manifest.
2. Check arguments count on invocation.
3. Change AppCall to a regular syscall.
4. Add test suite for `System.Contract.Call`.
This commit is contained in:
Evgenii Stratonikov 2020-07-23 18:13:02 +03:00
parent e87eba51f9
commit d2ddf7b7cb
14 changed files with 272 additions and 117 deletions

View file

@ -6,6 +6,7 @@ import (
"fmt"
"math"
"math/big"
"strings"
"unicode/utf8"
"github.com/nspcc-dev/neo-go/pkg/core/block"
@ -492,16 +493,49 @@ func contractCallExInternal(ic *interop.Context, v *vm.VM, h []byte, method stac
if err != nil {
return err
}
name := string(bs)
if strings.HasPrefix(name, "_") {
return errors.New("invalid method name (starts with '_')")
}
md := cs.Manifest.ABI.GetMethod(name)
if md == nil {
return fmt.Errorf("method '%s' not found", name)
}
curr, err := ic.DAO.GetContractState(v.GetCurrentScriptHash())
if err == nil {
if !curr.Manifest.CanCall(&cs.Manifest, string(bs)) {
return errors.New("disallowed method call")
}
}
arr, ok := args.Value().([]stackitem.Item)
if !ok {
return errors.New("second argument must be an array")
}
if len(arr) != len(md.Parameters) {
return fmt.Errorf("invalid argument count: %d (expected %d)", len(arr), len(md.Parameters))
}
ic.Invocations[u]++
v.LoadScriptWithHash(cs.Script, u, v.Context().GetCallFlags()&f)
v.Estack().PushVal(args)
v.Estack().PushVal(method)
var isNative bool
for i := range ic.Natives {
if ic.Natives[i].Metadata().Hash.Equals(u) {
isNative = true
break
}
}
if isNative {
v.Estack().PushVal(args)
v.Estack().PushVal(method)
} else {
for i := len(arr) - 1; i >= 0; i-- {
v.Estack().PushVal(arr[i])
}
// use Jump not Call here because context was loaded in LoadScript above.
v.Jump(v.Context(), md.Offset)
}
return nil
}