core: simplify System.Contract.Call* parameter handling

This commit is contained in:
Evgenii Stratonikov 2020-07-29 11:24:06 +03:00
parent f40aba4cd0
commit 3c99393bef
2 changed files with 18 additions and 19 deletions

View file

@ -457,16 +457,16 @@ func storageContextAsReadOnly(ic *interop.Context, v *vm.VM) error {
// contractCall calls a contract. // contractCall calls a contract.
func contractCall(ic *interop.Context, v *vm.VM) error { func contractCall(ic *interop.Context, v *vm.VM) error {
h := v.Estack().Pop().Bytes() h := v.Estack().Pop().Bytes()
method := v.Estack().Pop().Item() method := v.Estack().Pop().String()
args := v.Estack().Pop().Item() args := v.Estack().Pop().Array()
return contractCallExInternal(ic, v, h, method, args, smartcontract.All) return contractCallExInternal(ic, v, h, method, args, smartcontract.All)
} }
// contractCallEx calls a contract with flags. // contractCallEx calls a contract with flags.
func contractCallEx(ic *interop.Context, v *vm.VM) error { func contractCallEx(ic *interop.Context, v *vm.VM) error {
h := v.Estack().Pop().Bytes() h := v.Estack().Pop().Bytes()
method := v.Estack().Pop().Item() method := v.Estack().Pop().String()
args := v.Estack().Pop().Item() args := v.Estack().Pop().Array()
flags := smartcontract.CallFlag(int32(v.Estack().Pop().BigInt().Int64())) flags := smartcontract.CallFlag(int32(v.Estack().Pop().BigInt().Int64()))
if flags&^smartcontract.All != 0 { if flags&^smartcontract.All != 0 {
return errors.New("call flags out of range") return errors.New("call flags out of range")
@ -474,7 +474,7 @@ func contractCallEx(ic *interop.Context, v *vm.VM) error {
return contractCallExInternal(ic, v, h, method, args, flags) return contractCallExInternal(ic, v, h, method, args, flags)
} }
func contractCallExInternal(ic *interop.Context, v *vm.VM, h []byte, method stackitem.Item, args stackitem.Item, f smartcontract.CallFlag) error { func contractCallExInternal(ic *interop.Context, v *vm.VM, h []byte, name string, args []stackitem.Item, f smartcontract.CallFlag) error {
u, err := util.Uint160DecodeBytesBE(h) u, err := util.Uint160DecodeBytesBE(h)
if err != nil { if err != nil {
return errors.New("invalid contract hash") return errors.New("invalid contract hash")
@ -483,10 +483,6 @@ func contractCallExInternal(ic *interop.Context, v *vm.VM, h []byte, method stac
if err != nil { if err != nil {
return errors.New("contract not found") return errors.New("contract not found")
} }
name, err := stackitem.ToString(method)
if err != nil {
return err
}
if strings.HasPrefix(name, "_") { if strings.HasPrefix(name, "_") {
return errors.New("invalid method name (starts with '_')") return errors.New("invalid method name (starts with '_')")
} }
@ -501,12 +497,8 @@ func contractCallExInternal(ic *interop.Context, v *vm.VM, h []byte, method stac
} }
} }
arr, ok := args.Value().([]stackitem.Item) if len(args) != len(md.Parameters) {
if !ok { return fmt.Errorf("invalid argument count: %d (expected %d)", len(args), len(md.Parameters))
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]++ ic.Invocations[u]++
@ -520,10 +512,10 @@ func contractCallExInternal(ic *interop.Context, v *vm.VM, h []byte, method stac
} }
if isNative { if isNative {
v.Estack().PushVal(args) v.Estack().PushVal(args)
v.Estack().PushVal(method) v.Estack().PushVal(name)
} else { } else {
for i := len(arr) - 1; i >= 0; i-- { for i := len(args) - 1; i >= 0; i-- {
v.Estack().PushVal(arr[i]) v.Estack().PushVal(args[i])
} }
// use Jump not Call here because context was loaded in LoadScript above. // use Jump not Call here because context was loaded in LoadScript above.
v.Jump(v.Context(), md.Offset) v.Jump(v.Context(), md.Offset)

View file

@ -443,7 +443,14 @@ func TestContractCall(t *testing.T) {
for i := range args { for i := range args {
v.Estack().PushVal(args[i]) v.Estack().PushVal(args[i])
} }
require.Error(t, contractCall(ic, v)) // interops can both return error and panic,
// we don't care which kind of error has occured
require.Panics(t, func() {
err := contractCall(ic, v)
if err != nil {
panic(err)
}
})
} }
} }