forked from TrueCloudLab/neoneo-go
core: add notifications to ManagmentContract
This commit is contained in:
parent
d34353aec2
commit
b1324db847
2 changed files with 52 additions and 9 deletions
|
@ -38,7 +38,10 @@ const StoragePrice = 100000
|
||||||
const (
|
const (
|
||||||
prefixContract = 8
|
prefixContract = 8
|
||||||
|
|
||||||
defaultMinimumDeploymentFee = 10_00000000
|
defaultMinimumDeploymentFee = 10_00000000
|
||||||
|
contractDeployNotificationName = "Deploy"
|
||||||
|
contractUpdateNotificationName = "Update"
|
||||||
|
contractDestroyNotificationName = "Destroy"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -68,17 +71,17 @@ func newManagement() *Management {
|
||||||
desc = newDescriptor("deploy", smartcontract.ArrayType,
|
desc = newDescriptor("deploy", smartcontract.ArrayType,
|
||||||
manifest.NewParameter("script", smartcontract.ByteArrayType),
|
manifest.NewParameter("script", smartcontract.ByteArrayType),
|
||||||
manifest.NewParameter("manifest", smartcontract.ByteArrayType))
|
manifest.NewParameter("manifest", smartcontract.ByteArrayType))
|
||||||
md = newMethodAndPrice(m.deploy, 0, smartcontract.WriteStates)
|
md = newMethodAndPrice(m.deploy, 0, smartcontract.WriteStates|smartcontract.AllowNotify)
|
||||||
m.AddMethod(md, desc)
|
m.AddMethod(md, desc)
|
||||||
|
|
||||||
desc = newDescriptor("update", smartcontract.VoidType,
|
desc = newDescriptor("update", smartcontract.VoidType,
|
||||||
manifest.NewParameter("script", smartcontract.ByteArrayType),
|
manifest.NewParameter("script", smartcontract.ByteArrayType),
|
||||||
manifest.NewParameter("manifest", smartcontract.ByteArrayType))
|
manifest.NewParameter("manifest", smartcontract.ByteArrayType))
|
||||||
md = newMethodAndPrice(m.update, 0, smartcontract.WriteStates)
|
md = newMethodAndPrice(m.update, 0, smartcontract.WriteStates|smartcontract.AllowNotify)
|
||||||
m.AddMethod(md, desc)
|
m.AddMethod(md, desc)
|
||||||
|
|
||||||
desc = newDescriptor("destroy", smartcontract.VoidType)
|
desc = newDescriptor("destroy", smartcontract.VoidType)
|
||||||
md = newMethodAndPrice(m.destroy, 1000000, smartcontract.WriteStates)
|
md = newMethodAndPrice(m.destroy, 1000000, smartcontract.WriteStates|smartcontract.AllowNotify)
|
||||||
m.AddMethod(md, desc)
|
m.AddMethod(md, desc)
|
||||||
|
|
||||||
desc = newDescriptor("getMinimumDeploymentFee", smartcontract.IntegerType)
|
desc = newDescriptor("getMinimumDeploymentFee", smartcontract.IntegerType)
|
||||||
|
@ -89,6 +92,11 @@ func newManagement() *Management {
|
||||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||||
md = newMethodAndPrice(m.setMinimumDeploymentFee, 300_0000, smartcontract.WriteStates)
|
md = newMethodAndPrice(m.setMinimumDeploymentFee, 300_0000, smartcontract.WriteStates)
|
||||||
m.AddMethod(md, desc)
|
m.AddMethod(md, desc)
|
||||||
|
|
||||||
|
hashParam := manifest.NewParameter("Hash", smartcontract.Hash160Type)
|
||||||
|
m.AddEvent(contractDeployNotificationName, hashParam)
|
||||||
|
m.AddEvent(contractUpdateNotificationName, hashParam)
|
||||||
|
m.AddEvent(contractDestroyNotificationName, hashParam)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,6 +222,7 @@ func (m *Management) deploy(ic *interop.Context, args []stackitem.Item) stackite
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
callDeploy(ic, newcontract, false)
|
callDeploy(ic, newcontract, false)
|
||||||
|
m.emitNotification(ic, contractDeployNotificationName, newcontract.Hash)
|
||||||
return contractToStack(newcontract)
|
return contractToStack(newcontract)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +234,7 @@ func (m *Management) markUpdated(h util.Uint160) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deploy creates contract's hash/ID and saves new contract into the given DAO.
|
// Deploy creates contract's hash/ID and saves new contract into the given DAO.
|
||||||
// It doesn't run _deploy method.
|
// It doesn't run _deploy method and doesn't emit notification.
|
||||||
func (m *Management) Deploy(d dao.DAO, sender util.Uint160, neff *nef.File, manif *manifest.Manifest) (*state.Contract, error) {
|
func (m *Management) Deploy(d dao.DAO, sender util.Uint160, neff *nef.File, manif *manifest.Manifest) (*state.Contract, error) {
|
||||||
h := state.CreateContractHash(sender, neff.Script)
|
h := state.CreateContractHash(sender, neff.Script)
|
||||||
key := makeContractKey(h)
|
key := makeContractKey(h)
|
||||||
|
@ -269,11 +278,12 @@ func (m *Management) update(ic *interop.Context, args []stackitem.Item) stackite
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
callDeploy(ic, contract, true)
|
callDeploy(ic, contract, true)
|
||||||
|
m.emitNotification(ic, contractUpdateNotificationName, contract.Hash)
|
||||||
return stackitem.Null{}
|
return stackitem.Null{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates contract's script and/or manifest in the given DAO.
|
// Update updates contract's script and/or manifest in the given DAO.
|
||||||
// It doesn't run _deploy method.
|
// It doesn't run _deploy method and doesn't emit notification.
|
||||||
func (m *Management) Update(d dao.DAO, hash util.Uint160, neff *nef.File, manif *manifest.Manifest) (*state.Contract, error) {
|
func (m *Management) Update(d dao.DAO, hash util.Uint160, neff *nef.File, manif *manifest.Manifest) (*state.Contract, error) {
|
||||||
contract, err := m.GetContract(d, hash)
|
contract, err := m.GetContract(d, hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -308,10 +318,11 @@ func (m *Management) destroy(ic *interop.Context, sis []stackitem.Item) stackite
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
m.emitNotification(ic, contractDestroyNotificationName, hash)
|
||||||
return stackitem.Null{}
|
return stackitem.Null{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy drops given contract from DAO along with its storage.
|
// Destroy drops given contract from DAO along with its storage. It doesn't emit notification.
|
||||||
func (m *Management) Destroy(d dao.DAO, hash util.Uint160) error {
|
func (m *Management) Destroy(d dao.DAO, hash util.Uint160) error {
|
||||||
contract, err := m.GetContract(d, hash)
|
contract, err := m.GetContract(d, hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -502,3 +513,12 @@ func (m *Management) getNextContractID(d dao.DAO) (int32, error) {
|
||||||
si.Value = bigint.ToPreallocatedBytes(id, si.Value)
|
si.Value = bigint.ToPreallocatedBytes(id, si.Value)
|
||||||
return ret, d.PutStorageItem(m.ContractID, keyNextAvailableID, si)
|
return ret, d.PutStorageItem(m.ContractID, keyNextAvailableID, si)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Management) emitNotification(ic *interop.Context, name string, hash util.Uint160) {
|
||||||
|
ne := state.NotificationEvent{
|
||||||
|
ScriptHash: m.Hash,
|
||||||
|
Name: name,
|
||||||
|
Item: stackitem.NewArray([]stackitem.Item{addrToStackItem(&hash)}),
|
||||||
|
}
|
||||||
|
ic.Notifications = append(ic.Notifications, ne)
|
||||||
|
}
|
||||||
|
|
|
@ -159,7 +159,11 @@ func TestContractDeploy(t *testing.T) {
|
||||||
require.Equal(t, 1, len(res.Stack))
|
require.Equal(t, 1, len(res.Stack))
|
||||||
compareContractStates(t, cs1, res.Stack[0])
|
compareContractStates(t, cs1, res.Stack[0])
|
||||||
}
|
}
|
||||||
|
require.Equal(t, aers[0].Events, []state.NotificationEvent{{
|
||||||
|
ScriptHash: mgmtHash,
|
||||||
|
Name: "Deploy",
|
||||||
|
Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}),
|
||||||
|
}})
|
||||||
t.Run("_deploy called", func(t *testing.T) {
|
t.Run("_deploy called", func(t *testing.T) {
|
||||||
res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "getValue")
|
res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "getValue")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -337,7 +341,11 @@ func TestContractUpdate(t *testing.T) {
|
||||||
require.Equal(t, vm.HaltState, aers[1].VMState)
|
require.Equal(t, vm.HaltState, aers[1].VMState)
|
||||||
require.Equal(t, 1, len(aers[1].Stack))
|
require.Equal(t, 1, len(aers[1].Stack))
|
||||||
compareContractStates(t, cs1, aers[1].Stack[0])
|
compareContractStates(t, cs1, aers[1].Stack[0])
|
||||||
|
require.Equal(t, aers[0].Events, []state.NotificationEvent{{
|
||||||
|
ScriptHash: mgmtHash,
|
||||||
|
Name: "Update",
|
||||||
|
Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}),
|
||||||
|
}})
|
||||||
t.Run("_deploy called", func(t *testing.T) {
|
t.Run("_deploy called", func(t *testing.T) {
|
||||||
res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "getValue")
|
res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "getValue")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -358,6 +366,11 @@ func TestContractUpdate(t *testing.T) {
|
||||||
res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nil, manif1)
|
res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nil, manif1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, vm.HaltState, res.VMState)
|
require.Equal(t, vm.HaltState, res.VMState)
|
||||||
|
require.Equal(t, res.Events, []state.NotificationEvent{{
|
||||||
|
ScriptHash: mgmtHash,
|
||||||
|
Name: "Update",
|
||||||
|
Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}),
|
||||||
|
}})
|
||||||
t.Run("check contract", func(t *testing.T) {
|
t.Run("check contract", func(t *testing.T) {
|
||||||
checkContractState(t, bc, cs1.Hash, cs1)
|
checkContractState(t, bc, cs1.Hash, cs1)
|
||||||
})
|
})
|
||||||
|
@ -377,6 +390,11 @@ func TestContractUpdate(t *testing.T) {
|
||||||
res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nef1b, manif1)
|
res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nef1b, manif1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, vm.HaltState, res.VMState)
|
require.Equal(t, vm.HaltState, res.VMState)
|
||||||
|
require.Equal(t, res.Events, []state.NotificationEvent{{
|
||||||
|
ScriptHash: mgmtHash,
|
||||||
|
Name: "Update",
|
||||||
|
Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}),
|
||||||
|
}})
|
||||||
t.Run("check contract", func(t *testing.T) {
|
t.Run("check contract", func(t *testing.T) {
|
||||||
checkContractState(t, bc, cs1.Hash, cs1)
|
checkContractState(t, bc, cs1.Hash, cs1)
|
||||||
})
|
})
|
||||||
|
@ -432,6 +450,11 @@ func TestContractDestroy(t *testing.T) {
|
||||||
res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "destroy")
|
res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "destroy")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, vm.HaltState, res.VMState)
|
require.Equal(t, vm.HaltState, res.VMState)
|
||||||
|
require.Equal(t, res.Events, []state.NotificationEvent{{
|
||||||
|
ScriptHash: mgmtHash,
|
||||||
|
Name: "Destroy",
|
||||||
|
Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}),
|
||||||
|
}})
|
||||||
t.Run("check contract", func(t *testing.T) {
|
t.Run("check contract", func(t *testing.T) {
|
||||||
res, err := invokeContractMethod(bc, 1_00000000, mgmtHash, "getContract", cs1.Hash.BytesBE())
|
res, err := invokeContractMethod(bc, 1_00000000, mgmtHash, "getContract", cs1.Hash.BytesBE())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
Loading…
Reference in a new issue