core: call _deploy method during create/update

This commit is contained in:
Evgenii Stratonikov 2020-10-02 12:56:51 +03:00
parent b71f9e296c
commit 2d9ef9219a
4 changed files with 115 additions and 5 deletions

View file

@ -10,6 +10,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/callback"
"github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
@ -386,10 +387,26 @@ func getTestContractState() (*state.Contract, *state.Contract) {
verifyOff := w.Len()
emit.Opcodes(w.BinWriter, opcode.LDSFLD0, opcode.SUB,
opcode.CONVERT, opcode.Opcode(stackitem.BooleanT), opcode.RET)
deployOff := w.Len()
emit.Opcodes(w.BinWriter, opcode.JMPIF, 2+8+3)
emit.String(w.BinWriter, "create")
emit.Opcodes(w.BinWriter, opcode.CALL, 3+8+3, opcode.RET)
emit.String(w.BinWriter, "update")
emit.Opcodes(w.BinWriter, opcode.CALL, 3, opcode.RET)
putValOff := w.Len()
emit.String(w.BinWriter, "initial")
emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext)
emit.Syscall(w.BinWriter, interopnames.SystemStoragePut)
emit.Opcodes(w.BinWriter, opcode.RET)
getValOff := w.Len()
emit.String(w.BinWriter, "initial")
emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext)
emit.Syscall(w.BinWriter, interopnames.SystemStorageGet)
script := w.Bytes()
h := hash.Hash160(script)
m := manifest.NewManifest(h)
m.Features = smartcontract.HasStorage
m.ABI.Methods = []manifest.Method{
{
Name: "add",
@ -439,6 +456,27 @@ func getTestContractState() (*state.Contract, *state.Contract) {
Offset: verifyOff,
ReturnType: smartcontract.BoolType,
},
{
Name: manifest.MethodDeploy,
Offset: deployOff,
Parameters: []manifest.Parameter{
manifest.NewParameter("isUpdate", smartcontract.BoolType),
},
ReturnType: smartcontract.VoidType,
},
{
Name: "getValue",
Offset: getValOff,
ReturnType: smartcontract.StringType,
},
{
Name: "putValue",
Offset: putValOff,
Parameters: []manifest.Parameter{
manifest.NewParameter("value", smartcontract.StringType),
},
ReturnType: smartcontract.VoidType,
},
}
cs := &state.Contract{
Script: script,
@ -454,6 +492,7 @@ func getTestContractState() (*state.Contract, *state.Contract) {
perm.Methods.Add("add3")
perm.Methods.Add("invalidReturn")
perm.Methods.Add("justReturn")
perm.Methods.Add("getValue")
m.Permissions = append(m.Permissions, *perm)
return cs, &state.Contract{
@ -837,6 +876,55 @@ func TestContractUpdate(t *testing.T) {
})
}
// TestContractCreateDeploy checks that `_deploy` method was called
// during contract creation or update.
func TestContractCreateDeploy(t *testing.T) {
v, ic, bc := createVM(t)
defer bc.Close()
v.GasLimit = -1
putArgs := func(cs *state.Contract) {
rawManifest, err := cs.Manifest.MarshalJSON()
require.NoError(t, err)
v.Estack().PushVal(rawManifest)
v.Estack().PushVal(cs.Script)
}
cs, currCs := getTestContractState()
v.LoadScriptWithFlags([]byte{byte(opcode.RET)}, smartcontract.All)
putArgs(cs)
require.NoError(t, contractCreate(ic))
require.NoError(t, ic.VM.Run())
v.LoadScriptWithFlags(currCs.Script, smartcontract.All)
err := contract.CallExInternal(ic, cs, "getValue", nil, smartcontract.All)
require.NoError(t, err)
require.NoError(t, v.Run())
require.Equal(t, "create", v.Estack().Pop().String())
v.LoadScriptWithFlags(cs.Script, smartcontract.All)
md := cs.Manifest.ABI.GetMethod("justReturn")
v.Jump(v.Context(), md.Offset)
t.Run("Update", func(t *testing.T) {
newCs := &state.Contract{
ID: cs.ID,
Script: append(cs.Script, byte(opcode.RET)),
Manifest: cs.Manifest,
}
newCs.Manifest.ABI.Hash = hash.Hash160(newCs.Script)
putArgs(newCs)
require.NoError(t, contractUpdate(ic))
require.NoError(t, v.Run())
v.LoadScriptWithFlags(currCs.Script, smartcontract.All)
err = contract.CallExInternal(ic, newCs, "getValue", nil, smartcontract.All)
require.NoError(t, err)
require.NoError(t, v.Run())
require.Equal(t, "update", v.Estack().Pop().String())
})
}
func TestContractGetCallFlags(t *testing.T) {
v, ic, bc := createVM(t)
defer bc.Close()