diff --git a/src/Neo/Network/P2P/Payloads/Signer.cs b/src/Neo/Network/P2P/Payloads/Signer.cs index 40496dfe74..f5d9015131 100644 --- a/src/Neo/Network/P2P/Payloads/Signer.cs +++ b/src/Neo/Network/P2P/Payloads/Signer.cs @@ -20,13 +20,14 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; namespace Neo.Network.P2P.Payloads { /// /// Represents a signer of a . /// - public class Signer : IInteroperable, ISerializable + public class Signer : IInteroperable, ISerializable, IEquatable { // This limits maximum number of AllowedContracts or AllowedGroups here private const int MaxSubitems = 16; @@ -66,6 +67,31 @@ public class Signer : IInteroperable, ISerializable /*AllowedGroups*/ (Scopes.HasFlag(WitnessScope.CustomGroups) ? AllowedGroups.GetVarSize() : 0) + /*Rules*/ (Scopes.HasFlag(WitnessScope.WitnessRules) ? Rules.GetVarSize() : 0); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Signer other) + { + if (ReferenceEquals(this, other)) + return true; + if (other is null) return false; + return Account == other.Account && + Scopes == other.Scopes && + AllowedContracts.SequenceEqual(other.AllowedContracts) && + AllowedGroups.SequenceEqual(other.AllowedGroups) && + Rules.SequenceEqual(other.Rules); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object obj) + { + if (obj == null) return false; + return obj is Signer signerObj && Equals(signerObj); + } + + public override int GetHashCode() + { + return HashCode.Combine(Account.GetHashCode(), Scopes); + } + public void Deserialize(ref MemoryReader reader) { Account = reader.ReadSerializable(); @@ -202,5 +228,23 @@ VM.Types.StackItem IInteroperable.ToStackItem(IReferenceCounter referenceCounter Scopes.HasFlag(WitnessScope.WitnessRules) ? new VM.Types.Array(referenceCounter, Rules.Select(u => u.ToStackItem(referenceCounter))) : new VM.Types.Array(referenceCounter) ]); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Signer left, Signer right) + { + if (left is null || right is null) + return Equals(left, right); + + return left.Equals(right); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Signer left, Signer right) + { + if (left is null || right is null) + return !Equals(left, right); + + return !left.Equals(right); + } } } diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs index d2358e947c..0ac918466f 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs @@ -23,6 +23,72 @@ namespace Neo.UnitTests.Network.P2P.Payloads [TestClass] public class UT_Signers { + [TestMethod] + public void Test_IEquatable() + { + var ecPoint = ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1); + var expected = new Signer() + { + Account = UInt160.Zero, + Scopes = WitnessScope.Global, + AllowedContracts = [UInt160.Zero], + AllowedGroups = [ecPoint], + Rules = [ + new WitnessRule + { + Condition = new BooleanCondition + { + Expression = true, + }, + Action = WitnessRuleAction.Allow, + }, + ] + }; + + var actual = new Signer() + { + Account = UInt160.Zero, + Scopes = WitnessScope.Global, + AllowedContracts = [UInt160.Zero], + AllowedGroups = [ecPoint], + Rules = [ + new WitnessRule + { + Condition = new BooleanCondition + { + Expression = true, + }, + Action = WitnessRuleAction.Allow, + }, + ] + }; + + var notEqual = new Signer() + { + Account = UInt160.Zero, + Scopes = WitnessScope.WitnessRules, + AllowedContracts = [], + AllowedGroups = [], + Rules = [] + }; + + Assert.IsTrue(expected.Equals(expected)); + + Assert.AreEqual(expected, actual); + Assert.IsTrue(expected == actual); + Assert.IsTrue(expected.Equals(actual)); + + Assert.AreNotEqual(expected, notEqual); + Assert.IsTrue(expected != notEqual); + Assert.IsFalse(expected.Equals(notEqual)); + + Assert.IsFalse(expected == null); + Assert.IsFalse(null == expected); + Assert.AreNotEqual(expected, null); + Assert.IsFalse(expected.Equals(null)); + } + + [TestMethod] public void Serialize_Deserialize_Global() {