diff --git a/pkg/core/native/designate.go b/pkg/core/native/designate.go index e0edc425e..05f387dec 100644 --- a/pkg/core/native/designate.go +++ b/pkg/core/native/designate.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "errors" "math" + "math/big" "sort" "sync/atomic" @@ -57,6 +58,9 @@ const ( // maxNodeCount is the maximum number of nodes to set the role for. maxNodeCount = 32 + + // DesignationEventName is the name of a designation event. + DesignationEventName = "Designation" ) // Various errors. @@ -88,9 +92,13 @@ func newDesignate(p2pSigExtensionsEnabled bool) *Designate { desc = newDescriptor("designateAsRole", smartcontract.VoidType, manifest.NewParameter("role", smartcontract.IntegerType), manifest.NewParameter("nodes", smartcontract.ArrayType)) - md = newMethodAndPrice(s.designateAsRole, 1<<15, callflag.States) + md = newMethodAndPrice(s.designateAsRole, 1<<15, callflag.States|callflag.AllowNotify) s.AddMethod(md, desc) + s.AddEvent(DesignationEventName, + manifest.NewParameter("Role", smartcontract.IntegerType), + manifest.NewParameter("BlockIndex", smartcontract.IntegerType)) + return s } @@ -319,7 +327,20 @@ func (s *Designate) DesignateAsRole(ic *interop.Context, r noderoles.Role, pubs } sort.Sort(pubs) s.rolesChangedFlag.Store(true) - return ic.DAO.PutStorageItem(s.ID, key, NodeList(pubs).Bytes()) + err := ic.DAO.PutStorageItem(s.ID, key, NodeList(pubs).Bytes()) + if err != nil { + return err + } + + ic.Notifications = append(ic.Notifications, state.NotificationEvent{ + ScriptHash: s.Hash, + Name: DesignationEventName, + Item: stackitem.NewArray([]stackitem.Item{ + stackitem.NewBigInteger(big.NewInt(int64(r))), + stackitem.NewBigInteger(big.NewInt(int64(ic.Block.Index))), + }), + }) + return nil } func (s *Designate) getRole(item stackitem.Item) (noderoles.Role, bool) { diff --git a/pkg/core/native_designate_test.go b/pkg/core/native_designate_test.go index 386859359..f66d464fc 100644 --- a/pkg/core/native_designate_test.go +++ b/pkg/core/native_designate_test.go @@ -58,8 +58,18 @@ func (bc *Blockchain) setNodesByRole(t *testing.T, ok bool, r noderoles.Role, no require.Equal(t, 1, len(aer)) if ok { require.Equal(t, vm.HaltState, aer[0].VMState) + require.Equal(t, 1, len(aer[0].Events)) + + ev := aer[0].Events[0] + require.Equal(t, bc.contracts.Designate.Hash, ev.ScriptHash) + require.Equal(t, native.DesignationEventName, ev.Name) + require.Equal(t, []stackitem.Item{ + stackitem.Make(int64(r)), + stackitem.Make(bc.BlockHeight()), + }, ev.Item.Value().([]stackitem.Item)) } else { require.Equal(t, vm.FaultState, aer[0].VMState) + require.Equal(t, 0, len(aer[0].Events)) } } diff --git a/pkg/interop/native/roles/roles.go b/pkg/interop/native/roles/roles.go index a8c22b1ae..438150768 100644 --- a/pkg/interop/native/roles/roles.go +++ b/pkg/interop/native/roles/roles.go @@ -34,5 +34,5 @@ func GetDesignatedByRole(r Role, height uint32) []interop.PublicKey { // DesignateAsRole represents `designateAsRole` method of RoleManagement native contract. func DesignateAsRole(r Role, pubs []interop.PublicKey) { contract.Call(interop.Hash160(Hash), "designateAsRole", - contract.States, r, pubs) + contract.States|contract.AllowNotify, r, pubs) }