mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2025-05-08 09:10:30 +00:00
*: 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:
parent
e87eba51f9
commit
d2ddf7b7cb
14 changed files with 272 additions and 117 deletions
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -323,6 +324,109 @@ func TestBlockchainGetContractState(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func getTestContractState() *state.Contract {
|
||||
script := []byte{
|
||||
byte(opcode.ABORT), // abort if no offset was provided
|
||||
byte(opcode.ADD), byte(opcode.RET),
|
||||
byte(opcode.PUSH7), byte(opcode.RET),
|
||||
}
|
||||
h := hash.Hash160(script)
|
||||
m := manifest.NewManifest(h)
|
||||
m.ABI.Methods = []manifest.Method{
|
||||
{
|
||||
Name: "add",
|
||||
Offset: 1,
|
||||
Parameters: []manifest.Parameter{
|
||||
manifest.NewParameter("addend1", smartcontract.IntegerType),
|
||||
manifest.NewParameter("addend2", smartcontract.IntegerType),
|
||||
},
|
||||
ReturnType: smartcontract.IntegerType,
|
||||
},
|
||||
{
|
||||
Name: "ret7",
|
||||
Offset: 3,
|
||||
Parameters: []manifest.Parameter{},
|
||||
ReturnType: smartcontract.IntegerType,
|
||||
},
|
||||
}
|
||||
return &state.Contract{
|
||||
Script: script,
|
||||
Manifest: *m,
|
||||
ID: 42,
|
||||
}
|
||||
}
|
||||
|
||||
func TestContractCall(t *testing.T) {
|
||||
v, ic, bc := createVM(t)
|
||||
defer bc.Close()
|
||||
|
||||
cs := getTestContractState()
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
|
||||
currScript := []byte{byte(opcode.NOP)}
|
||||
initVM := func(v *vm.VM) {
|
||||
v.Istack().Clear()
|
||||
v.Estack().Clear()
|
||||
v.Load(currScript)
|
||||
v.Estack().PushVal(42) // canary
|
||||
}
|
||||
|
||||
h := cs.Manifest.ABI.Hash
|
||||
m := manifest.NewManifest(hash.Hash160(currScript))
|
||||
perm := manifest.NewPermission(manifest.PermissionHash, h)
|
||||
perm.Methods.Add("add")
|
||||
m.Permissions = append(m.Permissions, *perm)
|
||||
|
||||
require.NoError(t, ic.DAO.PutContractState(&state.Contract{
|
||||
Script: currScript,
|
||||
Manifest: *m,
|
||||
ID: 123,
|
||||
}))
|
||||
|
||||
addArgs := stackitem.NewArray([]stackitem.Item{stackitem.Make(1), stackitem.Make(2)})
|
||||
t.Run("Good", func(t *testing.T) {
|
||||
initVM(v)
|
||||
v.Estack().PushVal(addArgs)
|
||||
v.Estack().PushVal("add")
|
||||
v.Estack().PushVal(h.BytesBE())
|
||||
require.NoError(t, contractCall(ic, v))
|
||||
require.NoError(t, v.Run())
|
||||
require.Equal(t, 2, v.Estack().Len())
|
||||
require.Equal(t, big.NewInt(3), v.Estack().Pop().Value())
|
||||
require.Equal(t, big.NewInt(42), v.Estack().Pop().Value())
|
||||
})
|
||||
|
||||
t.Run("CallExInvalidFlag", func(t *testing.T) {
|
||||
initVM(v)
|
||||
v.Estack().PushVal(byte(0xFF))
|
||||
v.Estack().PushVal(addArgs)
|
||||
v.Estack().PushVal("add")
|
||||
v.Estack().PushVal(h.BytesBE())
|
||||
require.Error(t, contractCallEx(ic, v))
|
||||
})
|
||||
|
||||
runInvalid := func(args ...interface{}) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
initVM(v)
|
||||
for i := range args {
|
||||
v.Estack().PushVal(args[i])
|
||||
}
|
||||
require.Error(t, contractCall(ic, v))
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("Invalid", func(t *testing.T) {
|
||||
t.Run("Hash", runInvalid(addArgs, "add", h.BytesBE()[1:]))
|
||||
t.Run("MissingHash", runInvalid(addArgs, "add", util.Uint160{}.BytesBE()))
|
||||
t.Run("Method", runInvalid(addArgs, stackitem.NewInterop("add"), h.BytesBE()))
|
||||
t.Run("MissingMethod", runInvalid(addArgs, "sub", h.BytesBE()))
|
||||
t.Run("DisallowedMethod", runInvalid(stackitem.NewArray(nil), "ret7", h.BytesBE()))
|
||||
t.Run("Arguments", runInvalid(1, "add", h.BytesBE()))
|
||||
t.Run("NotEnoughArguments", runInvalid(
|
||||
stackitem.NewArray([]stackitem.Item{stackitem.Make(1)}), "add", h.BytesBE()))
|
||||
})
|
||||
}
|
||||
|
||||
func TestContractCreate(t *testing.T) {
|
||||
v, cs, ic, bc := createVMAndContractState(t)
|
||||
v.GasLimit = -1
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue