diff --git a/src/Neo/Hardfork.cs b/src/Neo/Hardfork.cs index 7bd3cc0aef..9276c9c07d 100644 --- a/src/Neo/Hardfork.cs +++ b/src/Neo/Hardfork.cs @@ -16,6 +16,7 @@ public enum Hardfork : byte HF_Aspidochelone, HF_Basilisk, HF_Cockatrice, - HF_Domovoi + HF_Domovoi, + HF_Echidna } } diff --git a/src/Neo/SmartContract/Native/RoleManagement.cs b/src/Neo/SmartContract/Native/RoleManagement.cs index 6e989b78cf..d9e3a3f2fd 100644 --- a/src/Neo/SmartContract/Native/RoleManagement.cs +++ b/src/Neo/SmartContract/Native/RoleManagement.cs @@ -26,7 +26,16 @@ public sealed class RoleManagement : NativeContract { [ContractEvent(0, name: "Designation", "Role", ContractParameterType.Integer, - "BlockIndex", ContractParameterType.Integer)] + "BlockIndex", ContractParameterType.Integer, + Hardfork.HF_Echidna)] + + [ContractEvent(Hardfork.HF_Echidna, 0, name: "Designation", + "Role", ContractParameterType.Integer, + "BlockIndex", ContractParameterType.Integer, + "Old", ContractParameterType.Array, + "New", ContractParameterType.Array + )] + internal RoleManagement() : base() { } /// @@ -69,7 +78,18 @@ private void DesignateAsRole(ApplicationEngine engine, Role role, ECPoint[] node list.AddRange(nodes); list.Sort(); engine.Snapshot.Add(key, new StorageItem(list)); - engine.SendNotification(Hash, "Designation", new VM.Types.Array(engine.ReferenceCounter, new StackItem[] { (int)role, engine.PersistingBlock.Index })); + + if (engine.IsHardforkEnabled(Hardfork.HF_Echidna)) + { + var oldNodes = new VM.Types.Array(engine.ReferenceCounter, GetDesignatedByRole(engine.Snapshot, role, index - 1).Select(u => (ByteString)u.EncodePoint(true))); + var newNodes = new VM.Types.Array(engine.ReferenceCounter, nodes.Select(u => (ByteString)u.EncodePoint(true))); + + engine.SendNotification(Hash, "Designation", new VM.Types.Array(engine.ReferenceCounter, [(int)role, engine.PersistingBlock.Index, oldNodes, newNodes])); + } + else + { + engine.SendNotification(Hash, "Designation", new VM.Types.Array(engine.ReferenceCounter, [(int)role, engine.PersistingBlock.Index])); + } } private class NodeList : InteroperableList diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 61e6e67f48..3d2eb9f70e 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -80,6 +80,24 @@ public void TestActiveDeprecatedIn() Assert.IsFalse(NativeContract.IsActive(new active() { ActiveIn = null, DeprecatedIn = Hardfork.HF_Cockatrice }, settings.IsHardforkEnabled, 20)); } + [TestMethod] + public void TestActiveDeprecatedInRoleManagement() + { + string json = UT_ProtocolSettings.CreateHKSettings("\"HF_Echidna\": 20"); + var file = Path.GetTempFileName(); + File.WriteAllText(file, json); + ProtocolSettings settings = ProtocolSettings.Load(file, false); + File.Delete(file); + + var before = NativeContract.RoleManagement.GetContractState(settings.IsHardforkEnabled, 19); + var after = NativeContract.RoleManagement.GetContractState(settings.IsHardforkEnabled, 20); + + Assert.AreEqual(2, before.Manifest.Abi.Events[0].Parameters.Length); + Assert.AreEqual(1, before.Manifest.Abi.Events.Length); + Assert.AreEqual(4, after.Manifest.Abi.Events[0].Parameters.Length); + Assert.AreEqual(1, after.Manifest.Abi.Events.Length); + } + [TestMethod] public void TestGetContract() {