From d55f0a1f455f171712dab02fb72c8524a2ca807d Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Sun, 29 Dec 2024 18:58:18 +0300 Subject: [PATCH] P2P: fix `UnknownCapability`validation and maintainig (#3647) * P2P: allow to serialize UnknownCapability Otherwise it can't be properly passed through the P2P network which makes it impossible to use UnknownCapabilities as an extensions in the existing networks. Follow https://github.com/nspcc-dev/neo-go/pull/3778. Signed-off-by: Anna Shaleva * P2P: fix verification rules for NetworkAddressWithTime Without this commit every `Addr` message containing UnknownCapability will be considered as invalid. The desired behaviour is to include node with UnknownCapability into the list of peers. Follow the https://github.com/nspcc-dev/neo-go/pull/3778, should be a part of https://github.com/neo-project/neo/pull/3639. Signed-off-by: Anna Shaleva * P2P: don't strip UnknownCapabilities from node's version Make the behaviour compatible with https://github.com/nspcc-dev/neo-go/pull/3778. Signed-off-by: Anna Shaleva --------- Signed-off-by: Anna Shaleva --- src/Neo/Network/P2P/Capabilities/UnknownCapability.cs | 2 +- src/Neo/Network/P2P/Payloads/NetworkAddressWithTime.cs | 5 ++++- src/Neo/Network/P2P/Payloads/VersionPayload.cs | 4 ++-- .../Network/P2P/Capabilities/UT_UnknownCapability.cs | 2 +- .../Network/P2P/Payloads/UT_NetworkAddressWithTime.cs | 3 ++- .../Neo.UnitTests/Network/P2P/Payloads/UT_VersionPayload.cs | 4 ++-- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Neo/Network/P2P/Capabilities/UnknownCapability.cs b/src/Neo/Network/P2P/Capabilities/UnknownCapability.cs index 4447166abe..537c7d15bc 100644 --- a/src/Neo/Network/P2P/Capabilities/UnknownCapability.cs +++ b/src/Neo/Network/P2P/Capabilities/UnknownCapability.cs @@ -48,7 +48,7 @@ protected override void DeserializeWithoutType(ref MemoryReader reader) protected override void SerializeWithoutType(BinaryWriter writer) { - throw new InvalidOperationException("Unknown capability can't be serialized"); + writer.WriteVarBytes(Data.Span); } } } diff --git a/src/Neo/Network/P2P/Payloads/NetworkAddressWithTime.cs b/src/Neo/Network/P2P/Payloads/NetworkAddressWithTime.cs index 0b7e0acc37..6b51f2e033 100644 --- a/src/Neo/Network/P2P/Payloads/NetworkAddressWithTime.cs +++ b/src/Neo/Network/P2P/Payloads/NetworkAddressWithTime.cs @@ -75,7 +75,10 @@ void ISerializable.Deserialize(ref MemoryReader reader) Capabilities = new NodeCapability[reader.ReadVarInt(VersionPayload.MaxCapabilities)]; for (int x = 0, max = Capabilities.Length; x < max; x++) Capabilities[x] = NodeCapability.DeserializeFrom(ref reader); - if (Capabilities.Select(p => p.Type).Distinct().Count() != Capabilities.Length) + // Verify that no duplicating capabilities are included. Unknown capabilities are not + // taken into account but still preserved to be able to share through the network. + var capabilities = Capabilities.Where(c => c is not UnknownCapability); + if (capabilities.Select(p => p.Type).Distinct().Count() != capabilities.Count()) throw new FormatException(); } diff --git a/src/Neo/Network/P2P/Payloads/VersionPayload.cs b/src/Neo/Network/P2P/Payloads/VersionPayload.cs index 29e9bec994..3a585a6af6 100644 --- a/src/Neo/Network/P2P/Payloads/VersionPayload.cs +++ b/src/Neo/Network/P2P/Payloads/VersionPayload.cs @@ -99,8 +99,8 @@ void ISerializable.Deserialize(ref MemoryReader reader) Capabilities = new NodeCapability[reader.ReadVarInt(MaxCapabilities)]; for (int x = 0, max = Capabilities.Length; x < max; x++) Capabilities[x] = NodeCapability.DeserializeFrom(ref reader); - Capabilities = Capabilities.Where(c => c is not UnknownCapability).ToArray(); - if (Capabilities.Select(p => p.Type).Distinct().Count() != Capabilities.Length) + var capabilities = Capabilities.Where(c => c is not UnknownCapability); + if (capabilities.Select(p => p.Type).Distinct().Count() != capabilities.Count()) throw new FormatException(); } diff --git a/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_UnknownCapability.cs b/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_UnknownCapability.cs index a228c00782..7579229f37 100644 --- a/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_UnknownCapability.cs +++ b/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_UnknownCapability.cs @@ -30,7 +30,7 @@ public void DeserializeUnknown() var capab = (NodeCapability)NodeCapability.DeserializeFrom(ref br); Assert.IsTrue(capab is UnknownCapability); - Assert.ThrowsException(() => capab.ToArray()); + CollectionAssert.AreEqual(buffer, capab.ToArray()); } } } diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NetworkAddressWithTime.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NetworkAddressWithTime.cs index 3e2c6c336c..e3196adf7a 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NetworkAddressWithTime.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NetworkAddressWithTime.cs @@ -10,6 +10,7 @@ // modifications are permitted. using FluentAssertions; +using FluentAssertions.Equivalency; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Extensions; using Neo.IO; @@ -40,7 +41,7 @@ public void SizeAndEndPoint_Get() [TestMethod] public void DeserializeAndSerialize() { - var test = NetworkAddressWithTime.Create(IPAddress.Any, 1, new NodeCapability[] { new ServerCapability(NodeCapabilityType.TcpServer, 22) }); + var test = NetworkAddressWithTime.Create(IPAddress.Any, 1, new NodeCapability[] { new ServerCapability(NodeCapabilityType.TcpServer, 22), new UnknownCapability(NodeCapabilityType.Extension0), new UnknownCapability(NodeCapabilityType.Extension0) }); var clone = test.ToArray().AsSerializable(); CollectionAssert.AreEqual(test.Capabilities.ToByteArray(), clone.Capabilities.ToByteArray()); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_VersionPayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_VersionPayload.cs index 551654d04b..fe23ae6a76 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_VersionPayload.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_VersionPayload.cs @@ -58,8 +58,8 @@ public void DeserializeAndSerialize() buf = buf.Concat(new byte[] { 0x10, 0x01, 0x00, 0x00, 0x00 }).ToArray(); // FullNode capability, 0x01 index. clone = buf.AsSerializable(); - Assert.AreEqual(2, clone.Capabilities.Length); - Assert.AreEqual(0, clone.Capabilities.OfType().Count()); + Assert.AreEqual(4, clone.Capabilities.Length); + Assert.AreEqual(2, clone.Capabilities.OfType().Count()); } } }