mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-26 09:42:22 +00:00
Merge pull request #1693 from nspcc-dev/fix/deploy
Provide additional data on deployment
This commit is contained in:
commit
cb56eb4696
12 changed files with 199 additions and 37 deletions
2
cli/testdata/deploy/main.go
vendored
2
cli/testdata/deploy/main.go
vendored
|
@ -13,7 +13,7 @@ var key = "key"
|
|||
|
||||
const mgmtKey = "mgmt"
|
||||
|
||||
func _deploy(isUpdate bool) {
|
||||
func _deploy(data interface{}, isUpdate bool) {
|
||||
var value string
|
||||
|
||||
ctx := storage.GetContext()
|
||||
|
|
2
cli/testdata/deploy/sub/put.go
vendored
2
cli/testdata/deploy/sub/put.go
vendored
|
@ -4,7 +4,7 @@ import "github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
|||
|
||||
var Key = "sub"
|
||||
|
||||
func _deploy(isUpdate bool) {
|
||||
func _deploy(data interface{}, isUpdate bool) {
|
||||
ctx := storage.GetContext()
|
||||
value := "sub create"
|
||||
if isUpdate {
|
||||
|
|
|
@ -16,7 +16,7 @@ func init() {
|
|||
trigger = runtime.GetTrigger()
|
||||
}
|
||||
|
||||
func _deploy(isUpdate bool) {
|
||||
func _deploy(_ interface{}, isUpdate bool) {
|
||||
if isUpdate {
|
||||
Log("_deploy method called before contract update")
|
||||
return
|
||||
|
|
|
@ -25,7 +25,7 @@ func init() {
|
|||
ctx = storage.GetContext()
|
||||
}
|
||||
|
||||
func _deploy(isUpdate bool) {
|
||||
func _deploy(_ interface{}, isUpdate bool) {
|
||||
if isUpdate {
|
||||
ticksLeft := storage.Get(ctx, ticksKey).(int) + 1
|
||||
storage.Put(ctx, ticksKey, ticksLeft)
|
||||
|
|
|
@ -336,11 +336,11 @@ func (c *codegen) convertInitFuncs(f *ast.File, pkg *types.Package, seenBefore b
|
|||
|
||||
func isDeployFunc(decl *ast.FuncDecl) bool {
|
||||
if decl.Name.Name != "_deploy" || decl.Recv != nil ||
|
||||
decl.Type.Params.NumFields() != 1 ||
|
||||
decl.Type.Params.NumFields() != 2 ||
|
||||
decl.Type.Results.NumFields() != 0 {
|
||||
return false
|
||||
}
|
||||
typ, ok := decl.Type.Params.List[0].Type.(*ast.Ident)
|
||||
typ, ok := decl.Type.Params.List[1].Type.(*ast.Ident)
|
||||
return ok && typ.Name == "bool"
|
||||
}
|
||||
|
||||
|
@ -1869,7 +1869,7 @@ func (c *codegen) compile(info *buildInfo, pkg *loader.PackageInfo) error {
|
|||
|
||||
hasDeploy := deployLocals > -1
|
||||
if hasDeploy {
|
||||
emit.Instruction(c.prog.BinWriter, opcode.INITSLOT, []byte{byte(deployLocals), 1})
|
||||
emit.Instruction(c.prog.BinWriter, opcode.INITSLOT, []byte{byte(deployLocals), 2})
|
||||
c.convertDeployFuncs()
|
||||
c.deployEndOffset = c.prog.Len()
|
||||
emit.Opcodes(c.prog.BinWriter, opcode.RET)
|
||||
|
|
|
@ -150,11 +150,18 @@ func (c *codegen) emitDebugInfo(contract []byte) *DebugInfo {
|
|||
Start: uint16(c.initEndOffset + 1),
|
||||
End: uint16(c.deployEndOffset),
|
||||
},
|
||||
Parameters: []DebugParam{{
|
||||
Name: "isUpdate",
|
||||
Type: "Boolean",
|
||||
TypeSC: smartcontract.BoolType,
|
||||
}},
|
||||
Parameters: []DebugParam{
|
||||
{
|
||||
Name: "data",
|
||||
Type: "Any",
|
||||
TypeSC: smartcontract.AnyType,
|
||||
},
|
||||
{
|
||||
Name: "isUpdate",
|
||||
Type: "Boolean",
|
||||
TypeSC: smartcontract.BoolType,
|
||||
},
|
||||
},
|
||||
ReturnType: "Void",
|
||||
ReturnTypeSC: smartcontract.VoidType,
|
||||
SeqPoints: c.sequencePoints[manifest.MethodDeploy],
|
||||
|
|
|
@ -53,7 +53,7 @@ func MethodParams(addr interop.Hash160, h interop.Hash256,
|
|||
type MyStruct struct {}
|
||||
func (ms MyStruct) MethodOnStruct() { }
|
||||
func (ms *MyStruct) MethodOnPointerToStruct() { }
|
||||
func _deploy(isUpdate bool) {}
|
||||
func _deploy(data interface{}, isUpdate bool) {}
|
||||
`
|
||||
|
||||
info, err := getBuildInfo("foo.go", src)
|
||||
|
@ -100,11 +100,18 @@ func _deploy(isUpdate bool) {}
|
|||
|
||||
t.Run("param types", func(t *testing.T) {
|
||||
paramTypes := map[string][]DebugParam{
|
||||
"_deploy": {{
|
||||
Name: "isUpdate",
|
||||
Type: "Boolean",
|
||||
TypeSC: smartcontract.BoolType,
|
||||
}},
|
||||
"_deploy": {
|
||||
{
|
||||
Name: "data",
|
||||
Type: "Any",
|
||||
TypeSC: smartcontract.AnyType,
|
||||
},
|
||||
{
|
||||
Name: "isUpdate",
|
||||
Type: "Boolean",
|
||||
TypeSC: smartcontract.BoolType,
|
||||
},
|
||||
},
|
||||
"MethodInt": {{
|
||||
Name: "a",
|
||||
Type: "ByteString",
|
||||
|
@ -160,6 +167,7 @@ func _deploy(isUpdate bool) {}
|
|||
Name: "_deploy",
|
||||
Offset: 0,
|
||||
Parameters: []manifest.Parameter{
|
||||
manifest.NewParameter("data", smartcontract.AnyType),
|
||||
manifest.NewParameter("isUpdate", smartcontract.BoolType),
|
||||
},
|
||||
ReturnType: smartcontract.VoidType,
|
||||
|
|
|
@ -104,7 +104,13 @@ type ContractMD struct {
|
|||
ContractID int32
|
||||
NEF nef.File
|
||||
Hash util.Uint160
|
||||
Methods map[string]MethodAndPrice
|
||||
Methods map[MethodAndArgCount]MethodAndPrice
|
||||
}
|
||||
|
||||
// MethodAndArgCount represents method's signature.
|
||||
type MethodAndArgCount struct {
|
||||
Name string
|
||||
ArgCount int
|
||||
}
|
||||
|
||||
// NewContractMD returns Contract with the specified list of methods.
|
||||
|
@ -112,7 +118,7 @@ func NewContractMD(name string, id int32) *ContractMD {
|
|||
c := &ContractMD{
|
||||
Name: name,
|
||||
ContractID: id,
|
||||
Methods: make(map[string]MethodAndPrice),
|
||||
Methods: make(map[MethodAndArgCount]MethodAndPrice),
|
||||
}
|
||||
|
||||
// NEF is now stored in contract state and affects state dump.
|
||||
|
@ -129,10 +135,35 @@ func NewContractMD(name string, id int32) *ContractMD {
|
|||
|
||||
// AddMethod adds new method to a native contract.
|
||||
func (c *ContractMD) AddMethod(md *MethodAndPrice, desc *manifest.Method) {
|
||||
c.Manifest.ABI.Methods = append(c.Manifest.ABI.Methods, *desc)
|
||||
md.MD = desc
|
||||
desc.Safe = md.RequiredFlags&(callflag.All^callflag.ReadOnly) == 0
|
||||
c.Methods[desc.Name] = *md
|
||||
|
||||
index := sort.Search(len(c.Manifest.ABI.Methods), func(i int) bool {
|
||||
md := c.Manifest.ABI.Methods[i]
|
||||
if md.Name != desc.Name {
|
||||
return md.Name >= desc.Name
|
||||
}
|
||||
return len(md.Parameters) > len(desc.Parameters)
|
||||
})
|
||||
c.Manifest.ABI.Methods = append(c.Manifest.ABI.Methods, manifest.Method{})
|
||||
copy(c.Manifest.ABI.Methods[index+1:], c.Manifest.ABI.Methods[index:])
|
||||
c.Manifest.ABI.Methods[index] = *desc
|
||||
|
||||
key := MethodAndArgCount{
|
||||
Name: desc.Name,
|
||||
ArgCount: len(desc.Parameters),
|
||||
}
|
||||
c.Methods[key] = *md
|
||||
}
|
||||
|
||||
// GetMethod returns method `name` with specified number of parameters.
|
||||
func (c *ContractMD) GetMethod(name string, paramCount int) (MethodAndPrice, bool) {
|
||||
key := MethodAndArgCount{
|
||||
Name: name,
|
||||
ArgCount: paramCount,
|
||||
}
|
||||
mp, ok := c.Methods[key]
|
||||
return mp, ok
|
||||
}
|
||||
|
||||
// AddEvent adds new event to a native contract.
|
||||
|
|
|
@ -479,10 +479,16 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
|
|||
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.SWAP, opcode.JMPIF, 2+8+1+1+5+3)
|
||||
emit.String(w.BinWriter, "create") // 8 bytes
|
||||
emit.Int(w.BinWriter, 2) // 1 byte
|
||||
emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemBinarySerialize) // 5 bytes
|
||||
emit.Opcodes(w.BinWriter, opcode.CALL, 3+8+1+1+5+3, opcode.RET)
|
||||
emit.String(w.BinWriter, "update") // 8 bytes
|
||||
emit.Int(w.BinWriter, 2) // 1 byte
|
||||
emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemBinarySerialize) // 5 bytes
|
||||
emit.Opcodes(w.BinWriter, opcode.CALL, 3, opcode.RET)
|
||||
putValOff := w.Len()
|
||||
emit.String(w.BinWriter, "initial")
|
||||
|
@ -501,6 +507,9 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
|
|||
emit.String(w.BinWriter, "LastPayment")
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemRuntimeNotify)
|
||||
emit.Opcodes(w.BinWriter, opcode.RET)
|
||||
update3Off := w.Len()
|
||||
emit.Int(w.BinWriter, 3)
|
||||
emit.Opcodes(w.BinWriter, opcode.JMP, 2+1)
|
||||
updateOff := w.Len()
|
||||
emit.Int(w.BinWriter, 2)
|
||||
emit.Opcodes(w.BinWriter, opcode.PACK)
|
||||
|
@ -588,6 +597,7 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
|
|||
Name: manifest.MethodDeploy,
|
||||
Offset: deployOff,
|
||||
Parameters: []manifest.Parameter{
|
||||
manifest.NewParameter("data", smartcontract.AnyType),
|
||||
manifest.NewParameter("isUpdate", smartcontract.BoolType),
|
||||
},
|
||||
ReturnType: smartcontract.VoidType,
|
||||
|
@ -624,6 +634,16 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
|
|||
},
|
||||
ReturnType: smartcontract.VoidType,
|
||||
},
|
||||
{
|
||||
Name: "update",
|
||||
Offset: update3Off,
|
||||
Parameters: []manifest.Parameter{
|
||||
manifest.NewParameter("nef", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("manifest", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("data", smartcontract.AnyType),
|
||||
},
|
||||
ReturnType: smartcontract.VoidType,
|
||||
},
|
||||
{
|
||||
Name: "destroy",
|
||||
Offset: destroyOff,
|
||||
|
|
|
@ -28,7 +28,7 @@ func Call(ic *interop.Context) error {
|
|||
return errors.New("it is not allowed to use Neo.Native.Call directly to call native contracts. System.Contract.Call should be used")
|
||||
}
|
||||
operation := ic.VM.Estack().Pop().String()
|
||||
m, ok := c.Metadata().Methods[operation]
|
||||
m, ok := c.Metadata().GetMethod(operation, ic.VM.Estack().Len())
|
||||
if !ok {
|
||||
return fmt.Errorf("method %s not found", operation)
|
||||
}
|
||||
|
|
|
@ -77,12 +77,26 @@ func newManagement() *Management {
|
|||
md = newMethodAndPrice(m.deploy, 0, callflag.WriteStates|callflag.AllowNotify)
|
||||
m.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("deploy", smartcontract.ArrayType,
|
||||
manifest.NewParameter("script", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("manifest", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("data", smartcontract.AnyType))
|
||||
md = newMethodAndPrice(m.deployWithData, 0, callflag.WriteStates|callflag.AllowNotify)
|
||||
m.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("update", smartcontract.VoidType,
|
||||
manifest.NewParameter("script", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("manifest", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(m.update, 0, callflag.WriteStates|callflag.AllowNotify)
|
||||
m.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("update", smartcontract.VoidType,
|
||||
manifest.NewParameter("script", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("manifest", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("data", smartcontract.AnyType))
|
||||
md = newMethodAndPrice(m.updateWithData, 0, callflag.WriteStates|callflag.AllowNotify)
|
||||
m.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("destroy", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(m.destroy, 1000000, callflag.WriteStates|callflag.AllowNotify)
|
||||
m.AddMethod(md, desc)
|
||||
|
@ -204,9 +218,14 @@ func (m *Management) getNefAndManifestFromItems(ic *interop.Context, args []stac
|
|||
return resNef, resManifest, nil
|
||||
}
|
||||
|
||||
// deploy is an implementation of public deploy method, it's run under
|
||||
// VM protections, so it's OK for it to panic instead of returning errors.
|
||||
// deploy is an implementation of public 2-argument deploy method.
|
||||
func (m *Management) deploy(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
return m.deployWithData(ic, append(args, stackitem.Null{}))
|
||||
}
|
||||
|
||||
// deployWithData is an implementation of public 3-argument deploy method.
|
||||
// It's run under VM protections, so it's OK for it to panic instead of returning errors.
|
||||
func (m *Management) deployWithData(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
neff, manif, err := m.getNefAndManifestFromItems(ic, args, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -224,7 +243,7 @@ func (m *Management) deploy(ic *interop.Context, args []stackitem.Item) stackite
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
m.callDeploy(ic, newcontract, false)
|
||||
m.callDeploy(ic, newcontract, args[2], false)
|
||||
m.emitNotification(ic, contractDeployNotificationName, newcontract.Hash)
|
||||
return contractToStack(newcontract)
|
||||
}
|
||||
|
@ -266,9 +285,13 @@ func (m *Management) Deploy(d dao.DAO, sender util.Uint160, neff *nef.File, mani
|
|||
return newcontract, nil
|
||||
}
|
||||
|
||||
func (m *Management) update(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
return m.updateWithData(ic, append(args, stackitem.Null{}))
|
||||
}
|
||||
|
||||
// update is an implementation of public update method, it's run under
|
||||
// VM protections, so it's OK for it to panic instead of returning errors.
|
||||
func (m *Management) update(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
func (m *Management) updateWithData(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
neff, manif, err := m.getNefAndManifestFromItems(ic, args, false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -280,7 +303,7 @@ func (m *Management) update(ic *interop.Context, args []stackitem.Item) stackite
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
m.callDeploy(ic, contract, true)
|
||||
m.callDeploy(ic, contract, args[2], true)
|
||||
m.emitNotification(ic, contractUpdateNotificationName, contract.Hash)
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
@ -299,6 +322,9 @@ func (m *Management) Update(d dao.DAO, hash util.Uint160, neff *nef.File, manif
|
|||
}
|
||||
// if manifest was provided, update the contract manifest
|
||||
if manif != nil {
|
||||
if manif.Name != contract.Manifest.Name {
|
||||
return nil, errors.New("contract name can't be changed")
|
||||
}
|
||||
if !manif.IsValid(contract.Hash) {
|
||||
return nil, errors.New("invalid manifest for this contract")
|
||||
}
|
||||
|
@ -378,11 +404,11 @@ func (m *Management) setMinimumDeploymentFee(ic *interop.Context, args []stackit
|
|||
return stackitem.Null{}
|
||||
}
|
||||
|
||||
func (m *Management) callDeploy(ic *interop.Context, cs *state.Contract, isUpdate bool) {
|
||||
md := cs.Manifest.ABI.GetMethod(manifest.MethodDeploy, 1)
|
||||
func (m *Management) callDeploy(ic *interop.Context, cs *state.Contract, data stackitem.Item, isUpdate bool) {
|
||||
md := cs.Manifest.ABI.GetMethod(manifest.MethodDeploy, 2)
|
||||
if md != nil {
|
||||
err := contract.CallFromNative(ic, m.Hash, cs, manifest.MethodDeploy,
|
||||
[]stackitem.Item{stackitem.NewBool(isUpdate)}, false)
|
||||
[]stackitem.Item{data, stackitem.NewBool(isUpdate)}, false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -71,6 +71,57 @@ func TestStartFromHeight(t *testing.T) {
|
|||
checkContractState(t, bc2, cs1.Hash, cs1)
|
||||
}
|
||||
|
||||
func TestContractDeployAndUpdateWithParameter(t *testing.T) {
|
||||
bc := newTestChain(t)
|
||||
defer bc.Close()
|
||||
|
||||
// nef.NewFile() cares about version a lot.
|
||||
config.Version = "0.90.0-test"
|
||||
mgmtHash := bc.ManagementContractHash()
|
||||
cs1, _ := getTestContractState(bc)
|
||||
cs1.Manifest.Permissions = []manifest.Permission{*manifest.NewPermission(manifest.PermissionWildcard)}
|
||||
cs1.ID = 1
|
||||
cs1.Hash = state.CreateContractHash(testchain.MultisigScriptHash(), cs1.NEF.Checksum, cs1.Manifest.Name)
|
||||
manif1, err := json.Marshal(cs1.Manifest)
|
||||
require.NoError(t, err)
|
||||
nef1b, err := cs1.NEF.Bytes()
|
||||
require.NoError(t, err)
|
||||
|
||||
aer, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nef1b, manif1, int64(42))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vm.HaltState, aer.VMState)
|
||||
|
||||
t.Run("_deploy called", func(t *testing.T) {
|
||||
res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "getValue")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
item, err := stackitem.DeserializeItem(res.Stack[0].Value().([]byte))
|
||||
require.NoError(t, err)
|
||||
expected := []stackitem.Item{stackitem.Make("create"), stackitem.Make(42)}
|
||||
require.Equal(t, stackitem.NewArray(expected), item)
|
||||
})
|
||||
|
||||
cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.RET))
|
||||
cs1.NEF.Checksum = cs1.NEF.CalculateChecksum()
|
||||
nef1b, err = cs1.NEF.Bytes()
|
||||
require.NoError(t, err)
|
||||
cs1.UpdateCounter++
|
||||
|
||||
aer, err = invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nef1b, nil, "new data")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vm.HaltState, aer.VMState)
|
||||
|
||||
t.Run("_deploy called", func(t *testing.T) {
|
||||
res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "getValue")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
item, err := stackitem.DeserializeItem(res.Stack[0].Value().([]byte))
|
||||
require.NoError(t, err)
|
||||
expected := []stackitem.Item{stackitem.Make("update"), stackitem.Make("new data")}
|
||||
require.Equal(t, stackitem.NewArray(expected), item)
|
||||
})
|
||||
}
|
||||
|
||||
func TestContractDeploy(t *testing.T) {
|
||||
bc := newTestChain(t)
|
||||
defer bc.Close()
|
||||
|
@ -166,7 +217,10 @@ func TestContractDeploy(t *testing.T) {
|
|||
res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "getValue")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
require.Equal(t, []byte("create"), res.Stack[0].Value())
|
||||
item, err := stackitem.DeserializeItem(res.Stack[0].Value().([]byte))
|
||||
require.NoError(t, err)
|
||||
expected := []stackitem.Item{stackitem.Make("create"), stackitem.Null{}}
|
||||
require.Equal(t, stackitem.NewArray(expected), item)
|
||||
})
|
||||
t.Run("get after deploy", func(t *testing.T) {
|
||||
checkContractState(t, bc, cs1.Hash, cs1)
|
||||
|
@ -198,6 +252,7 @@ func TestContractDeploy(t *testing.T) {
|
|||
Name: manifest.MethodDeploy,
|
||||
Offset: 0,
|
||||
Parameters: []manifest.Parameter{
|
||||
manifest.NewParameter("data", smartcontract.AnyType),
|
||||
manifest.NewParameter("isUpdate", smartcontract.BoolType),
|
||||
},
|
||||
ReturnType: smartcontract.VoidType,
|
||||
|
@ -226,6 +281,7 @@ func TestContractDeploy(t *testing.T) {
|
|||
Name: manifest.MethodDeploy,
|
||||
Offset: 0,
|
||||
Parameters: []manifest.Parameter{
|
||||
manifest.NewParameter("data", smartcontract.AnyType),
|
||||
manifest.NewParameter("isUpdate", smartcontract.BoolType),
|
||||
},
|
||||
ReturnType: smartcontract.ArrayType,
|
||||
|
@ -319,6 +375,17 @@ func TestContractUpdate(t *testing.T) {
|
|||
checkFAULTState(t, res)
|
||||
})
|
||||
|
||||
t.Run("change name", func(t *testing.T) {
|
||||
var badManifest = cs1.Manifest
|
||||
badManifest.Name += "tail"
|
||||
manifB, err := json.Marshal(badManifest)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nef1b, manifB)
|
||||
require.NoError(t, err)
|
||||
checkFAULTState(t, res)
|
||||
})
|
||||
|
||||
cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.RET))
|
||||
cs1.NEF.Checksum = cs1.NEF.CalculateChecksum()
|
||||
nef1b, err = cs1.NEF.Bytes()
|
||||
|
@ -346,7 +413,10 @@ func TestContractUpdate(t *testing.T) {
|
|||
res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "getValue")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
require.Equal(t, []byte("update"), res.Stack[0].Value())
|
||||
item, err := stackitem.DeserializeItem(res.Stack[0].Value().([]byte))
|
||||
require.NoError(t, err)
|
||||
expected := []stackitem.Item{stackitem.Make("update"), stackitem.Null{}}
|
||||
require.Equal(t, stackitem.NewArray(expected), item)
|
||||
})
|
||||
t.Run("check contract", func(t *testing.T) {
|
||||
checkContractState(t, bc, cs1.Hash, cs1)
|
||||
|
|
Loading…
Reference in a new issue