core: update System.Contract.Call
syscall
1. Remove `System.Contract.CallEx`. 2. Extend number of parameters. 3. Add return value count to `VM.Context`.
This commit is contained in:
parent
86b0e76bf0
commit
1c0c331e25
38 changed files with 170 additions and 171 deletions
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
@ -14,27 +15,19 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// Call calls a contract.
|
||||
// Call calls a contract with flags.
|
||||
func Call(ic *interop.Context) error {
|
||||
h := ic.VM.Estack().Pop().Bytes()
|
||||
method := ic.VM.Estack().Pop().String()
|
||||
args := ic.VM.Estack().Pop().Array()
|
||||
return callExInternal(ic, h, method, args, callflag.All)
|
||||
}
|
||||
|
||||
// CallEx calls a contract with flags.
|
||||
func CallEx(ic *interop.Context) error {
|
||||
h := ic.VM.Estack().Pop().Bytes()
|
||||
method := ic.VM.Estack().Pop().String()
|
||||
args := ic.VM.Estack().Pop().Array()
|
||||
fs := callflag.CallFlag(int32(ic.VM.Estack().Pop().BigInt().Int64()))
|
||||
if fs&^callflag.All != 0 {
|
||||
return errors.New("call flags out of range")
|
||||
}
|
||||
return callExInternal(ic, h, method, args, fs)
|
||||
args := ic.VM.Estack().Pop().Array()
|
||||
return callInternal(ic, h, method, fs, args)
|
||||
}
|
||||
|
||||
func callExInternal(ic *interop.Context, h []byte, name string, args []stackitem.Item, f callflag.CallFlag) error {
|
||||
func callInternal(ic *interop.Context, h []byte, name string, f callflag.CallFlag, args []stackitem.Item) error {
|
||||
u, err := util.Uint160DecodeBytesBE(h)
|
||||
if err != nil {
|
||||
return errors.New("invalid contract hash")
|
||||
|
@ -50,6 +43,10 @@ func callExInternal(ic *interop.Context, h []byte, name string, args []stackitem
|
|||
if md == nil {
|
||||
return errors.New("method not found")
|
||||
}
|
||||
hasReturn := md.ReturnType != smartcontract.VoidType
|
||||
if !hasReturn {
|
||||
ic.VM.Estack().PushVal(stackitem.Null{})
|
||||
}
|
||||
if md.Safe {
|
||||
f &^= callflag.WriteStates
|
||||
} else if ctx := ic.VM.Context(); ctx != nil && ctx.IsDeployed() {
|
||||
|
@ -60,18 +57,12 @@ func callExInternal(ic *interop.Context, h []byte, name string, args []stackitem
|
|||
}
|
||||
}
|
||||
}
|
||||
return CallExInternal(ic, cs, name, args, f, vm.EnsureNotEmpty)
|
||||
}
|
||||
|
||||
// CallExInternal calls a contract with flags and can't be invoked directly by user.
|
||||
func CallExInternal(ic *interop.Context, cs *state.Contract,
|
||||
name string, args []stackitem.Item, f callflag.CallFlag, checkReturn vm.CheckReturnState) error {
|
||||
return callExFromNative(ic, ic.VM.GetCurrentScriptHash(), cs, name, args, f, checkReturn)
|
||||
return callExFromNative(ic, ic.VM.GetCurrentScriptHash(), cs, name, args, f, hasReturn)
|
||||
}
|
||||
|
||||
// callExFromNative calls a contract with flags using provided calling hash.
|
||||
func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contract,
|
||||
name string, args []stackitem.Item, f callflag.CallFlag, checkReturn vm.CheckReturnState) error {
|
||||
name string, args []stackitem.Item, f callflag.CallFlag, hasReturn bool) error {
|
||||
md := cs.Manifest.ABI.GetMethod(name)
|
||||
if md == nil {
|
||||
return fmt.Errorf("method '%s' not found", name)
|
||||
|
@ -82,7 +73,7 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
|
|||
}
|
||||
|
||||
ic.VM.Invocations[cs.Hash]++
|
||||
ic.VM.LoadScriptWithCallingHash(caller, cs.NEF.Script, cs.Hash, ic.VM.Context().GetCallFlags()&f)
|
||||
ic.VM.LoadScriptWithCallingHash(caller, cs.NEF.Script, cs.Hash, ic.VM.Context().GetCallFlags()&f, true, uint16(len(args)))
|
||||
var isNative bool
|
||||
for i := range ic.Natives {
|
||||
if ic.Natives[i].Metadata().Hash.Equals(cs.Hash) {
|
||||
|
@ -90,17 +81,20 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
|
|||
break
|
||||
}
|
||||
}
|
||||
for i := len(args) - 1; i >= 0; i-- {
|
||||
ic.VM.Estack().PushVal(args[i])
|
||||
}
|
||||
if isNative {
|
||||
ic.VM.Estack().PushVal(args)
|
||||
ic.VM.Estack().PushVal(name)
|
||||
} else {
|
||||
for i := len(args) - 1; i >= 0; i-- {
|
||||
ic.VM.Estack().PushVal(args[i])
|
||||
}
|
||||
// use Jump not Call here because context was loaded in LoadScript above.
|
||||
ic.VM.Jump(ic.VM.Context(), md.Offset)
|
||||
}
|
||||
ic.VM.Context().CheckReturn = checkReturn
|
||||
if hasReturn {
|
||||
ic.VM.Context().RetCount = 1
|
||||
} else {
|
||||
ic.VM.Context().RetCount = 0
|
||||
}
|
||||
|
||||
md = cs.Manifest.ABI.GetMethod(manifest.MethodInit)
|
||||
if md != nil {
|
||||
|
@ -114,9 +108,9 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
|
|||
var ErrNativeCall = errors.New("error during call from native")
|
||||
|
||||
// CallFromNative performs synchronous call from native contract.
|
||||
func CallFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contract, method string, args []stackitem.Item, checkReturn vm.CheckReturnState) error {
|
||||
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, checkReturn); err != nil {
|
||||
if err := callExFromNative(ic, caller, cs, method, args, callflag.All, hasReturn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue