From ee20bc944ca2c8d6512cfbd5b50dafa94ef12ddb Mon Sep 17 00:00:00 2001 From: Charis Date: Tue, 16 Jul 2019 12:49:12 +0800 Subject: [PATCH 01/84] add internal to DB and WriteBatch --- neo/IO/Data/LevelDB/DB.cs | 16 ++++++++-------- neo/IO/Data/LevelDB/WriteBatch.cs | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/neo/IO/Data/LevelDB/DB.cs b/neo/IO/Data/LevelDB/DB.cs index 559a109594..5f4a9f359a 100644 --- a/neo/IO/Data/LevelDB/DB.cs +++ b/neo/IO/Data/LevelDB/DB.cs @@ -16,7 +16,7 @@ private DB(IntPtr handle) this.handle = handle; } - public void Dispose() + public virtual void Dispose() { if (handle != IntPtr.Zero) { @@ -25,14 +25,14 @@ public void Dispose() } } - public void Delete(WriteOptions options, Slice key) + public virtual void Delete(WriteOptions options, Slice key) { IntPtr error; Native.leveldb_delete(handle, options.handle, key.buffer, (UIntPtr)key.buffer.Length, out error); NativeHelper.CheckError(error); } - public Slice Get(ReadOptions options, Slice key) + public virtual Slice Get(ReadOptions options, Slice key) { UIntPtr length; IntPtr error; @@ -50,12 +50,12 @@ public Slice Get(ReadOptions options, Slice key) } } - public Snapshot GetSnapshot() + public virtual Snapshot GetSnapshot() { return new Snapshot(handle); } - public Iterator NewIterator(ReadOptions options) + public virtual Iterator NewIterator(ReadOptions options) { return new Iterator(Native.leveldb_create_iterator(handle, options.handle)); } @@ -73,14 +73,14 @@ public static DB Open(string name, Options options) return new DB(handle); } - public void Put(WriteOptions options, Slice key, Slice value) + public virtual void Put(WriteOptions options, Slice key, Slice value) { IntPtr error; Native.leveldb_put(handle, options.handle, key.buffer, (UIntPtr)key.buffer.Length, value.buffer, (UIntPtr)value.buffer.Length, out error); NativeHelper.CheckError(error); } - public bool TryGet(ReadOptions options, Slice key, out Slice value) + public virtual bool TryGet(ReadOptions options, Slice key, out Slice value) { UIntPtr length; IntPtr error; @@ -101,7 +101,7 @@ public bool TryGet(ReadOptions options, Slice key, out Slice value) return true; } - public void Write(WriteOptions options, WriteBatch write_batch) + public virtual void Write(WriteOptions options, WriteBatch write_batch) { // There's a bug in .Net Core. // When calling DB.Write(), it will throw LevelDBException sometimes. diff --git a/neo/IO/Data/LevelDB/WriteBatch.cs b/neo/IO/Data/LevelDB/WriteBatch.cs index eaa3e08bd6..29d04643a1 100644 --- a/neo/IO/Data/LevelDB/WriteBatch.cs +++ b/neo/IO/Data/LevelDB/WriteBatch.cs @@ -11,17 +11,17 @@ public class WriteBatch Native.leveldb_writebatch_destroy(handle); } - public void Clear() + public virtual void Clear() { Native.leveldb_writebatch_clear(handle); } - public void Delete(Slice key) + public virtual void Delete(Slice key) { Native.leveldb_writebatch_delete(handle, key.buffer, (UIntPtr)key.buffer.Length); } - public void Put(Slice key, Slice value) + public virtual void Put(Slice key, Slice value) { Native.leveldb_writebatch_put(handle, key.buffer, (UIntPtr)key.buffer.Length, value.buffer, (UIntPtr)value.buffer.Length); } From 3ef8f924f414cc9e66491984857717cb12ea2289 Mon Sep 17 00:00:00 2001 From: luchuan Date: Thu, 10 Oct 2019 18:24:46 +0800 Subject: [PATCH 02/84] add disconnect message --- .../P2P/Payloads/UT_DisconnectionPayload.cs | 45 ++++ neo.UnitTests/Network/P2P/UT_LocalNode.cs | 210 ++++++++++++++++++ .../Network/P2P/UT_ProtocolHandler.cs | 46 +++- neo.UnitTests/Network/P2P/UT_RemoteNode.cs | 131 ++++++++++- neo/Network/P2P/Connection.cs | 16 +- neo/Network/P2P/LocalNode.cs | 11 + neo/Network/P2P/Message.cs | 3 + neo/Network/P2P/MessageCommand.cs | 1 + .../P2P/Payloads/DisconnectionPayload.cs | 55 +++++ neo/Network/P2P/Peer.cs | 48 +++- neo/Network/P2P/ProtocolHandler.cs | 16 +- neo/Network/P2P/RemoteNode.cs | 42 +++- 12 files changed, 588 insertions(+), 36 deletions(-) create mode 100644 neo.UnitTests/Network/P2P/Payloads/UT_DisconnectionPayload.cs create mode 100644 neo.UnitTests/Network/P2P/UT_LocalNode.cs create mode 100644 neo/Network/P2P/Payloads/DisconnectionPayload.cs diff --git a/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectionPayload.cs b/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectionPayload.cs new file mode 100644 index 0000000000..8d3d3b2fef --- /dev/null +++ b/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectionPayload.cs @@ -0,0 +1,45 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.Network.P2P.Payloads; +using System.IO; + +namespace Neo.UnitTests.Network.P2P.Payloads +{ + [TestClass] + public class UT_DisconnectionPayload + { + [TestMethod] + public void Size_Get() + { + var payload = DisconnectionPayload.Create(DisconnectionReason.DuplicateConnection, "test message", new byte[] { 0x01, 0x02 }); + payload.Size.Should().Be(17); + } + + [TestMethod] + public void Deserialize() + { + var payload = new DisconnectionPayload(); + var hex = "030c74657374206d657373616765020102"; + using (MemoryStream ms = new MemoryStream(hex.HexToBytes(), false)) + { + using (BinaryReader reader = new BinaryReader(ms)) + { + payload.Deserialize(reader); + } + } + Assert.AreEqual(DisconnectionReason.DuplicateConnection, payload.Reason); + Assert.AreEqual("test message", payload.Message); + Assert.AreEqual(2, payload.Data.Length); + Assert.AreEqual(0x01, payload.Data[0]); + Assert.AreEqual(0x02, payload.Data[1]); + } + + [TestMethod] + public void Serialize() + { + var payload = DisconnectionPayload.Create(DisconnectionReason.DuplicateConnection, "test message", new byte[] { 0x01, 0x02 }); + payload.ToArray().ToHexString().Should().Be("030c74657374206d657373616765020102"); + } + } +} diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs new file mode 100644 index 0000000000..712175a36b --- /dev/null +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -0,0 +1,210 @@ +using Akka.Actor; +using Akka.IO; +using Akka.TestKit.Xunit2; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.Network.P2P; +using Neo.Network.P2P.Capabilities; +using Neo.Network.P2P.Payloads; +using System.Linq; +using System.Net; +using Akka.TestKit; +using System.Collections.Generic; + +namespace Neo.UnitTests.Network.P2P +{ + [TestClass] + public class UT_LocalNode : TestKit + { + private static NeoSystem testBlockchain; + + [ClassInitialize] + public static void TestSetup(TestContext ctx) + { + testBlockchain = TestBlockchain.InitializeMockNeoSystem(); + } + + [TestCleanup] + public void TestCleanup() + { + // clear all remote nodes in LocalNode + var testProbe = CreateTestProbe(); + foreach (var remoteActor in LocalNode.Singleton.RemoteNodes.Keys) + { + testProbe.Send(remoteActor, new Tcp.ConnectionClosed()); + } + } + + [TestMethod] + public void Test_GetRandomConnectedPeers() + { + var localNode = testBlockchain.LocalNode; + var local = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080); + var remote = new IPEndPoint(IPAddress.Parse("133.133.133.133"), 8080); + var connected = new Tcp.Connected(remote, local); + + // create a remote node connection by sending tcp.connected message + var testProbe = CreateTestProbe(); + testProbe.Send(localNode, connected); + testProbe.ExpectMsg(); // register msg is earlier than version message + testProbe.ExpectMsg(); // remote ndoe send version message + + // send version to remote node + var payload = new VersionPayload() + { + UserAgent = "Unit Test".PadLeft(1024, '0'), + Nonce = 1, + Magic = ProtocolSettings.Default.Magic, + Timestamp = 5, + Version = 6, + Capabilities = new NodeCapability[] + { + new ServerCapability(NodeCapabilityType.TcpServer, 8080) + } + }; + var message = Message.Create(MessageCommand.Version, payload); + var versionReceived = new Tcp.Received(ByteString.FromBytes(message.ToArray())); + var remoteNodeActor = LocalNode.Singleton.RemoteNodes.Keys.First(); + testProbe.Send(remoteNodeActor, versionReceived); + testProbe.ExpectMsg(); // remote node will send verack and change its listenerPort + + // check connected peers + int connectedCount = LocalNode.Singleton.ConnectedCount; + NetworkAddressWithTime[] addressWithTimes = LocalNode.Singleton.GetRandomConnectedPeers(connectedCount); + addressWithTimes.Where(p => p.EndPoint.Equals(remote)).Count().Should().Be(1); // `remote` must be contained + + } + + [TestMethod] + public void Test_Peer_Max_Per_Address_Connection_Reached() + { + var localNode = testBlockchain.LocalNode; + var local = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080); + + // Create the maximum number of per address connections + IPEndPoint remote = null; + Tcp.Connected connected = null; + var senderDict = new Dictionary(); + for (int i = 1; i <= LocalNode.Singleton.MaxConnectionsPerAddress; i++) + { + remote = new IPEndPoint(IPAddress.Parse("192.168.1.1"), 8080 + i); + connected = new Tcp.Connected(remote, local); + + var proble = CreateTestProbe(); + proble.Send(localNode, connected); + proble.ExpectMsg(); // register msg is earlier than version msg + proble.ExpectMsg(); // remote ndoe send version msg + + senderDict[remote] = proble; + } + + // send version message to one remote node, which will contain listenerport + // and can be selected in `GetRandomConnectedPeers` + var payload = new VersionPayload() + { + UserAgent = "Unit Test".PadLeft(1024, '0'), + Nonce = 1, + Magic = ProtocolSettings.Default.Magic, + Timestamp = 5, + Version = 6, + Capabilities = new NodeCapability[] + { + new ServerCapability(NodeCapabilityType.TcpServer, 8080) + } + }; + var message = Message.Create(MessageCommand.Version, payload); + var versionReceived = new Tcp.Received(ByteString.FromBytes(message.ToArray())); + var remoteAddr = LocalNode.Singleton.RemoteNodes.Values.First().Remote; + var remoteNodeActor = LocalNode.Singleton.RemoteNodes.Keys.First(); + var testProbe = senderDict[remoteAddr]; + testProbe.Send(remoteNodeActor, versionReceived); + testProbe.ExpectMsg(); // remote node will send verack and change its listenerPort + + // create one more remote connection and localnode will disconnect with `MaxPerAddressConnectionReached` + remote = new IPEndPoint(IPAddress.Parse("192.168.1.1"), 8079); + connected = new Tcp.Connected(remote, local); + testProbe.Send(localNode, connected); + + var tcpWrite = testProbe.ExpectMsg(); + message = tcpWrite.Data.ToArray().AsSerializable(); + message.Command.Should().Be(MessageCommand.Disconnect); + + DisconnectionPayload disconnectionPayload = (DisconnectionPayload)message.Payload; + disconnectionPayload.Reason.Should().Be(DisconnectionReason.MaxPerAddressConnectionReached); + + // return addr + var count = DisconnectionPayload.MaxDataSize; + NetworkAddressWithTime[] addrs = disconnectionPayload.Data.AsSerializableArray(count); + addrs.Length.Should().Be(1); + addrs[0].EndPoint.Address.Should().BeEquivalentTo(IPAddress.Parse("192.168.1.1")); + + testProbe.ExpectMsg(); + } + + [TestMethod] + public void Test_Peer_MaxConnection_Reached() + { + var localNode = testBlockchain.LocalNode; + var local = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080); + + // Create the maximum number of connections + IPEndPoint remote = null; + Tcp.Connected connected = null; + var senderDict = new Dictionary(); + for (int i = 1; i <= LocalNode.Singleton.MaxConnections; i++) + { + remote = new IPEndPoint(IPAddress.Parse("192.168.1." + i), 8080); + connected = new Tcp.Connected(remote, local); + var proble = CreateTestProbe(); + proble.Send(localNode, connected); + proble.ExpectMsg(); // register msg is earlier than version msg + proble.ExpectMsg(); // remote ndoe send version msg + + senderDict[remote] = proble; + } + + // send version message to one remote node, which will contain listenerport + // and can be selected in `GetRandomConnectedPeers` + var payload = new VersionPayload() + { + UserAgent = "Unit Test".PadLeft(1024, '0'), + Nonce = 1, + Magic = ProtocolSettings.Default.Magic, + Timestamp = 5, + Version = 6, + Capabilities = new NodeCapability[] + { + new ServerCapability(NodeCapabilityType.TcpServer, 8080) + } + }; + var versionReceived = new Tcp.Received(ByteString.FromBytes(Message.Create(MessageCommand.Version, payload).ToArray())); + var remoteAddr = LocalNode.Singleton.RemoteNodes.Values.First().Remote; + var remoteNodeActor = LocalNode.Singleton.RemoteNodes.Keys.First(); + var testProbe = senderDict[remoteAddr]; + + testProbe.Send(remoteNodeActor, versionReceived); + testProbe.ExpectMsg(); // remote node will send verack and change its listenerPort + + // create one more remote connection and localnode will disconnect with `MaxConnectionReached` + remote = new IPEndPoint(IPAddress.Parse("192.168.2.1"), 8080); + connected = new Tcp.Connected(remote, local); + testProbe.Send(localNode, connected); + + var tcpWrite = testProbe.ExpectMsg(); + Message message = tcpWrite.Data.ToArray().AsSerializable(); + message.Command.Should().Be(MessageCommand.Disconnect); + + DisconnectionPayload disconnectionPayload = (DisconnectionPayload)message.Payload; + disconnectionPayload.Reason.Should().Be(DisconnectionReason.MaxConnectionReached); + + // return addr + var count = DisconnectionPayload.MaxDataSize; + NetworkAddressWithTime[] addrs = disconnectionPayload.Data.AsSerializableArray(count); + addrs.Length.Should().Be(1); + addrs[0].EndPoint.Port.Should().Be(8080); + + testProbe.ExpectMsg(); + } + } +} diff --git a/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs b/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs index f8b932c4f2..e7a688ab6d 100644 --- a/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs +++ b/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs @@ -9,16 +9,10 @@ namespace Neo.UnitTests.Network.P2P [TestClass] public class UT_ProtocolHandler : TestKit { - private NeoSystem testBlockchain; + private static NeoSystem testBlockchain; - [TestCleanup] - public void Cleanup() - { - Shutdown(); - } - - [TestInitialize] - public void TestSetup() + [ClassInitialize] + public static void TestSetup(TestContext ctx) { testBlockchain = TestBlockchain.InitializeMockNeoSystem(); } @@ -46,5 +40,39 @@ public void ProtocolHandler_Test_SendVersion_TellParent() senderProbe.Send(protocolActor, Message.Create(MessageCommand.Version, payload)); parent.ExpectMsg(); } + + [TestMethod] + public void ProtocolHandler_Test_SendDisconnection_TellParent() + { + var senderProbe = CreateTestProbe(); + var parent = CreateTestProbe(); + var protocolActor = ActorOfAsTestActorRef(() => new ProtocolHandler(testBlockchain), parent); + + // send version + var versionPayload = new VersionPayload() + { + UserAgent = "".PadLeft(1024, '0'), + Nonce = 1, + Magic = 2, + Timestamp = 5, + Version = 6, + Capabilities = new NodeCapability[] + { + new ServerCapability(NodeCapabilityType.TcpServer, 25) + } + }; + + senderProbe.Send(protocolActor, Message.Create(MessageCommand.Version, versionPayload)); + parent.ExpectMsg(); + + // send verack + senderProbe.Send(protocolActor, Message.Create(MessageCommand.Verack)); + parent.ExpectMsg(); + + // send disconnection + var disconnectionPayload = DisconnectionPayload.Create(DisconnectionReason.ConnectionTimeout, "test message"); + senderProbe.Send(protocolActor, Message.Create(MessageCommand.Disconnect, disconnectionPayload)); + parent.ExpectMsg(); + } } } diff --git a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs index 570cc904da..c870f1d693 100644 --- a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs +++ b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs @@ -2,9 +2,12 @@ using Akka.TestKit.Xunit2; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; using Neo.Network.P2P; using Neo.Network.P2P.Capabilities; using Neo.Network.P2P.Payloads; +using System.Linq; +using System.Net; namespace Neo.UnitTests.Network.P2P { @@ -50,7 +53,14 @@ public void RemoteNode_Test_Abort_DifferentMagic() var testProbe = CreateTestProbe(); testProbe.Send(remoteNodeActor, payload); - connectionTestProbe.ExpectMsg(); + var tcpWrite = connectionTestProbe.ExpectMsg(); + Message message = tcpWrite.Data.ToArray().AsSerializable(); + message.Command.Should().Be(MessageCommand.Disconnect); + + DisconnectionPayload disconnectionPayload = (DisconnectionPayload)message.Payload; + disconnectionPayload.Reason.Should().Be(DisconnectionReason.MagicNumberIncompatible); + + connectionTestProbe.ExpectMsg(); } [TestMethod] @@ -82,5 +92,124 @@ public void RemoteNode_Test_Accept_IfSameMagic() //Verack verackMessage.Data.Count.Should().Be(3); } + + [TestMethod] + public void RemoteNode_Test_Received_MaxConnectionReached_Disconnection() + { + var connectionTestProbe = CreateTestProbe(); + var remoteNodeActor = ActorOfAsTestActorRef(() => new RemoteNode(testBlockchain, connectionTestProbe, null, null)); + + connectionTestProbe.ExpectMsg(); // remote node will send version message + LocalNode.Singleton.GetUnconnectedPeers().Count().Should().Be(0); + + //send MaxConnectionReached disconnection + NetworkAddressWithTime[] addressWithTimes = new NetworkAddressWithTime[] + { + new NetworkAddressWithTime() + { + Timestamp = 0, + Address = IPAddress.Parse("192.168.255.255"), + Capabilities = new NodeCapability[] + { + new ServerCapability(NodeCapabilityType.TcpServer, 8080) + } + } + }; + var payload = DisconnectionPayload.Create(DisconnectionReason.MaxConnectionReached, "The maximum number of connections reached!", addressWithTimes.ToByteArray()); + var testProbe = CreateTestProbe(); + testProbe.Send(remoteNodeActor, payload); + + connectionTestProbe.ExpectNoMsg(); + LocalNode.Singleton.GetUnconnectedPeers().Count().Should().Be(1); + var iPEndPoint = LocalNode.Singleton.GetUnconnectedPeers().First(); + iPEndPoint.Should().Be(new IPEndPoint(addressWithTimes[0].Address, 8080)); + } + + + [TestMethod] + public void RemoteNode_Test_Received_Duplicate_Connection() + { + var connectionTestProbeA = CreateTestProbe(); + var Remote = new IPEndPoint(IPAddress.Parse("192.168.255.255"), 8080); + var payload = new VersionPayload() + { + UserAgent = "Unit Test".PadLeft(1024, '0'), + Nonce = 1, + Magic = ProtocolSettings.Default.Magic, + Timestamp = 5, + Version = 6, + Capabilities = new NodeCapability[] + { + new ServerCapability(NodeCapabilityType.TcpServer, 25) + } + }; + + // send to remote node A + var remoteNodeActorA = ActorOfAsTestActorRef(() => new RemoteNode(testBlockchain, connectionTestProbeA, Remote, null)); + connectionTestProbeA.ExpectMsg(); // remote node A will send version message + + var testProbe = CreateTestProbe(); + testProbe.Send(remoteNodeActorA, payload); + + // set remote node B with the same address + var connectionTestProbeB = CreateTestProbe(); + var remoteNodeActorB = ActorOfAsTestActorRef(() => new RemoteNode(testBlockchain, connectionTestProbeB, Remote, null)); + connectionTestProbeB.ExpectMsg(); // remote node B will send version message + + var testProbeB = CreateTestProbe(); + testProbeB.Send(remoteNodeActorB, payload); // send a version message to remote node B, and B will disconnect with `DuplicateConnection` + + var tcpWrite = connectionTestProbeB.ExpectMsg(); + var message = tcpWrite.Data.ToArray().AsSerializable(); + message.Command.Should().Be(MessageCommand.Disconnect); + + var disconnectionPayload = (DisconnectionPayload)message.Payload; + disconnectionPayload.Reason.Should().Be(DisconnectionReason.DuplicateConnection); + + connectionTestProbeB.ExpectMsg(); + } + + [TestMethod] + public void RemoteNode_Test_Received_Invalid_Data() + { + var connectionTestProbe = CreateTestProbe(); + var remoteNodeActor = ActorOfAsTestActorRef(() => new RemoteNode(testBlockchain, connectionTestProbe, null, null)); + connectionTestProbe.ExpectMsg(); // remote node will send version message + + // The `length` field of this message is 0x300000000000, which is more than PayloadMaxSize = 0x02000000 + // Message.cs#TryDeserialize will throw a FormatException + Tcp.Received received = new Tcp.Received(ByteString.FromBytes(new byte[] { 0x02, 0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 })); + var testProbe = CreateTestProbe(); + testProbe.Send(remoteNodeActor, received); // remote node will parse failed + + var tcpWrite = connectionTestProbe.ExpectMsg(); + var message = tcpWrite.Data.ToArray().AsSerializable(); + message.Command.Should().Be(MessageCommand.Disconnect); + + var disconnectionPayload = (DisconnectionPayload)message.Payload; + disconnectionPayload.Reason.Should().Be(DisconnectionReason.FormatExcpetion); + + connectionTestProbe.ExpectMsg(); + } + + [TestMethod] + public void Connection_Test_Timeout() + { + var connectionTestProbe = CreateTestProbe(); + var remoteNodeActor = ActorOfAsTestActorRef(() => new RemoteNode(testBlockchain, connectionTestProbe, null, null)); + connectionTestProbe.ExpectMsg(); // remote node will send version message + + var testProbe = CreateTestProbe(); + testProbe.Send(remoteNodeActor, Connection.Timer.Instance); // remote node will disconnect with `ConnectionTimeout` + + var tcpWrite = connectionTestProbe.ExpectMsg(); + var message = tcpWrite.Data.ToArray().AsSerializable(); + message.Command.Should().Be(MessageCommand.Disconnect); + + var disconnectionPayload = (DisconnectionPayload)message.Payload; + disconnectionPayload.Reason.Should().Be(DisconnectionReason.ConnectionTimeout); + + connectionTestProbe.ExpectMsg(); + } } } diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index 5a00a588ef..b78f9abb52 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -1,5 +1,7 @@ using Akka.Actor; using Akka.IO; +using Neo.IO; +using Neo.Network.P2P.Payloads; using System; using System.Net; using System.Net.WebSockets; @@ -66,12 +68,15 @@ private void WsReceive() failure: ex => new Tcp.ErrorClosed(ex.Message)); } - public void Disconnect(bool abort = false) + protected void Disconnect(DisconnectionReason reason, string message = "", byte[] data = null) { disconnected = true; if (tcp != null) { - tcp.Tell(abort ? (Tcp.CloseCommand)Tcp.Abort.Instance : Tcp.Close.Instance); + var payload = DisconnectionPayload.Create(reason, message, data); + var disconnectMessage = Message.Create(MessageCommand.Disconnect, payload); + tcp.Tell(Tcp.Write.Create((ByteString.FromBytes(disconnectMessage.ToArray())))); + tcp.Tell(Tcp.Close.Instance); } else { @@ -91,7 +96,7 @@ protected override void OnReceive(object message) switch (message) { case Timer _: - Disconnect(true); + Disconnect(DisconnectionReason.ConnectionTimeout, $"Connection timeout after {connectionTimeoutLimit} seconds!"); break; case Ack _: OnAck(); @@ -112,10 +117,13 @@ private void OnReceived(ByteString data) try { OnData(data); + }catch(FormatException) + { + Disconnect(DisconnectionReason.FormatExcpetion, "Parse data failed!"); } catch { - Disconnect(true); + Disconnect(DisconnectionReason.InternalError); } } diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index 79ad7fb096..10071328a3 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -134,6 +134,17 @@ protected override void NeedMorePeers(int count) } } + public override NetworkAddressWithTime[] GetRandomConnectedPeers(int count) + { + Random rand = new Random(); + IEnumerable peers = RemoteNodes.Values + .Where(p => p.ListenerTcpPort > 0) + .GroupBy(p => p.Remote.Address, (k, g) => g.First()) + .OrderBy(p => rand.Next()) + .Take(AddrPayload.MaxCountToSend); + return peers.Select(p => NetworkAddressWithTime.Create(p.Listener.Address, p.Version.Timestamp, p.Version.Capabilities)).ToArray(); + } + protected override void OnReceive(object message) { base.OnReceive(message); diff --git a/neo/Network/P2P/Message.cs b/neo/Network/P2P/Message.cs index 61ee4493b4..d9ebee7f73 100644 --- a/neo/Network/P2P/Message.cs +++ b/neo/Network/P2P/Message.cs @@ -92,6 +92,9 @@ private void DecompressPayload() case MessageCommand.MerkleBlock: Payload = decompressed.AsSerializable(); break; + case MessageCommand.Disconnect: + Payload = decompressed.AsSerializable(); + break; } } diff --git a/neo/Network/P2P/MessageCommand.cs b/neo/Network/P2P/MessageCommand.cs index ed8dc6b96b..d9b1025b29 100644 --- a/neo/Network/P2P/MessageCommand.cs +++ b/neo/Network/P2P/MessageCommand.cs @@ -11,6 +11,7 @@ public enum MessageCommand : byte Addr = 0x11, Ping = 0x18, Pong = 0x19, + Disconnect = 0x88, //synchronization GetHeaders = 0x20, diff --git a/neo/Network/P2P/Payloads/DisconnectionPayload.cs b/neo/Network/P2P/Payloads/DisconnectionPayload.cs new file mode 100644 index 0000000000..e41ba31570 --- /dev/null +++ b/neo/Network/P2P/Payloads/DisconnectionPayload.cs @@ -0,0 +1,55 @@ +using Neo.IO; +using System.IO; + +namespace Neo.Network.P2P.Payloads +{ + public enum DisconnectionReason : byte + { + MaxConnectionReached = 0x01, + MaxPerAddressConnectionReached = 0x02, + DuplicateConnection = 0x03, + MagicNumberIncompatible = 0x04, + ConnectionTimeout = 0x05, + UntrustedIpAddresses = 0x06, + + FormatExcpetion = 0x10, + InternalError = 0x11, + } + + public class DisconnectionPayload : ISerializable + { + + public const int MaxDataSize = 5120; + + public DisconnectionReason Reason; + public string Message; + public byte[] Data; + + public int Size => sizeof(DisconnectionReason) + Message.GetVarSize() + Data.GetVarSize(); + + + public static DisconnectionPayload Create(DisconnectionReason reason, string message = "", byte[] data = null) + { + return new DisconnectionPayload + { + Reason = reason, + Message = message, + Data = data == null ? new byte[0] : data + }; + } + + public void Deserialize(BinaryReader reader) + { + Reason = (DisconnectionReason) reader.ReadByte(); + Message = reader.ReadString(); + Data = reader.ReadVarBytes(MaxDataSize); + } + + public void Serialize(BinaryWriter writer) + { + writer.Write((byte)Reason); + writer.Write(Message); + writer.WriteVarBytes(Data); + } + } +} diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index 0cbd6cbaff..5ca44c3f48 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Neo.IO; +using Neo.Network.P2P.Payloads; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -35,7 +36,7 @@ private class WsConnected { public WebSocket Socket; public IPEndPoint Remote; p private static readonly HashSet localAddresses = new HashSet(); private readonly Dictionary ConnectedAddresses = new Dictionary(); - protected readonly ConcurrentDictionary ConnectedPeers = new ConcurrentDictionary(); + protected readonly ConcurrentDictionary> ConnectedPeers = new ConcurrentDictionary>(); protected ImmutableHashSet UnconnectedPeers = ImmutableHashSet.Empty; protected ImmutableHashSet ConnectingPeers = ImmutableHashSet.Empty; protected HashSet TrustedIpAddresses { get; } = new HashSet(); @@ -71,6 +72,14 @@ protected void AddPeers(IEnumerable peers) } } + public void AddRemoteNodeListenerIPEndPoint(IActorRef remoteActorRef, IPEndPoint listener) + { + if (ConnectedPeers.TryGetValue(remoteActorRef, out List endPoints)) + { + endPoints.Add(listener); + } + } + protected void ConnectToPeer(IPEndPoint endPoint, bool isTrusted = false) { endPoint = endPoint.Unmap(); @@ -79,7 +88,7 @@ protected void ConnectToPeer(IPEndPoint endPoint, bool isTrusted = false) if (isTrusted) TrustedIpAddresses.Add(endPoint.Address); if (ConnectedAddresses.TryGetValue(endPoint.Address, out int count) && count >= MaxConnectionsPerAddress) return; - if (ConnectedPeers.Values.Contains(endPoint)) return; + if (ConnectedPeers.Values.SelectMany(p => p).ToList().Contains(endPoint)) return; ImmutableInterlocked.Update(ref ConnectingPeers, p => { if ((p.Count >= ConnectingMax && !isTrusted) || p.Contains(endPoint)) return p; @@ -98,6 +107,8 @@ private static bool IsIntranetAddress(IPAddress address) protected abstract void NeedMorePeers(int count); + public abstract NetworkAddressWithTime[] GetRandomConnectedPeers(int count); + protected override void OnReceive(object message) { switch (message) @@ -177,16 +188,21 @@ private void OnStart(ChannelsConfig config) private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) { ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); - if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) + if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections) { - Sender.Tell(Tcp.Abort.Instance); + DisconnectWithAddresses(DisconnectionReason.MaxConnectionReached, "The maximum number of connections reached!"); + return; + } + if (TrustedIpAddresses.Count > 0 && !TrustedIpAddresses.Contains(remote.Address)) + { + Disconnect(DisconnectionReason.UntrustedIpAddresses, $"Untrusted ip address: {remote.Address}"); return; } - ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { - Sender.Tell(Tcp.Abort.Instance); + DisconnectWithAddresses(DisconnectionReason.MaxPerAddressConnectionReached, "The maximum number of per address connections reached!"); + return; } else { @@ -194,10 +210,25 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) IActorRef connection = Context.ActorOf(ProtocolProps(Sender, remote, local), $"connection_{Guid.NewGuid()}"); Context.Watch(connection); Sender.Tell(new Tcp.Register(connection)); - ConnectedPeers.TryAdd(connection, remote); + ConnectedPeers.TryAdd(connection, new List { remote }); } } + private void DisconnectWithAddresses(DisconnectionReason reason, string message) + { + NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); + Disconnect(reason, message, networkAddresses.ToByteArray()); + } + + private void Disconnect(DisconnectionReason reason, string message = "", byte[] data = null) + { + var payload = DisconnectionPayload.Create(reason, message, data); + var disconnect = Message.Create(MessageCommand.Disconnect, payload); + var command = Tcp.Write.Create(ByteString.FromBytes(disconnect.ToArray())); + Sender.Tell(command); + Sender.Tell(Tcp.Close.Instance); + } + private void OnTcpCommandFailed(Tcp.Command cmd) { switch (cmd) @@ -210,8 +241,9 @@ private void OnTcpCommandFailed(Tcp.Command cmd) private void OnTerminated(IActorRef actorRef) { - if (ConnectedPeers.TryRemove(actorRef, out IPEndPoint endPoint)) + if (ConnectedPeers.TryRemove(actorRef, out List endPoints)) { + IPEndPoint endPoint = endPoints[0]; ConnectedAddresses.TryGetValue(endPoint.Address, out int count); if (count > 0) count--; if (count == 0) diff --git a/neo/Network/P2P/ProtocolHandler.cs b/neo/Network/P2P/ProtocolHandler.cs index aa7f0e06f2..796b501a44 100644 --- a/neo/Network/P2P/ProtocolHandler.cs +++ b/neo/Network/P2P/ProtocolHandler.cs @@ -105,6 +105,9 @@ protected override void OnReceive(object message) if (msg.Payload.Size <= Transaction.MaxTransactionSize) OnInventoryReceived((Transaction)msg.Payload); break; + case MessageCommand.Disconnect: + OnDisconnectRecived((DisconnectionPayload)msg.Payload); + break; case MessageCommand.Verack: case MessageCommand.Version: throw new ProtocolViolationException(); @@ -144,13 +147,7 @@ private void OnFilterLoadMessageReceived(FilterLoadPayload payload) private void OnGetAddrMessageReceived() { - Random rand = new Random(); - IEnumerable peers = LocalNode.Singleton.RemoteNodes.Values - .Where(p => p.ListenerTcpPort > 0) - .GroupBy(p => p.Remote.Address, (k, g) => g.First()) - .OrderBy(p => rand.Next()) - .Take(AddrPayload.MaxCountToSend); - NetworkAddressWithTime[] networkAddresses = peers.Select(p => NetworkAddressWithTime.Create(p.Listener.Address, p.Version.Timestamp, p.Version.Capabilities)).ToArray(); + NetworkAddressWithTime[] networkAddresses = LocalNode.Singleton.GetRandomConnectedPeers(AddrPayload.MaxCountToSend); if (networkAddresses.Length == 0) return; Context.Parent.Tell(Message.Create(MessageCommand.Addr, AddrPayload.Create(networkAddresses))); } @@ -291,6 +288,11 @@ private void OnVersionMessageReceived(VersionPayload payload) Context.Parent.Tell(payload); } + private void OnDisconnectRecived(DisconnectionPayload payload) + { + Context.Parent.Tell(payload); + } + public static Props Props(NeoSystem system) { return Akka.Actor.Props.Create(() => new ProtocolHandler(system)).WithMailbox("protocol-handler-mailbox"); diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index ec2a16e047..46153bd78e 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -7,6 +7,7 @@ using Neo.Ledger; using Neo.Network.P2P.Capabilities; using Neo.Network.P2P.Payloads; +using System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -43,7 +44,6 @@ public RemoteNode(NeoSystem system, object connection, IPEndPoint remote, IPEndP { new FullNodeCapability(Blockchain.Singleton.Height) }; - if (LocalNode.Singleton.ListenerTcpPort > 0) capabilities.Add(new ServerCapability(NodeCapabilityType.TcpServer, (ushort)LocalNode.Singleton.ListenerTcpPort)); if (LocalNode.Singleton.ListenerWsPort > 0) capabilities.Add(new ServerCapability(NodeCapabilityType.WsServer, (ushort)LocalNode.Singleton.ListenerWsPort)); @@ -112,7 +112,6 @@ protected override void OnAck() protected override void OnData(ByteString data) { msg_buffer = msg_buffer.Concat(data); - for (Message message = TryParseMessage(); message != null; message = TryParseMessage()) protocol.Tell(message); } @@ -137,6 +136,9 @@ protected override void OnReceive(object message) case MessageCommand.Verack: OnVerack(); break; + case DisconnectionPayload payload: + OnDisconnectPayload(payload); + break; case ProtocolHandler.SetFilter setFilter: OnSetFilter(setFilter.Filter); break; @@ -205,17 +207,39 @@ private void OnVersionPayload(VersionPayload version) } if (version.Nonce == LocalNode.Nonce || version.Magic != ProtocolSettings.Default.Magic) { - Disconnect(true); + Disconnect(DisconnectionReason.MagicNumberIncompatible, "Incomppatible magic number!"); return; } - if (LocalNode.Singleton.RemoteNodes.Values.Where(p => p != this).Any(p => p.Remote.Address.Equals(Remote.Address) && p.Version?.Nonce == version.Nonce)) + if (LocalNode.Singleton.RemoteNodes.Values.Where(p => p != this).Any(p => p.Remote != null && Remote != null && p.Remote.Address.Equals(Remote.Address) && p.Version?.Nonce == version.Nonce)) { - Disconnect(true); + Disconnect(DisconnectionReason.DuplicateConnection, "Duplicate connection!"); return; } SendMessage(Message.Create(MessageCommand.Verack)); } + private void OnDisconnectPayload(DisconnectionPayload payload) + { + switch (payload.Reason) + { + case DisconnectionReason.MaxConnectionReached: + try + { + NetworkAddressWithTime[] addressList = payload.Data.AsSerializableArray(AddrPayload.MaxCountToSend); + system.LocalNode.Tell(new Peer.Peers + { + EndPoints = addressList.Select(p => p.EndPoint).Where(p => p.Port > 0) + }); + } + catch (FormatException) { } + break; + case DisconnectionReason.DuplicateConnection: + LocalNode.Singleton.AddRemoteNodeListenerIPEndPoint(Self, Listener); + break; + default: break; + } + } + protected override void PostStop() { LocalNode.Singleton.RemoteNodes.TryRemove(Self, out _); @@ -237,7 +261,7 @@ protected override SupervisorStrategy SupervisorStrategy() { return new OneForOneStrategy(ex => { - Disconnect(true); + Disconnect(DisconnectionReason.InternalError); return Directive.Stop; }, loggingEnabled: false); } @@ -245,7 +269,11 @@ protected override SupervisorStrategy SupervisorStrategy() private Message TryParseMessage() { var length = Message.TryDeserialize(msg_buffer, out var msg); - if (length <= 0) return null; + if (length <= 0) + { + msg_buffer = ByteString.Empty; + return null; + } msg_buffer = msg_buffer.Slice(length).Compact(); return msg; From 85f6103bddb6db55b9d5c928b3e352e36c19ed3c Mon Sep 17 00:00:00 2001 From: luchuan Date: Thu, 10 Oct 2019 18:31:07 +0800 Subject: [PATCH 03/84] rename DisconnectionPayload to DisconnectPayload --- ...ctionPayload.cs => UT_DisconnectPayload.cs} | 10 +++++----- neo.UnitTests/Network/P2P/UT_LocalNode.cs | 12 ++++++------ .../Network/P2P/UT_ProtocolHandler.cs | 4 ++-- neo.UnitTests/Network/P2P/UT_RemoteNode.cs | 18 +++++++++--------- neo/Network/P2P/Connection.cs | 10 +++++----- neo/Network/P2P/Message.cs | 2 +- ...nnectionPayload.cs => DisconnectPayload.cs} | 14 +++++++------- neo/Network/P2P/Peer.cs | 12 ++++++------ neo/Network/P2P/ProtocolHandler.cs | 4 ++-- neo/Network/P2P/RemoteNode.cs | 14 +++++++------- 10 files changed, 50 insertions(+), 50 deletions(-) rename neo.UnitTests/Network/P2P/Payloads/{UT_DisconnectionPayload.cs => UT_DisconnectPayload.cs} (70%) rename neo/Network/P2P/Payloads/{DisconnectionPayload.cs => DisconnectPayload.cs} (68%) diff --git a/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectionPayload.cs b/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectPayload.cs similarity index 70% rename from neo.UnitTests/Network/P2P/Payloads/UT_DisconnectionPayload.cs rename to neo.UnitTests/Network/P2P/Payloads/UT_DisconnectPayload.cs index 8d3d3b2fef..c18be98a0c 100644 --- a/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectionPayload.cs +++ b/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectPayload.cs @@ -7,19 +7,19 @@ namespace Neo.UnitTests.Network.P2P.Payloads { [TestClass] - public class UT_DisconnectionPayload + public class UT_DisconnectPayload { [TestMethod] public void Size_Get() { - var payload = DisconnectionPayload.Create(DisconnectionReason.DuplicateConnection, "test message", new byte[] { 0x01, 0x02 }); + var payload = DisconnectPayload.Create(DisconnectReason.DuplicateConnection, "test message", new byte[] { 0x01, 0x02 }); payload.Size.Should().Be(17); } [TestMethod] public void Deserialize() { - var payload = new DisconnectionPayload(); + var payload = new DisconnectPayload(); var hex = "030c74657374206d657373616765020102"; using (MemoryStream ms = new MemoryStream(hex.HexToBytes(), false)) { @@ -28,7 +28,7 @@ public void Deserialize() payload.Deserialize(reader); } } - Assert.AreEqual(DisconnectionReason.DuplicateConnection, payload.Reason); + Assert.AreEqual(DisconnectReason.DuplicateConnection, payload.Reason); Assert.AreEqual("test message", payload.Message); Assert.AreEqual(2, payload.Data.Length); Assert.AreEqual(0x01, payload.Data[0]); @@ -38,7 +38,7 @@ public void Deserialize() [TestMethod] public void Serialize() { - var payload = DisconnectionPayload.Create(DisconnectionReason.DuplicateConnection, "test message", new byte[] { 0x01, 0x02 }); + var payload = DisconnectPayload.Create(DisconnectReason.DuplicateConnection, "test message", new byte[] { 0x01, 0x02 }); payload.ToArray().ToHexString().Should().Be("030c74657374206d657373616765020102"); } } diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 712175a36b..b0c1240b36 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -130,11 +130,11 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() message = tcpWrite.Data.ToArray().AsSerializable(); message.Command.Should().Be(MessageCommand.Disconnect); - DisconnectionPayload disconnectionPayload = (DisconnectionPayload)message.Payload; - disconnectionPayload.Reason.Should().Be(DisconnectionReason.MaxPerAddressConnectionReached); + var disconnectionPayload = (DisconnectPayload)message.Payload; + disconnectionPayload.Reason.Should().Be(DisconnectReason.MaxPerAddressConnectionReached); // return addr - var count = DisconnectionPayload.MaxDataSize; + var count = DisconnectPayload.MaxDataSize; NetworkAddressWithTime[] addrs = disconnectionPayload.Data.AsSerializableArray(count); addrs.Length.Should().Be(1); addrs[0].EndPoint.Address.Should().BeEquivalentTo(IPAddress.Parse("192.168.1.1")); @@ -195,11 +195,11 @@ public void Test_Peer_MaxConnection_Reached() Message message = tcpWrite.Data.ToArray().AsSerializable(); message.Command.Should().Be(MessageCommand.Disconnect); - DisconnectionPayload disconnectionPayload = (DisconnectionPayload)message.Payload; - disconnectionPayload.Reason.Should().Be(DisconnectionReason.MaxConnectionReached); + var disconnectionPayload = (DisconnectPayload)message.Payload; + disconnectionPayload.Reason.Should().Be(DisconnectReason.MaxConnectionReached); // return addr - var count = DisconnectionPayload.MaxDataSize; + var count = DisconnectPayload.MaxDataSize; NetworkAddressWithTime[] addrs = disconnectionPayload.Data.AsSerializableArray(count); addrs.Length.Should().Be(1); addrs[0].EndPoint.Port.Should().Be(8080); diff --git a/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs b/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs index e7a688ab6d..eb570fa305 100644 --- a/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs +++ b/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs @@ -70,9 +70,9 @@ public void ProtocolHandler_Test_SendDisconnection_TellParent() parent.ExpectMsg(); // send disconnection - var disconnectionPayload = DisconnectionPayload.Create(DisconnectionReason.ConnectionTimeout, "test message"); + var disconnectionPayload = DisconnectPayload.Create(DisconnectReason.ConnectionTimeout, "test message"); senderProbe.Send(protocolActor, Message.Create(MessageCommand.Disconnect, disconnectionPayload)); - parent.ExpectMsg(); + parent.ExpectMsg(); } } } diff --git a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs index c870f1d693..60855ce5ce 100644 --- a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs +++ b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs @@ -57,8 +57,8 @@ public void RemoteNode_Test_Abort_DifferentMagic() Message message = tcpWrite.Data.ToArray().AsSerializable(); message.Command.Should().Be(MessageCommand.Disconnect); - DisconnectionPayload disconnectionPayload = (DisconnectionPayload)message.Payload; - disconnectionPayload.Reason.Should().Be(DisconnectionReason.MagicNumberIncompatible); + var disconnectionPayload = (DisconnectPayload)message.Payload; + disconnectionPayload.Reason.Should().Be(DisconnectReason.MagicNumberIncompatible); connectionTestProbe.ExpectMsg(); } @@ -115,7 +115,7 @@ public void RemoteNode_Test_Received_MaxConnectionReached_Disconnection() } } }; - var payload = DisconnectionPayload.Create(DisconnectionReason.MaxConnectionReached, "The maximum number of connections reached!", addressWithTimes.ToByteArray()); + var payload = DisconnectPayload.Create(DisconnectReason.MaxConnectionReached, "The maximum number of connections reached!", addressWithTimes.ToByteArray()); var testProbe = CreateTestProbe(); testProbe.Send(remoteNodeActor, payload); @@ -163,8 +163,8 @@ public void RemoteNode_Test_Received_Duplicate_Connection() var message = tcpWrite.Data.ToArray().AsSerializable(); message.Command.Should().Be(MessageCommand.Disconnect); - var disconnectionPayload = (DisconnectionPayload)message.Payload; - disconnectionPayload.Reason.Should().Be(DisconnectionReason.DuplicateConnection); + var disconnectionPayload = (DisconnectPayload)message.Payload; + disconnectionPayload.Reason.Should().Be(DisconnectReason.DuplicateConnection); connectionTestProbeB.ExpectMsg(); } @@ -186,8 +186,8 @@ public void RemoteNode_Test_Received_Invalid_Data() var message = tcpWrite.Data.ToArray().AsSerializable(); message.Command.Should().Be(MessageCommand.Disconnect); - var disconnectionPayload = (DisconnectionPayload)message.Payload; - disconnectionPayload.Reason.Should().Be(DisconnectionReason.FormatExcpetion); + var disconnectionPayload = (DisconnectPayload)message.Payload; + disconnectionPayload.Reason.Should().Be(DisconnectReason.FormatExcpetion); connectionTestProbe.ExpectMsg(); } @@ -206,8 +206,8 @@ public void Connection_Test_Timeout() var message = tcpWrite.Data.ToArray().AsSerializable(); message.Command.Should().Be(MessageCommand.Disconnect); - var disconnectionPayload = (DisconnectionPayload)message.Payload; - disconnectionPayload.Reason.Should().Be(DisconnectionReason.ConnectionTimeout); + var disconnectionPayload = (DisconnectPayload)message.Payload; + disconnectionPayload.Reason.Should().Be(DisconnectReason.ConnectionTimeout); connectionTestProbe.ExpectMsg(); } diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index b78f9abb52..8a9eb71556 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -68,12 +68,12 @@ private void WsReceive() failure: ex => new Tcp.ErrorClosed(ex.Message)); } - protected void Disconnect(DisconnectionReason reason, string message = "", byte[] data = null) + protected void Disconnect(DisconnectReason reason, string message = "", byte[] data = null) { disconnected = true; if (tcp != null) { - var payload = DisconnectionPayload.Create(reason, message, data); + var payload = DisconnectPayload.Create(reason, message, data); var disconnectMessage = Message.Create(MessageCommand.Disconnect, payload); tcp.Tell(Tcp.Write.Create((ByteString.FromBytes(disconnectMessage.ToArray())))); tcp.Tell(Tcp.Close.Instance); @@ -96,7 +96,7 @@ protected override void OnReceive(object message) switch (message) { case Timer _: - Disconnect(DisconnectionReason.ConnectionTimeout, $"Connection timeout after {connectionTimeoutLimit} seconds!"); + Disconnect(DisconnectReason.ConnectionTimeout, $"Connection timeout after {connectionTimeoutLimit} seconds!"); break; case Ack _: OnAck(); @@ -119,11 +119,11 @@ private void OnReceived(ByteString data) OnData(data); }catch(FormatException) { - Disconnect(DisconnectionReason.FormatExcpetion, "Parse data failed!"); + Disconnect(DisconnectReason.FormatExcpetion, "Parse data failed!"); } catch { - Disconnect(DisconnectionReason.InternalError); + Disconnect(DisconnectReason.InternalError); } } diff --git a/neo/Network/P2P/Message.cs b/neo/Network/P2P/Message.cs index d9ebee7f73..c0501fbbe0 100644 --- a/neo/Network/P2P/Message.cs +++ b/neo/Network/P2P/Message.cs @@ -93,7 +93,7 @@ private void DecompressPayload() Payload = decompressed.AsSerializable(); break; case MessageCommand.Disconnect: - Payload = decompressed.AsSerializable(); + Payload = decompressed.AsSerializable(); break; } } diff --git a/neo/Network/P2P/Payloads/DisconnectionPayload.cs b/neo/Network/P2P/Payloads/DisconnectPayload.cs similarity index 68% rename from neo/Network/P2P/Payloads/DisconnectionPayload.cs rename to neo/Network/P2P/Payloads/DisconnectPayload.cs index e41ba31570..6277ebc83e 100644 --- a/neo/Network/P2P/Payloads/DisconnectionPayload.cs +++ b/neo/Network/P2P/Payloads/DisconnectPayload.cs @@ -3,7 +3,7 @@ namespace Neo.Network.P2P.Payloads { - public enum DisconnectionReason : byte + public enum DisconnectReason : byte { MaxConnectionReached = 0x01, MaxPerAddressConnectionReached = 0x02, @@ -16,21 +16,21 @@ public enum DisconnectionReason : byte InternalError = 0x11, } - public class DisconnectionPayload : ISerializable + public class DisconnectPayload : ISerializable { public const int MaxDataSize = 5120; - public DisconnectionReason Reason; + public DisconnectReason Reason; public string Message; public byte[] Data; - public int Size => sizeof(DisconnectionReason) + Message.GetVarSize() + Data.GetVarSize(); + public int Size => sizeof(DisconnectReason) + Message.GetVarSize() + Data.GetVarSize(); - public static DisconnectionPayload Create(DisconnectionReason reason, string message = "", byte[] data = null) + public static DisconnectPayload Create(DisconnectReason reason, string message = "", byte[] data = null) { - return new DisconnectionPayload + return new DisconnectPayload { Reason = reason, Message = message, @@ -40,7 +40,7 @@ public static DisconnectionPayload Create(DisconnectionReason reason, string mes public void Deserialize(BinaryReader reader) { - Reason = (DisconnectionReason) reader.ReadByte(); + Reason = (DisconnectReason) reader.ReadByte(); Message = reader.ReadString(); Data = reader.ReadVarBytes(MaxDataSize); } diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index 5ca44c3f48..084e5f2216 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -190,18 +190,18 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections) { - DisconnectWithAddresses(DisconnectionReason.MaxConnectionReached, "The maximum number of connections reached!"); + DisconnectWithAddresses(DisconnectReason.MaxConnectionReached, "The maximum number of connections reached!"); return; } if (TrustedIpAddresses.Count > 0 && !TrustedIpAddresses.Contains(remote.Address)) { - Disconnect(DisconnectionReason.UntrustedIpAddresses, $"Untrusted ip address: {remote.Address}"); + Disconnect(DisconnectReason.UntrustedIpAddresses, $"Untrusted ip address: {remote.Address}"); return; } ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { - DisconnectWithAddresses(DisconnectionReason.MaxPerAddressConnectionReached, "The maximum number of per address connections reached!"); + DisconnectWithAddresses(DisconnectReason.MaxPerAddressConnectionReached, "The maximum number of per address connections reached!"); return; } else @@ -214,15 +214,15 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) } } - private void DisconnectWithAddresses(DisconnectionReason reason, string message) + private void DisconnectWithAddresses(DisconnectReason reason, string message) { NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); Disconnect(reason, message, networkAddresses.ToByteArray()); } - private void Disconnect(DisconnectionReason reason, string message = "", byte[] data = null) + private void Disconnect(DisconnectReason reason, string message = "", byte[] data = null) { - var payload = DisconnectionPayload.Create(reason, message, data); + var payload = DisconnectPayload.Create(reason, message, data); var disconnect = Message.Create(MessageCommand.Disconnect, payload); var command = Tcp.Write.Create(ByteString.FromBytes(disconnect.ToArray())); Sender.Tell(command); diff --git a/neo/Network/P2P/ProtocolHandler.cs b/neo/Network/P2P/ProtocolHandler.cs index 796b501a44..b47ee2fca5 100644 --- a/neo/Network/P2P/ProtocolHandler.cs +++ b/neo/Network/P2P/ProtocolHandler.cs @@ -106,7 +106,7 @@ protected override void OnReceive(object message) OnInventoryReceived((Transaction)msg.Payload); break; case MessageCommand.Disconnect: - OnDisconnectRecived((DisconnectionPayload)msg.Payload); + OnDisconnectRecived((DisconnectPayload)msg.Payload); break; case MessageCommand.Verack: case MessageCommand.Version: @@ -288,7 +288,7 @@ private void OnVersionMessageReceived(VersionPayload payload) Context.Parent.Tell(payload); } - private void OnDisconnectRecived(DisconnectionPayload payload) + private void OnDisconnectRecived(DisconnectPayload payload) { Context.Parent.Tell(payload); } diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index 46153bd78e..74453e95c2 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -136,7 +136,7 @@ protected override void OnReceive(object message) case MessageCommand.Verack: OnVerack(); break; - case DisconnectionPayload payload: + case DisconnectPayload payload: OnDisconnectPayload(payload); break; case ProtocolHandler.SetFilter setFilter: @@ -207,22 +207,22 @@ private void OnVersionPayload(VersionPayload version) } if (version.Nonce == LocalNode.Nonce || version.Magic != ProtocolSettings.Default.Magic) { - Disconnect(DisconnectionReason.MagicNumberIncompatible, "Incomppatible magic number!"); + Disconnect(DisconnectReason.MagicNumberIncompatible, "Incomppatible magic number!"); return; } if (LocalNode.Singleton.RemoteNodes.Values.Where(p => p != this).Any(p => p.Remote != null && Remote != null && p.Remote.Address.Equals(Remote.Address) && p.Version?.Nonce == version.Nonce)) { - Disconnect(DisconnectionReason.DuplicateConnection, "Duplicate connection!"); + Disconnect(DisconnectReason.DuplicateConnection, "Duplicate connection!"); return; } SendMessage(Message.Create(MessageCommand.Verack)); } - private void OnDisconnectPayload(DisconnectionPayload payload) + private void OnDisconnectPayload(DisconnectPayload payload) { switch (payload.Reason) { - case DisconnectionReason.MaxConnectionReached: + case DisconnectReason.MaxConnectionReached: try { NetworkAddressWithTime[] addressList = payload.Data.AsSerializableArray(AddrPayload.MaxCountToSend); @@ -233,7 +233,7 @@ private void OnDisconnectPayload(DisconnectionPayload payload) } catch (FormatException) { } break; - case DisconnectionReason.DuplicateConnection: + case DisconnectReason.DuplicateConnection: LocalNode.Singleton.AddRemoteNodeListenerIPEndPoint(Self, Listener); break; default: break; @@ -261,7 +261,7 @@ protected override SupervisorStrategy SupervisorStrategy() { return new OneForOneStrategy(ex => { - Disconnect(DisconnectionReason.InternalError); + Disconnect(DisconnectReason.InternalError); return Directive.Stop; }, loggingEnabled: false); } From bfef98236dcf0233b4ea883cbe8fd0b8500b3d3a Mon Sep 17 00:00:00 2001 From: luchuan Date: Fri, 11 Oct 2019 14:46:54 +0800 Subject: [PATCH 04/84] remove OnDisconnect handler from RemoteNode to LocalNode as tcp.close is high priority --- neo.UnitTests/Network/P2P/UT_LocalNode.cs | 25 ++++++++++ .../Network/P2P/UT_ProtocolHandler.cs | 49 +++++++++---------- neo.UnitTests/Network/P2P/UT_RemoteNode.cs | 34 ------------- neo/Network/P2P/Connection.cs | 1 + neo/Network/P2P/LocalNode.cs | 42 ++++++++++++++++ neo/Network/P2P/Peer.cs | 9 +--- neo/Network/P2P/ProtocolHandler.cs | 13 +++-- neo/Network/P2P/RemoteNode.cs | 46 +++++------------ 8 files changed, 112 insertions(+), 107 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index b0c1240b36..823724a099 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -206,5 +206,30 @@ public void Test_Peer_MaxConnection_Reached() testProbe.ExpectMsg(); } + + [TestMethod] + public void Test_Received_MaxConnectionReached_Disconnection() + { + //send MaxConnectionReached disconnection + NetworkAddressWithTime[] addressWithTimes = new NetworkAddressWithTime[] + { + new NetworkAddressWithTime() + { + Timestamp = 0, + Address = IPAddress.Parse("192.167.1.1"), + Capabilities = new NodeCapability[] + { + new ServerCapability(NodeCapabilityType.TcpServer, 8080) + } + } + }; + + var payload = DisconnectPayload.Create(DisconnectReason.MaxConnectionReached, "The maximum number of connections reached!", addressWithTimes.ToByteArray()); + var testProbe = CreateTestProbe(); + testProbe.Send(testBlockchain.LocalNode, payload); + + testProbe.ExpectNoMsg(); + LocalNode.Singleton.GetUnconnectedPeers().Any(p => p.Equals(new IPEndPoint(IPAddress.Parse("192.167.1.1"), 8080))).Should().BeTrue(); + } } } diff --git a/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs b/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs index eb570fa305..bc80fca0b7 100644 --- a/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs +++ b/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs @@ -1,8 +1,12 @@ using Akka.TestKit.Xunit2; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; using Neo.Network.P2P; using Neo.Network.P2P.Capabilities; using Neo.Network.P2P.Payloads; +using System.Linq; +using System.Net; namespace Neo.UnitTests.Network.P2P { @@ -42,37 +46,28 @@ public void ProtocolHandler_Test_SendVersion_TellParent() } [TestMethod] - public void ProtocolHandler_Test_SendDisconnection_TellParent() + public void ProtocolHandler_Test_SendDisconnection_Tell_LocalNode() { - var senderProbe = CreateTestProbe(); - var parent = CreateTestProbe(); - var protocolActor = ActorOfAsTestActorRef(() => new ProtocolHandler(testBlockchain), parent); - - // send version - var versionPayload = new VersionPayload() + // send disconnection message as max connection reached + var addressWithTimes = new NetworkAddressWithTime[] { - UserAgent = "".PadLeft(1024, '0'), - Nonce = 1, - Magic = 2, - Timestamp = 5, - Version = 6, - Capabilities = new NodeCapability[] - { - new ServerCapability(NodeCapabilityType.TcpServer, 25) - } + new NetworkAddressWithTime() + { + Timestamp = 0, + Address = IPAddress.Parse("192.166.1.1"), + Capabilities = new NodeCapability[] + { + new ServerCapability(NodeCapabilityType.TcpServer, 8080) + } + } }; - - senderProbe.Send(protocolActor, Message.Create(MessageCommand.Version, versionPayload)); - parent.ExpectMsg(); - - // send verack - senderProbe.Send(protocolActor, Message.Create(MessageCommand.Verack)); - parent.ExpectMsg(); - - // send disconnection - var disconnectionPayload = DisconnectPayload.Create(DisconnectReason.ConnectionTimeout, "test message"); + var protocolActor = ActorOfAsTestActorRef(() => new ProtocolHandler(testBlockchain)); + var disconnectionPayload = DisconnectPayload.Create(DisconnectReason.MaxConnectionReached, "The maximum number of connections reached!", addressWithTimes.ToByteArray()); + var senderProbe = CreateTestProbe(); senderProbe.Send(protocolActor, Message.Create(MessageCommand.Disconnect, disconnectionPayload)); - parent.ExpectMsg(); + + senderProbe.ExpectNoMsg(); + LocalNode.Singleton.GetUnconnectedPeers().Any(p => p.Equals(new IPEndPoint(IPAddress.Parse("192.166.1.1"), 8080))).Should().BeTrue(); } } } diff --git a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs index 60855ce5ce..4b13952fe7 100644 --- a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs +++ b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs @@ -6,7 +6,6 @@ using Neo.Network.P2P; using Neo.Network.P2P.Capabilities; using Neo.Network.P2P.Payloads; -using System.Linq; using System.Net; namespace Neo.UnitTests.Network.P2P @@ -93,39 +92,6 @@ public void RemoteNode_Test_Accept_IfSameMagic() verackMessage.Data.Count.Should().Be(3); } - [TestMethod] - public void RemoteNode_Test_Received_MaxConnectionReached_Disconnection() - { - var connectionTestProbe = CreateTestProbe(); - var remoteNodeActor = ActorOfAsTestActorRef(() => new RemoteNode(testBlockchain, connectionTestProbe, null, null)); - - connectionTestProbe.ExpectMsg(); // remote node will send version message - LocalNode.Singleton.GetUnconnectedPeers().Count().Should().Be(0); - - //send MaxConnectionReached disconnection - NetworkAddressWithTime[] addressWithTimes = new NetworkAddressWithTime[] - { - new NetworkAddressWithTime() - { - Timestamp = 0, - Address = IPAddress.Parse("192.168.255.255"), - Capabilities = new NodeCapability[] - { - new ServerCapability(NodeCapabilityType.TcpServer, 8080) - } - } - }; - var payload = DisconnectPayload.Create(DisconnectReason.MaxConnectionReached, "The maximum number of connections reached!", addressWithTimes.ToByteArray()); - var testProbe = CreateTestProbe(); - testProbe.Send(remoteNodeActor, payload); - - connectionTestProbe.ExpectNoMsg(); - LocalNode.Singleton.GetUnconnectedPeers().Count().Should().Be(1); - var iPEndPoint = LocalNode.Singleton.GetUnconnectedPeers().First(); - iPEndPoint.Should().Be(new IPEndPoint(addressWithTimes[0].Address, 8080)); - } - - [TestMethod] public void RemoteNode_Test_Received_Duplicate_Connection() { diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index 8a9eb71556..28aa991f6d 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -80,6 +80,7 @@ protected void Disconnect(DisconnectReason reason, string message = "", byte[] d } else { + // send data... ws.Abort(); } Context.Stop(Self); diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index 10071328a3..cff253edeb 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -111,6 +111,28 @@ private static IEnumerable GetIPEndPointsFromSeedList(int seedsToTak } } + public bool IsDuplicateConnection(RemoteNode remoteNode) + { + var version = remoteNode.Version; + var remote = remoteNode.Remote; + + foreach(var pair in RemoteNodes) + { + var remoteActorRef = pair.Key; + var otherNode = pair.Value; + if(otherNode != remoteNode && otherNode.Remote.Address.Equals(remote.Address) && otherNode.Version?.Nonce == version.Nonce) + { + // add the duplicate address in ConnectedPeers + if (ConnectedPeers.TryGetValue(remoteActorRef, out List endPoints)) + { + endPoints.Add(remote); + } + return true; + } + } + return false; + } + public IEnumerable GetRemoteNodes() { return RemoteNodes.Values; @@ -164,6 +186,9 @@ protected override void OnReceive(object message) break; case RelayResultReason _: break; + case DisconnectPayload payload: + OnDisconnectPayload(payload); + break; } } @@ -184,6 +209,23 @@ private void OnSendDirectly(IInventory inventory) Connections.Tell(inventory); } + private void OnDisconnectPayload(DisconnectPayload payload) + { + switch (payload.Reason) + { + case DisconnectReason.MaxConnectionReached: + case DisconnectReason.MaxPerAddressConnectionReached: + try + { + NetworkAddressWithTime[] addressList = payload.Data.AsSerializableArray(AddrPayload.MaxCountToSend); + AddPeers(addressList.Select(p => p.EndPoint).Where(p => p.Port > 0)); + } + catch { } + break; + default: break; + } + } + public static Props Props(NeoSystem system) { return Akka.Actor.Props.Create(() => new LocalNode(system)); diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index 084e5f2216..e6ebc81984 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -72,14 +72,6 @@ protected void AddPeers(IEnumerable peers) } } - public void AddRemoteNodeListenerIPEndPoint(IActorRef remoteActorRef, IPEndPoint listener) - { - if (ConnectedPeers.TryGetValue(remoteActorRef, out List endPoints)) - { - endPoints.Add(listener); - } - } - protected void ConnectToPeer(IPEndPoint endPoint, bool isTrusted = false) { endPoint = endPoint.Unmap(); @@ -222,6 +214,7 @@ private void DisconnectWithAddresses(DisconnectReason reason, string message) private void Disconnect(DisconnectReason reason, string message = "", byte[] data = null) { + Console.WriteLine("disconnect sender by reaseon: " + reason); var payload = DisconnectPayload.Create(reason, message, data); var disconnect = Message.Create(MessageCommand.Disconnect, payload); var command = Tcp.Write.Create(ByteString.FromBytes(disconnect.ToArray())); diff --git a/neo/Network/P2P/ProtocolHandler.cs b/neo/Network/P2P/ProtocolHandler.cs index b47ee2fca5..d381b950be 100644 --- a/neo/Network/P2P/ProtocolHandler.cs +++ b/neo/Network/P2P/ProtocolHandler.cs @@ -40,6 +40,12 @@ protected override void OnReceive(object message) foreach (IP2PPlugin plugin in Plugin.P2PPlugins) if (!plugin.OnP2PMessage(msg)) return; + + if (msg.Command == MessageCommand.Disconnect) + { + OnDisconnectMessageRecived((DisconnectPayload)msg.Payload); + return; + } if (version == null) { if (msg.Command != MessageCommand.Version) @@ -105,9 +111,6 @@ protected override void OnReceive(object message) if (msg.Payload.Size <= Transaction.MaxTransactionSize) OnInventoryReceived((Transaction)msg.Payload); break; - case MessageCommand.Disconnect: - OnDisconnectRecived((DisconnectPayload)msg.Payload); - break; case MessageCommand.Verack: case MessageCommand.Version: throw new ProtocolViolationException(); @@ -288,9 +291,9 @@ private void OnVersionMessageReceived(VersionPayload payload) Context.Parent.Tell(payload); } - private void OnDisconnectRecived(DisconnectPayload payload) + private void OnDisconnectMessageRecived(DisconnectPayload payload) { - Context.Parent.Tell(payload); + system.LocalNode.Tell(payload, Context.Parent); // As the priority of message is lower than Tcp.Close } public static Props Props(NeoSystem system) diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index 74453e95c2..cc3ad11806 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -113,7 +113,9 @@ protected override void OnData(ByteString data) { msg_buffer = msg_buffer.Concat(data); for (Message message = TryParseMessage(); message != null; message = TryParseMessage()) + { protocol.Tell(message); + } } protected override void OnReceive(object message) @@ -136,9 +138,6 @@ protected override void OnReceive(object message) case MessageCommand.Verack: OnVerack(); break; - case DisconnectPayload payload: - OnDisconnectPayload(payload); - break; case ProtocolHandler.SetFilter setFilter: OnSetFilter(setFilter.Filter); break; @@ -205,39 +204,24 @@ private void OnVersionPayload(VersionPayload version) break; } } - if (version.Nonce == LocalNode.Nonce || version.Magic != ProtocolSettings.Default.Magic) + + if (version.Nonce == LocalNode.Nonce) { - Disconnect(DisconnectReason.MagicNumberIncompatible, "Incomppatible magic number!"); + Disconnect(DisconnectReason.DuplicateConnection, "Local node"); return; } - if (LocalNode.Singleton.RemoteNodes.Values.Where(p => p != this).Any(p => p.Remote != null && Remote != null && p.Remote.Address.Equals(Remote.Address) && p.Version?.Nonce == version.Nonce)) + if (version.Magic != ProtocolSettings.Default.Magic) { - Disconnect(DisconnectReason.DuplicateConnection, "Duplicate connection!"); + Disconnect(DisconnectReason.MagicNumberIncompatible, "Incomppatible magic number!", BitConverter.GetBytes(ProtocolSettings.Default.Magic)); return; } - SendMessage(Message.Create(MessageCommand.Verack)); - } - - private void OnDisconnectPayload(DisconnectPayload payload) - { - switch (payload.Reason) + if (Remote != null && LocalNode.Singleton.IsDuplicateConnection(this)) { - case DisconnectReason.MaxConnectionReached: - try - { - NetworkAddressWithTime[] addressList = payload.Data.AsSerializableArray(AddrPayload.MaxCountToSend); - system.LocalNode.Tell(new Peer.Peers - { - EndPoints = addressList.Select(p => p.EndPoint).Where(p => p.Port > 0) - }); - } - catch (FormatException) { } - break; - case DisconnectReason.DuplicateConnection: - LocalNode.Singleton.AddRemoteNodeListenerIPEndPoint(Self, Listener); - break; - default: break; + Disconnect(DisconnectReason.DuplicateConnection, "Duplicate connection!"); + return; } + + SendMessage(Message.Create(MessageCommand.Verack)); } protected override void PostStop() @@ -269,11 +253,7 @@ protected override SupervisorStrategy SupervisorStrategy() private Message TryParseMessage() { var length = Message.TryDeserialize(msg_buffer, out var msg); - if (length <= 0) - { - msg_buffer = ByteString.Empty; - return null; - } + if (length <= 0) return null; msg_buffer = msg_buffer.Slice(length).Compact(); return msg; From 90e47f4838b4ba8e2d94392833787fb00709669d Mon Sep 17 00:00:00 2001 From: luchuan Date: Fri, 11 Oct 2019 14:55:00 +0800 Subject: [PATCH 05/84] format --- neo/IO/Data/LevelDB/DB.cs | 10 +++++----- neo/IO/Data/LevelDB/WriteBatch.cs | 6 +++--- neo/Network/P2P/RemoteNode.cs | 2 -- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/neo/IO/Data/LevelDB/DB.cs b/neo/IO/Data/LevelDB/DB.cs index b446f0eb56..451684b5cc 100644 --- a/neo/IO/Data/LevelDB/DB.cs +++ b/neo/IO/Data/LevelDB/DB.cs @@ -16,7 +16,7 @@ private DB(IntPtr handle) this.handle = handle; } - public virtual void Dispose() + public void Dispose() { if (handle != IntPtr.Zero) { @@ -25,14 +25,14 @@ public virtual void Dispose() } } - public virtual void Delete(WriteOptions options, Slice key) + public void Delete(WriteOptions options, Slice key) { IntPtr error; Native.leveldb_delete(handle, options.handle, key.buffer, (UIntPtr)key.buffer.Length, out error); NativeHelper.CheckError(error); } - public virtual Slice Get(ReadOptions options, Slice key) + public Slice Get(ReadOptions options, Slice key) { UIntPtr length; IntPtr error; @@ -50,12 +50,12 @@ public virtual Slice Get(ReadOptions options, Slice key) } } - public virtual Snapshot GetSnapshot() + public Snapshot GetSnapshot() { return new Snapshot(handle); } - public virtual Iterator NewIterator(ReadOptions options) + public Iterator NewIterator(ReadOptions options) { return new Iterator(Native.leveldb_create_iterator(handle, options.handle)); } diff --git a/neo/IO/Data/LevelDB/WriteBatch.cs b/neo/IO/Data/LevelDB/WriteBatch.cs index 03dcab1f3d..b3a9782108 100644 --- a/neo/IO/Data/LevelDB/WriteBatch.cs +++ b/neo/IO/Data/LevelDB/WriteBatch.cs @@ -11,17 +11,17 @@ public class WriteBatch Native.leveldb_writebatch_destroy(handle); } - public virtual void Clear() + public void Clear() { Native.leveldb_writebatch_clear(handle); } - public virtual void Delete(Slice key) + public void Delete(Slice key) { Native.leveldb_writebatch_delete(handle, key.buffer, (UIntPtr)key.buffer.Length); } - public virtual void Put(Slice key, Slice value) + public void Put(Slice key, Slice value) { Native.leveldb_writebatch_put(handle, key.buffer, (UIntPtr)key.buffer.Length, value.buffer, (UIntPtr)value.buffer.Length); } diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index cc3ad11806..64262f1578 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -113,9 +113,7 @@ protected override void OnData(ByteString data) { msg_buffer = msg_buffer.Concat(data); for (Message message = TryParseMessage(); message != null; message = TryParseMessage()) - { protocol.Tell(message); - } } protected override void OnReceive(object message) From 1ace691b373d73861ad44372e8f3af5b2d253811 Mon Sep 17 00:00:00 2001 From: luchuan Date: Fri, 11 Oct 2019 15:12:27 +0800 Subject: [PATCH 06/84] add websocket disconnect --- neo.UnitTests/Network/P2P/UT_RemoteNode.cs | 4 ++-- neo/IO/Data/LevelDB/DB.cs | 6 +++--- neo/Network/P2P/Connection.cs | 12 ++++++++---- neo/Network/P2P/Peer.cs | 10 ++++++++-- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs index 4b13952fe7..de6620159c 100644 --- a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs +++ b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs @@ -105,9 +105,9 @@ public void RemoteNode_Test_Received_Duplicate_Connection() Timestamp = 5, Version = 6, Capabilities = new NodeCapability[] - { + { new ServerCapability(NodeCapabilityType.TcpServer, 25) - } + } }; // send to remote node A diff --git a/neo/IO/Data/LevelDB/DB.cs b/neo/IO/Data/LevelDB/DB.cs index 451684b5cc..04e8f50e8f 100644 --- a/neo/IO/Data/LevelDB/DB.cs +++ b/neo/IO/Data/LevelDB/DB.cs @@ -73,14 +73,14 @@ public static DB Open(string name, Options options) return new DB(handle); } - public virtual void Put(WriteOptions options, Slice key, Slice value) + public void Put(WriteOptions options, Slice key, Slice value) { IntPtr error; Native.leveldb_put(handle, options.handle, key.buffer, (UIntPtr)key.buffer.Length, value.buffer, (UIntPtr)value.buffer.Length, out error); NativeHelper.CheckError(error); } - public virtual bool TryGet(ReadOptions options, Slice key, out Slice value) + public bool TryGet(ReadOptions options, Slice key, out Slice value) { UIntPtr length; IntPtr error; @@ -101,7 +101,7 @@ public virtual bool TryGet(ReadOptions options, Slice key, out Slice value) return true; } - public virtual void Write(WriteOptions options, WriteBatch write_batch) + public void Write(WriteOptions options, WriteBatch write_batch) { // There's a bug in .Net Core. // When calling DB.Write(), it will throw LevelDBException sometimes. diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index 28aa991f6d..cd55cb3c17 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -71,17 +71,21 @@ private void WsReceive() protected void Disconnect(DisconnectReason reason, string message = "", byte[] data = null) { disconnected = true; + + var payload = DisconnectPayload.Create(reason, message, data); + var disconnectMessage = Message.Create(MessageCommand.Disconnect, payload); + if (tcp != null) { - var payload = DisconnectPayload.Create(reason, message, data); - var disconnectMessage = Message.Create(MessageCommand.Disconnect, payload); tcp.Tell(Tcp.Write.Create((ByteString.FromBytes(disconnectMessage.ToArray())))); tcp.Tell(Tcp.Close.Instance); } else { - // send data... - ws.Abort(); + ArraySegment segment = new ArraySegment(disconnectMessage.ToArray()); + ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, + failure: ex => new Tcp.ErrorClosed(ex.Message)); + ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); } Context.Stop(Self); } diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index e6ebc81984..8a3c31f8e5 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -14,6 +14,7 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Net.WebSockets; +using System.Threading; using System.Threading.Tasks; namespace Neo.Network.P2P @@ -214,7 +215,6 @@ private void DisconnectWithAddresses(DisconnectReason reason, string message) private void Disconnect(DisconnectReason reason, string message = "", byte[] data = null) { - Console.WriteLine("disconnect sender by reaseon: " + reason); var payload = DisconnectPayload.Create(reason, message, data); var disconnect = Message.Create(MessageCommand.Disconnect, payload); var command = Tcp.Write.Create(ByteString.FromBytes(disconnect.ToArray())); @@ -264,7 +264,13 @@ private void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { - ws.Abort(); + NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); + var payload = DisconnectPayload.Create(DisconnectReason.MaxPerAddressConnectionReached, "The maximum number of per address connections reached!", networkAddresses.ToByteArray()); + var disconnectMessage = Message.Create(MessageCommand.Disconnect, payload); + ArraySegment segment = new ArraySegment(disconnectMessage.ToArray()); + ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, + failure: ex => new Tcp.ErrorClosed(ex.Message)); + ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); } else { From f5c21e4d9dd6022c6e3a5bcf12ec88d427a840e8 Mon Sep 17 00:00:00 2001 From: luchuan Date: Fri, 11 Oct 2019 15:19:07 +0800 Subject: [PATCH 07/84] format --- neo/Network/P2P/RemoteNode.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index 64262f1578..f94fb244d7 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -44,6 +44,7 @@ public RemoteNode(NeoSystem system, object connection, IPEndPoint remote, IPEndP { new FullNodeCapability(Blockchain.Singleton.Height) }; + if (LocalNode.Singleton.ListenerTcpPort > 0) capabilities.Add(new ServerCapability(NodeCapabilityType.TcpServer, (ushort)LocalNode.Singleton.ListenerTcpPort)); if (LocalNode.Singleton.ListenerWsPort > 0) capabilities.Add(new ServerCapability(NodeCapabilityType.WsServer, (ushort)LocalNode.Singleton.ListenerWsPort)); @@ -112,6 +113,7 @@ protected override void OnAck() protected override void OnData(ByteString data) { msg_buffer = msg_buffer.Concat(data); + for (Message message = TryParseMessage(); message != null; message = TryParseMessage()) protocol.Tell(message); } From b49534f433ad4a67c84ef0f65d9c7e9990e7e3e8 Mon Sep 17 00:00:00 2001 From: luchuan Date: Fri, 11 Oct 2019 15:30:14 +0800 Subject: [PATCH 08/84] format --- neo/Network/P2P/Payloads/DisconnectPayload.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/neo/Network/P2P/Payloads/DisconnectPayload.cs b/neo/Network/P2P/Payloads/DisconnectPayload.cs index 6277ebc83e..7633c8beaf 100644 --- a/neo/Network/P2P/Payloads/DisconnectPayload.cs +++ b/neo/Network/P2P/Payloads/DisconnectPayload.cs @@ -10,7 +10,7 @@ public enum DisconnectReason : byte DuplicateConnection = 0x03, MagicNumberIncompatible = 0x04, ConnectionTimeout = 0x05, - UntrustedIpAddresses = 0x06, + UntrustedIpAddresses = 0x06, FormatExcpetion = 0x10, InternalError = 0x11, @@ -18,7 +18,6 @@ public enum DisconnectReason : byte public class DisconnectPayload : ISerializable { - public const int MaxDataSize = 5120; public DisconnectReason Reason; @@ -27,7 +26,6 @@ public class DisconnectPayload : ISerializable public int Size => sizeof(DisconnectReason) + Message.GetVarSize() + Data.GetVarSize(); - public static DisconnectPayload Create(DisconnectReason reason, string message = "", byte[] data = null) { return new DisconnectPayload @@ -40,7 +38,7 @@ public static DisconnectPayload Create(DisconnectReason reason, string message = public void Deserialize(BinaryReader reader) { - Reason = (DisconnectReason) reader.ReadByte(); + Reason = (DisconnectReason)reader.ReadByte(); Message = reader.ReadString(); Data = reader.ReadVarBytes(MaxDataSize); } From f1468d5432c9f9b29aa2d55e4d4c995c8d9ae3d9 Mon Sep 17 00:00:00 2001 From: luchuan Date: Fri, 11 Oct 2019 16:47:20 +0800 Subject: [PATCH 09/84] format --- neo/Network/P2P/Connection.cs | 2 +- neo/Network/P2P/LocalNode.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index cd55cb3c17..3e7441d439 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -122,7 +122,7 @@ private void OnReceived(ByteString data) try { OnData(data); - }catch(FormatException) + }catch (FormatException) { Disconnect(DisconnectReason.FormatExcpetion, "Parse data failed!"); } diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index cff253edeb..d7b7336614 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -116,11 +116,11 @@ public bool IsDuplicateConnection(RemoteNode remoteNode) var version = remoteNode.Version; var remote = remoteNode.Remote; - foreach(var pair in RemoteNodes) + foreach (var pair in RemoteNodes) { var remoteActorRef = pair.Key; var otherNode = pair.Value; - if(otherNode != remoteNode && otherNode.Remote.Address.Equals(remote.Address) && otherNode.Version?.Nonce == version.Nonce) + if (otherNode != remoteNode && otherNode.Remote.Address.Equals(remote.Address) && otherNode.Version?.Nonce == version.Nonce) { // add the duplicate address in ConnectedPeers if (ConnectedPeers.TryGetValue(remoteActorRef, out List endPoints)) From b5ed267f79cebfef77c13f2eaef10670a64a3ac9 Mon Sep 17 00:00:00 2001 From: luchuan Date: Fri, 11 Oct 2019 16:53:35 +0800 Subject: [PATCH 10/84] format --- neo/Network/P2P/Connection.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index 3e7441d439..44ac0a1bee 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -122,7 +122,8 @@ private void OnReceived(ByteString data) try { OnData(data); - }catch (FormatException) + } + catch (FormatException) { Disconnect(DisconnectReason.FormatExcpetion, "Parse data failed!"); } From cbc1c2a80ca9307d82883194af365032314f76c0 Mon Sep 17 00:00:00 2001 From: luchuan Date: Fri, 11 Oct 2019 17:02:50 +0800 Subject: [PATCH 11/84] fix UT_LocalNode --- neo.UnitTests/Network/P2P/UT_LocalNode.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 823724a099..1f6e52c11e 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -15,6 +15,7 @@ namespace Neo.UnitTests.Network.P2P { [TestClass] + [NotReRunnable] public class UT_LocalNode : TestKit { private static NeoSystem testBlockchain; From 2588118ca83a8a4a67eb2ae3b61a85d21328bece Mon Sep 17 00:00:00 2001 From: luchuan Date: Sat, 12 Oct 2019 10:39:40 +0800 Subject: [PATCH 12/84] rename MaxConnectionPerAddressReached --- neo.UnitTests/Network/P2P/UT_LocalNode.cs | 4 ++-- neo/Network/P2P/LocalNode.cs | 2 +- neo/Network/P2P/Payloads/DisconnectPayload.cs | 2 +- neo/Network/P2P/Peer.cs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 1f6e52c11e..18a1264fea 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -122,7 +122,7 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() testProbe.Send(remoteNodeActor, versionReceived); testProbe.ExpectMsg(); // remote node will send verack and change its listenerPort - // create one more remote connection and localnode will disconnect with `MaxPerAddressConnectionReached` + // create one more remote connection and localnode will disconnect with `MaxConnectionPerAddressReached` remote = new IPEndPoint(IPAddress.Parse("192.168.1.1"), 8079); connected = new Tcp.Connected(remote, local); testProbe.Send(localNode, connected); @@ -132,7 +132,7 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() message.Command.Should().Be(MessageCommand.Disconnect); var disconnectionPayload = (DisconnectPayload)message.Payload; - disconnectionPayload.Reason.Should().Be(DisconnectReason.MaxPerAddressConnectionReached); + disconnectionPayload.Reason.Should().Be(DisconnectReason.MaxConnectionPerAddressReached); // return addr var count = DisconnectPayload.MaxDataSize; diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index d7b7336614..eec7a8d3e9 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -214,7 +214,7 @@ private void OnDisconnectPayload(DisconnectPayload payload) switch (payload.Reason) { case DisconnectReason.MaxConnectionReached: - case DisconnectReason.MaxPerAddressConnectionReached: + case DisconnectReason.MaxConnectionPerAddressReached: try { NetworkAddressWithTime[] addressList = payload.Data.AsSerializableArray(AddrPayload.MaxCountToSend); diff --git a/neo/Network/P2P/Payloads/DisconnectPayload.cs b/neo/Network/P2P/Payloads/DisconnectPayload.cs index 7633c8beaf..77e92e189d 100644 --- a/neo/Network/P2P/Payloads/DisconnectPayload.cs +++ b/neo/Network/P2P/Payloads/DisconnectPayload.cs @@ -6,7 +6,7 @@ namespace Neo.Network.P2P.Payloads public enum DisconnectReason : byte { MaxConnectionReached = 0x01, - MaxPerAddressConnectionReached = 0x02, + MaxConnectionPerAddressReached = 0x02, DuplicateConnection = 0x03, MagicNumberIncompatible = 0x04, ConnectionTimeout = 0x05, diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index 8a3c31f8e5..659014748c 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -194,7 +194,7 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { - DisconnectWithAddresses(DisconnectReason.MaxPerAddressConnectionReached, "The maximum number of per address connections reached!"); + DisconnectWithAddresses(DisconnectReason.MaxConnectionPerAddressReached, "The maximum number of per address connections reached!"); return; } else @@ -265,7 +265,7 @@ private void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) if (count >= MaxConnectionsPerAddress) { NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); - var payload = DisconnectPayload.Create(DisconnectReason.MaxPerAddressConnectionReached, "The maximum number of per address connections reached!", networkAddresses.ToByteArray()); + var payload = DisconnectPayload.Create(DisconnectReason.MaxConnectionPerAddressReached, "The maximum number of per address connections reached!", networkAddresses.ToByteArray()); var disconnectMessage = Message.Create(MessageCommand.Disconnect, payload); ArraySegment segment = new ArraySegment(disconnectMessage.ToArray()); ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, From 383e0436f17bce719cbfd4c126623ae7bd06045f Mon Sep 17 00:00:00 2001 From: luchuan Date: Sat, 12 Oct 2019 10:44:52 +0800 Subject: [PATCH 13/84] fix trusted ip addresses --- neo/Network/P2P/Peer.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index 659014748c..caff907027 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -181,16 +181,12 @@ private void OnStart(ChannelsConfig config) private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) { ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); - if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections) + if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) { DisconnectWithAddresses(DisconnectReason.MaxConnectionReached, "The maximum number of connections reached!"); return; } - if (TrustedIpAddresses.Count > 0 && !TrustedIpAddresses.Contains(remote.Address)) - { - Disconnect(DisconnectReason.UntrustedIpAddresses, $"Untrusted ip address: {remote.Address}"); - return; - } + ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { From da0abb5753aaf87d5b931edc77f5279df6404fcc Mon Sep 17 00:00:00 2001 From: luchuan Date: Sat, 12 Oct 2019 10:49:33 +0800 Subject: [PATCH 14/84] format remove whitespace --- neo/Network/P2P/Peer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index caff907027..a7bcac6a49 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -186,7 +186,7 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) DisconnectWithAddresses(DisconnectReason.MaxConnectionReached, "The maximum number of connections reached!"); return; } - + ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { From 575c37cdc01f69e0bd00cff0e558ff82305cec94 Mon Sep 17 00:00:00 2001 From: luchuan Date: Sat, 12 Oct 2019 15:25:42 +0800 Subject: [PATCH 15/84] change tcp.close => tcp.abort --- neo.UnitTests/Network/P2P/UT_RemoteNode.cs | 8 ++++---- neo/Network/P2P/Connection.cs | 23 ++++++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs index de6620159c..85895d3186 100644 --- a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs +++ b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs @@ -59,7 +59,7 @@ public void RemoteNode_Test_Abort_DifferentMagic() var disconnectionPayload = (DisconnectPayload)message.Payload; disconnectionPayload.Reason.Should().Be(DisconnectReason.MagicNumberIncompatible); - connectionTestProbe.ExpectMsg(); + connectionTestProbe.ExpectMsg(); } [TestMethod] @@ -132,7 +132,7 @@ public void RemoteNode_Test_Received_Duplicate_Connection() var disconnectionPayload = (DisconnectPayload)message.Payload; disconnectionPayload.Reason.Should().Be(DisconnectReason.DuplicateConnection); - connectionTestProbeB.ExpectMsg(); + connectionTestProbeB.ExpectMsg(); } [TestMethod] @@ -155,7 +155,7 @@ public void RemoteNode_Test_Received_Invalid_Data() var disconnectionPayload = (DisconnectPayload)message.Payload; disconnectionPayload.Reason.Should().Be(DisconnectReason.FormatExcpetion); - connectionTestProbe.ExpectMsg(); + connectionTestProbe.ExpectMsg(); } [TestMethod] @@ -175,7 +175,7 @@ public void Connection_Test_Timeout() var disconnectionPayload = (DisconnectPayload)message.Payload; disconnectionPayload.Reason.Should().Be(DisconnectReason.ConnectionTimeout); - connectionTestProbe.ExpectMsg(); + connectionTestProbe.ExpectMsg(); } } } diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index 44ac0a1bee..fa64d5dc4a 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -6,6 +6,7 @@ using System.Net; using System.Net.WebSockets; using System.Threading; +using System.Threading.Tasks; namespace Neo.Network.P2P { @@ -68,7 +69,7 @@ private void WsReceive() failure: ex => new Tcp.ErrorClosed(ex.Message)); } - protected void Disconnect(DisconnectReason reason, string message = "", byte[] data = null) + protected async void Disconnect(DisconnectReason reason, string message = "", byte[] data = null) { disconnected = true; @@ -77,17 +78,27 @@ protected void Disconnect(DisconnectReason reason, string message = "", byte[] d if (tcp != null) { - tcp.Tell(Tcp.Write.Create((ByteString.FromBytes(disconnectMessage.ToArray())))); - tcp.Tell(Tcp.Close.Instance); + tcp.Tell(Tcp.Write.Create(ByteString.FromBytes(disconnectMessage.ToArray()), Ack.Instance)); + Context.SetReceiveTimeout(TimeSpan.FromSeconds(2.5)); + Become(msg => + { + if (msg is Ack || msg is ReceiveTimeout) + { + tcp.Tell(Tcp.Abort.Instance); + Context.Stop(Self); + } + }); } else { ArraySegment segment = new ArraySegment(disconnectMessage.ToArray()); - ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, + var task = ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, + success: () => Ack.Instance, failure: ex => new Tcp.ErrorClosed(ex.Message)); - ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); + await Task.WhenAny(task, Task.Delay(2500)); + ws.Abort(); + Context.Stop(Self); } - Context.Stop(Self); } protected virtual void OnAck() From df39f5ec4b74a8a90f9763ade019f12cda9944b7 Mon Sep 17 00:00:00 2001 From: luchuan Date: Sat, 12 Oct 2019 15:27:28 +0800 Subject: [PATCH 16/84] format --- neo/Network/P2P/Connection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index fa64d5dc4a..ab7a8c3f42 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -85,7 +85,7 @@ protected async void Disconnect(DisconnectReason reason, string message = "", by if (msg is Ack || msg is ReceiveTimeout) { tcp.Tell(Tcp.Abort.Instance); - Context.Stop(Self); + Context.Stop(Self); } }); } From b76b04daa18414b4fa9d7ea2ce09234db7a8e328 Mon Sep 17 00:00:00 2001 From: luchuan Date: Sat, 12 Oct 2019 16:07:45 +0800 Subject: [PATCH 17/84] reset db.cs writebatch.cs --- neo/IO/Data/LevelDB/DB.cs | 16 ++++++++-------- neo/IO/Data/LevelDB/WriteBatch.cs | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/neo/IO/Data/LevelDB/DB.cs b/neo/IO/Data/LevelDB/DB.cs index b446f0eb56..04e8f50e8f 100644 --- a/neo/IO/Data/LevelDB/DB.cs +++ b/neo/IO/Data/LevelDB/DB.cs @@ -16,7 +16,7 @@ private DB(IntPtr handle) this.handle = handle; } - public virtual void Dispose() + public void Dispose() { if (handle != IntPtr.Zero) { @@ -25,14 +25,14 @@ public virtual void Dispose() } } - public virtual void Delete(WriteOptions options, Slice key) + public void Delete(WriteOptions options, Slice key) { IntPtr error; Native.leveldb_delete(handle, options.handle, key.buffer, (UIntPtr)key.buffer.Length, out error); NativeHelper.CheckError(error); } - public virtual Slice Get(ReadOptions options, Slice key) + public Slice Get(ReadOptions options, Slice key) { UIntPtr length; IntPtr error; @@ -50,12 +50,12 @@ public virtual Slice Get(ReadOptions options, Slice key) } } - public virtual Snapshot GetSnapshot() + public Snapshot GetSnapshot() { return new Snapshot(handle); } - public virtual Iterator NewIterator(ReadOptions options) + public Iterator NewIterator(ReadOptions options) { return new Iterator(Native.leveldb_create_iterator(handle, options.handle)); } @@ -73,14 +73,14 @@ public static DB Open(string name, Options options) return new DB(handle); } - public virtual void Put(WriteOptions options, Slice key, Slice value) + public void Put(WriteOptions options, Slice key, Slice value) { IntPtr error; Native.leveldb_put(handle, options.handle, key.buffer, (UIntPtr)key.buffer.Length, value.buffer, (UIntPtr)value.buffer.Length, out error); NativeHelper.CheckError(error); } - public virtual bool TryGet(ReadOptions options, Slice key, out Slice value) + public bool TryGet(ReadOptions options, Slice key, out Slice value) { UIntPtr length; IntPtr error; @@ -101,7 +101,7 @@ public virtual bool TryGet(ReadOptions options, Slice key, out Slice value) return true; } - public virtual void Write(WriteOptions options, WriteBatch write_batch) + public void Write(WriteOptions options, WriteBatch write_batch) { // There's a bug in .Net Core. // When calling DB.Write(), it will throw LevelDBException sometimes. diff --git a/neo/IO/Data/LevelDB/WriteBatch.cs b/neo/IO/Data/LevelDB/WriteBatch.cs index 03dcab1f3d..b3a9782108 100644 --- a/neo/IO/Data/LevelDB/WriteBatch.cs +++ b/neo/IO/Data/LevelDB/WriteBatch.cs @@ -11,17 +11,17 @@ public class WriteBatch Native.leveldb_writebatch_destroy(handle); } - public virtual void Clear() + public void Clear() { Native.leveldb_writebatch_clear(handle); } - public virtual void Delete(Slice key) + public void Delete(Slice key) { Native.leveldb_writebatch_delete(handle, key.buffer, (UIntPtr)key.buffer.Length); } - public virtual void Put(Slice key, Slice value) + public void Put(Slice key, Slice value) { Native.leveldb_writebatch_put(handle, key.buffer, (UIntPtr)key.buffer.Length, value.buffer, (UIntPtr)value.buffer.Length); } From 8e2b0fa554cb5e2b39c8d72141af06bd831423cd Mon Sep 17 00:00:00 2001 From: luchuan Date: Sat, 12 Oct 2019 20:45:02 +0800 Subject: [PATCH 18/84] typo received --- neo/Network/P2P/ProtocolHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neo/Network/P2P/ProtocolHandler.cs b/neo/Network/P2P/ProtocolHandler.cs index d381b950be..703031fc18 100644 --- a/neo/Network/P2P/ProtocolHandler.cs +++ b/neo/Network/P2P/ProtocolHandler.cs @@ -43,7 +43,7 @@ protected override void OnReceive(object message) if (msg.Command == MessageCommand.Disconnect) { - OnDisconnectMessageRecived((DisconnectPayload)msg.Payload); + OnDisconnectMessageReceived((DisconnectPayload)msg.Payload); return; } if (version == null) @@ -291,7 +291,7 @@ private void OnVersionMessageReceived(VersionPayload payload) Context.Parent.Tell(payload); } - private void OnDisconnectMessageRecived(DisconnectPayload payload) + private void OnDisconnectMessageReceived(DisconnectPayload payload) { system.LocalNode.Tell(payload, Context.Parent); // As the priority of message is lower than Tcp.Close } From 8eda67d56d3bec5272aa55f81e62ad45c2a0288a Mon Sep 17 00:00:00 2001 From: luchuan Date: Mon, 14 Oct 2019 22:58:43 +0800 Subject: [PATCH 19/84] remove UntrustedIpAddresses --- neo/Network/P2P/Payloads/DisconnectPayload.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/neo/Network/P2P/Payloads/DisconnectPayload.cs b/neo/Network/P2P/Payloads/DisconnectPayload.cs index 77e92e189d..94e33d2b13 100644 --- a/neo/Network/P2P/Payloads/DisconnectPayload.cs +++ b/neo/Network/P2P/Payloads/DisconnectPayload.cs @@ -10,7 +10,6 @@ public enum DisconnectReason : byte DuplicateConnection = 0x03, MagicNumberIncompatible = 0x04, ConnectionTimeout = 0x05, - UntrustedIpAddresses = 0x06, FormatExcpetion = 0x10, InternalError = 0x11, From 4600839f3cd8e717111060dfe0a6332687b0c473 Mon Sep 17 00:00:00 2001 From: luchuan Date: Mon, 14 Oct 2019 23:10:06 +0800 Subject: [PATCH 20/84] optimize ConnectedPeers filter --- neo/Network/P2P/Peer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index a7bcac6a49..115c6046d8 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -81,7 +81,7 @@ protected void ConnectToPeer(IPEndPoint endPoint, bool isTrusted = false) if (isTrusted) TrustedIpAddresses.Add(endPoint.Address); if (ConnectedAddresses.TryGetValue(endPoint.Address, out int count) && count >= MaxConnectionsPerAddress) return; - if (ConnectedPeers.Values.SelectMany(p => p).ToList().Contains(endPoint)) return; + if (ConnectedPeers.Values.Any(p => p.Contains(endPoint))) return; ImmutableInterlocked.Update(ref ConnectingPeers, p => { if ((p.Count >= ConnectingMax && !isTrusted) || p.Contains(endPoint)) return p; From 082d7859be2c353fdc6f40857fe9ab2e34a6aad9 Mon Sep 17 00:00:00 2001 From: luchuan Date: Thu, 17 Oct 2019 10:53:42 +0800 Subject: [PATCH 21/84] remove Message field in DisconnectPayload --- .../Network/P2P/Payloads/UT_DisconnectPayload.cs | 11 +++++------ neo.UnitTests/Network/P2P/UT_LocalNode.cs | 2 +- neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs | 2 +- neo/Network/P2P/Connection.cs | 8 ++++---- neo/Network/P2P/Payloads/DisconnectPayload.cs | 8 ++------ neo/Network/P2P/Peer.cs | 14 +++++++------- neo/Network/P2P/RemoteNode.cs | 6 +++--- 7 files changed, 23 insertions(+), 28 deletions(-) diff --git a/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectPayload.cs b/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectPayload.cs index c18be98a0c..ff26d0e751 100644 --- a/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectPayload.cs +++ b/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectPayload.cs @@ -12,15 +12,15 @@ public class UT_DisconnectPayload [TestMethod] public void Size_Get() { - var payload = DisconnectPayload.Create(DisconnectReason.DuplicateConnection, "test message", new byte[] { 0x01, 0x02 }); - payload.Size.Should().Be(17); + var payload = DisconnectPayload.Create(DisconnectReason.DuplicateConnection, new byte[] { 0x01, 0x02 }); + payload.Size.Should().Be(4); } [TestMethod] public void Deserialize() { var payload = new DisconnectPayload(); - var hex = "030c74657374206d657373616765020102"; + var hex = "03020102"; using (MemoryStream ms = new MemoryStream(hex.HexToBytes(), false)) { using (BinaryReader reader = new BinaryReader(ms)) @@ -29,7 +29,6 @@ public void Deserialize() } } Assert.AreEqual(DisconnectReason.DuplicateConnection, payload.Reason); - Assert.AreEqual("test message", payload.Message); Assert.AreEqual(2, payload.Data.Length); Assert.AreEqual(0x01, payload.Data[0]); Assert.AreEqual(0x02, payload.Data[1]); @@ -38,8 +37,8 @@ public void Deserialize() [TestMethod] public void Serialize() { - var payload = DisconnectPayload.Create(DisconnectReason.DuplicateConnection, "test message", new byte[] { 0x01, 0x02 }); - payload.ToArray().ToHexString().Should().Be("030c74657374206d657373616765020102"); + var payload = DisconnectPayload.Create(DisconnectReason.DuplicateConnection, new byte[] { 0x01, 0x02 }); + payload.ToArray().ToHexString().Should().Be("03020102"); } } } diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 18a1264fea..be1f4d349f 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -225,7 +225,7 @@ public void Test_Received_MaxConnectionReached_Disconnection() } }; - var payload = DisconnectPayload.Create(DisconnectReason.MaxConnectionReached, "The maximum number of connections reached!", addressWithTimes.ToByteArray()); + var payload = DisconnectPayload.Create(DisconnectReason.MaxConnectionReached, addressWithTimes.ToByteArray()); var testProbe = CreateTestProbe(); testProbe.Send(testBlockchain.LocalNode, payload); diff --git a/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs b/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs index bc80fca0b7..6eba199270 100644 --- a/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs +++ b/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs @@ -62,7 +62,7 @@ public void ProtocolHandler_Test_SendDisconnection_Tell_LocalNode() } }; var protocolActor = ActorOfAsTestActorRef(() => new ProtocolHandler(testBlockchain)); - var disconnectionPayload = DisconnectPayload.Create(DisconnectReason.MaxConnectionReached, "The maximum number of connections reached!", addressWithTimes.ToByteArray()); + var disconnectionPayload = DisconnectPayload.Create(DisconnectReason.MaxConnectionReached, addressWithTimes.ToByteArray()); var senderProbe = CreateTestProbe(); senderProbe.Send(protocolActor, Message.Create(MessageCommand.Disconnect, disconnectionPayload)); diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index ab7a8c3f42..db9effee12 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -69,11 +69,11 @@ private void WsReceive() failure: ex => new Tcp.ErrorClosed(ex.Message)); } - protected async void Disconnect(DisconnectReason reason, string message = "", byte[] data = null) + protected async void Disconnect(DisconnectReason reason, byte[] data = null) { disconnected = true; - var payload = DisconnectPayload.Create(reason, message, data); + var payload = DisconnectPayload.Create(reason, data); var disconnectMessage = Message.Create(MessageCommand.Disconnect, payload); if (tcp != null) @@ -112,7 +112,7 @@ protected override void OnReceive(object message) switch (message) { case Timer _: - Disconnect(DisconnectReason.ConnectionTimeout, $"Connection timeout after {connectionTimeoutLimit} seconds!"); + Disconnect(DisconnectReason.ConnectionTimeout); break; case Ack _: OnAck(); @@ -136,7 +136,7 @@ private void OnReceived(ByteString data) } catch (FormatException) { - Disconnect(DisconnectReason.FormatExcpetion, "Parse data failed!"); + Disconnect(DisconnectReason.FormatExcpetion); } catch { diff --git a/neo/Network/P2P/Payloads/DisconnectPayload.cs b/neo/Network/P2P/Payloads/DisconnectPayload.cs index 94e33d2b13..e445c17982 100644 --- a/neo/Network/P2P/Payloads/DisconnectPayload.cs +++ b/neo/Network/P2P/Payloads/DisconnectPayload.cs @@ -20,17 +20,15 @@ public class DisconnectPayload : ISerializable public const int MaxDataSize = 5120; public DisconnectReason Reason; - public string Message; public byte[] Data; - public int Size => sizeof(DisconnectReason) + Message.GetVarSize() + Data.GetVarSize(); + public int Size => sizeof(DisconnectReason) + Data.GetVarSize(); - public static DisconnectPayload Create(DisconnectReason reason, string message = "", byte[] data = null) + public static DisconnectPayload Create(DisconnectReason reason, byte[] data = null) { return new DisconnectPayload { Reason = reason, - Message = message, Data = data == null ? new byte[0] : data }; } @@ -38,14 +36,12 @@ public static DisconnectPayload Create(DisconnectReason reason, string message = public void Deserialize(BinaryReader reader) { Reason = (DisconnectReason)reader.ReadByte(); - Message = reader.ReadString(); Data = reader.ReadVarBytes(MaxDataSize); } public void Serialize(BinaryWriter writer) { writer.Write((byte)Reason); - writer.Write(Message); writer.WriteVarBytes(Data); } } diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index 115c6046d8..9c89c10771 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -183,14 +183,14 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) { - DisconnectWithAddresses(DisconnectReason.MaxConnectionReached, "The maximum number of connections reached!"); + DisconnectWithAddresses(DisconnectReason.MaxConnectionReached); return; } ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { - DisconnectWithAddresses(DisconnectReason.MaxConnectionPerAddressReached, "The maximum number of per address connections reached!"); + DisconnectWithAddresses(DisconnectReason.MaxConnectionPerAddressReached); return; } else @@ -203,15 +203,15 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) } } - private void DisconnectWithAddresses(DisconnectReason reason, string message) + private void DisconnectWithAddresses(DisconnectReason reason) { NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); - Disconnect(reason, message, networkAddresses.ToByteArray()); + Disconnect(reason, networkAddresses.ToByteArray()); } - private void Disconnect(DisconnectReason reason, string message = "", byte[] data = null) + private void Disconnect(DisconnectReason reason, byte[] data = null) { - var payload = DisconnectPayload.Create(reason, message, data); + var payload = DisconnectPayload.Create(reason, data); var disconnect = Message.Create(MessageCommand.Disconnect, payload); var command = Tcp.Write.Create(ByteString.FromBytes(disconnect.ToArray())); Sender.Tell(command); @@ -261,7 +261,7 @@ private void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) if (count >= MaxConnectionsPerAddress) { NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); - var payload = DisconnectPayload.Create(DisconnectReason.MaxConnectionPerAddressReached, "The maximum number of per address connections reached!", networkAddresses.ToByteArray()); + var payload = DisconnectPayload.Create(DisconnectReason.MaxConnectionPerAddressReached, networkAddresses.ToByteArray()); var disconnectMessage = Message.Create(MessageCommand.Disconnect, payload); ArraySegment segment = new ArraySegment(disconnectMessage.ToArray()); ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index f94fb244d7..0b96c4750e 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -207,17 +207,17 @@ private void OnVersionPayload(VersionPayload version) if (version.Nonce == LocalNode.Nonce) { - Disconnect(DisconnectReason.DuplicateConnection, "Local node"); + Disconnect(DisconnectReason.DuplicateConnection); return; } if (version.Magic != ProtocolSettings.Default.Magic) { - Disconnect(DisconnectReason.MagicNumberIncompatible, "Incomppatible magic number!", BitConverter.GetBytes(ProtocolSettings.Default.Magic)); + Disconnect(DisconnectReason.MagicNumberIncompatible, BitConverter.GetBytes(ProtocolSettings.Default.Magic)); return; } if (Remote != null && LocalNode.Singleton.IsDuplicateConnection(this)) { - Disconnect(DisconnectReason.DuplicateConnection, "Duplicate connection!"); + Disconnect(DisconnectReason.DuplicateConnection); return; } From e46d02e5d5d135054dbaf078d269714480a070bc Mon Sep 17 00:00:00 2001 From: luchuan Date: Thu, 17 Oct 2019 18:39:36 +0800 Subject: [PATCH 22/84] add emtpyactor --- neo.UnitTests/Network/P2P/UT_LocalNode.cs | 8 ++++---- neo/Network/P2P/Connection.cs | 8 +++++--- neo/Network/P2P/EmptyActor.cs | 16 ++++++++++++++++ neo/Network/P2P/Peer.cs | 5 +++-- 4 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 neo/Network/P2P/EmptyActor.cs diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index be1f4d349f..753eb1f162 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -127,6 +127,8 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() connected = new Tcp.Connected(remote, local); testProbe.Send(localNode, connected); + testProbe.ExpectMsg(); + var tcpWrite = testProbe.ExpectMsg(); message = tcpWrite.Data.ToArray().AsSerializable(); message.Command.Should().Be(MessageCommand.Disconnect); @@ -139,8 +141,6 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() NetworkAddressWithTime[] addrs = disconnectionPayload.Data.AsSerializableArray(count); addrs.Length.Should().Be(1); addrs[0].EndPoint.Address.Should().BeEquivalentTo(IPAddress.Parse("192.168.1.1")); - - testProbe.ExpectMsg(); } [TestMethod] @@ -192,6 +192,8 @@ public void Test_Peer_MaxConnection_Reached() connected = new Tcp.Connected(remote, local); testProbe.Send(localNode, connected); + testProbe.ExpectMsg(); + var tcpWrite = testProbe.ExpectMsg(); Message message = tcpWrite.Data.ToArray().AsSerializable(); message.Command.Should().Be(MessageCommand.Disconnect); @@ -204,8 +206,6 @@ public void Test_Peer_MaxConnection_Reached() NetworkAddressWithTime[] addrs = disconnectionPayload.Data.AsSerializableArray(count); addrs.Length.Should().Be(1); addrs[0].EndPoint.Port.Should().Be(8080); - - testProbe.ExpectMsg(); } [TestMethod] diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index db9effee12..28e4eea3c9 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -95,9 +95,11 @@ protected async void Disconnect(DisconnectReason reason, byte[] data = null) var task = ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, success: () => Ack.Instance, failure: ex => new Tcp.ErrorClosed(ex.Message)); - await Task.WhenAny(task, Task.Delay(2500)); - ws.Abort(); - Context.Stop(Self); + task.ContinueWith(t => + { + ws.Abort(); + Context.Stop(Self); + }); } } diff --git a/neo/Network/P2P/EmptyActor.cs b/neo/Network/P2P/EmptyActor.cs new file mode 100644 index 0000000000..41382707a9 --- /dev/null +++ b/neo/Network/P2P/EmptyActor.cs @@ -0,0 +1,16 @@ +using Akka.Actor; + +namespace Neo.Network.P2P +{ + class EmptyActor : UntypedActor + { + protected override void OnReceive(object message) + { + } + + internal static Props Props() + { + return Akka.Actor.Props.Create(() => new EmptyActor()); + } + } +} diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index 9c89c10771..f453230149 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -214,8 +214,9 @@ private void Disconnect(DisconnectReason reason, byte[] data = null) var payload = DisconnectPayload.Create(reason, data); var disconnect = Message.Create(MessageCommand.Disconnect, payload); var command = Tcp.Write.Create(ByteString.FromBytes(disconnect.ToArray())); - Sender.Tell(command); - Sender.Tell(Tcp.Close.Instance); + + Sender.Tell(new Tcp.Register(Context.ActorOf(EmptyActor.Props()))); + Sender.Ask(command).ContinueWith(t => Sender.Tell(Tcp.Abort.Instance)); } private void OnTcpCommandFailed(Tcp.Command cmd) From 1e1aedfaae428046573bc16eb3f9635f23b8332d Mon Sep 17 00:00:00 2001 From: luchuan Date: Thu, 17 Oct 2019 18:41:44 +0800 Subject: [PATCH 23/84] remove async --- neo/Network/P2P/Connection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index 28e4eea3c9..cbe3d0779f 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -69,7 +69,7 @@ private void WsReceive() failure: ex => new Tcp.ErrorClosed(ex.Message)); } - protected async void Disconnect(DisconnectReason reason, byte[] data = null) + protected void Disconnect(DisconnectReason reason, byte[] data = null) { disconnected = true; From 0561c32c82def54bdef873b4283d55748fe2cb80 Mon Sep 17 00:00:00 2001 From: luchuan Date: Thu, 17 Oct 2019 20:09:39 +0800 Subject: [PATCH 24/84] fix typo --- neo.UnitTests/Network/P2P/UT_RemoteNode.cs | 2 +- neo/Network/P2P/Connection.cs | 2 +- neo/Network/P2P/Payloads/DisconnectPayload.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs index 85895d3186..e802b2fbbe 100644 --- a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs +++ b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs @@ -153,7 +153,7 @@ public void RemoteNode_Test_Received_Invalid_Data() message.Command.Should().Be(MessageCommand.Disconnect); var disconnectionPayload = (DisconnectPayload)message.Payload; - disconnectionPayload.Reason.Should().Be(DisconnectReason.FormatExcpetion); + disconnectionPayload.Reason.Should().Be(DisconnectReason.FormatException); connectionTestProbe.ExpectMsg(); } diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index cbe3d0779f..6840faf90b 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -138,7 +138,7 @@ private void OnReceived(ByteString data) } catch (FormatException) { - Disconnect(DisconnectReason.FormatExcpetion); + Disconnect(DisconnectReason.FormatException); } catch { diff --git a/neo/Network/P2P/Payloads/DisconnectPayload.cs b/neo/Network/P2P/Payloads/DisconnectPayload.cs index e445c17982..39740f26bc 100644 --- a/neo/Network/P2P/Payloads/DisconnectPayload.cs +++ b/neo/Network/P2P/Payloads/DisconnectPayload.cs @@ -11,7 +11,7 @@ public enum DisconnectReason : byte MagicNumberIncompatible = 0x04, ConnectionTimeout = 0x05, - FormatExcpetion = 0x10, + FormatException = 0x10, InternalError = 0x11, } From 226481a972ad7c5536857fcc494214b2d468ed6a Mon Sep 17 00:00:00 2001 From: luchuan Date: Thu, 17 Oct 2019 20:14:59 +0800 Subject: [PATCH 25/84] remove DisconnectWithAddresses method --- neo/Network/P2P/Peer.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index f453230149..5c2416f11b 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -183,14 +183,14 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) { - DisconnectWithAddresses(DisconnectReason.MaxConnectionReached); + Disconnect(DisconnectReason.MaxConnectionReached); return; } ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { - DisconnectWithAddresses(DisconnectReason.MaxConnectionPerAddressReached); + Disconnect(DisconnectReason.MaxConnectionPerAddressReached); return; } else @@ -202,15 +202,9 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) ConnectedPeers.TryAdd(connection, new List { remote }); } } - - private void DisconnectWithAddresses(DisconnectReason reason) - { - NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); - Disconnect(reason, networkAddresses.ToByteArray()); - } - private void Disconnect(DisconnectReason reason, byte[] data = null) { + NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); var payload = DisconnectPayload.Create(reason, data); var disconnect = Message.Create(MessageCommand.Disconnect, payload); var command = Tcp.Write.Create(ByteString.FromBytes(disconnect.ToArray())); From 0100068144029e68a540b719c7782330bb5d58b1 Mon Sep 17 00:00:00 2001 From: luchuan Date: Thu, 17 Oct 2019 20:20:33 +0800 Subject: [PATCH 26/84] remove DisconnectWithAddresses method --- neo/Network/P2P/Peer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index 5c2416f11b..b41a102887 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -202,10 +202,10 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) ConnectedPeers.TryAdd(connection, new List { remote }); } } - private void Disconnect(DisconnectReason reason, byte[] data = null) + private void Disconnect(DisconnectReason reason) { NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); - var payload = DisconnectPayload.Create(reason, data); + var payload = DisconnectPayload.Create(reason, networkAddresses.ToByteArray()); var disconnect = Message.Create(MessageCommand.Disconnect, payload); var command = Tcp.Write.Create(ByteString.FromBytes(disconnect.ToArray())); From 2d96b3f3a626c4cfe3fde2663ffa951d5dea5da5 Mon Sep 17 00:00:00 2001 From: luchuan Date: Mon, 21 Oct 2019 10:48:51 +0800 Subject: [PATCH 27/84] add localnode remote address --- neo/Network/P2P/Peer.cs | 5 +++++ neo/Network/P2P/RemoteNode.cs | 1 + 2 files changed, 6 insertions(+) diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index b41a102887..86b0889c33 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -64,6 +64,11 @@ static Peer() localAddresses.UnionWith(NetworkInterface.GetAllNetworkInterfaces().SelectMany(p => p.GetIPProperties().UnicastAddresses).Select(p => p.Address.Unmap())); } + public void AddLocalRemoteAddress(IPAddress remoteAddress) + { + localAddresses.Add(remoteAddress); + } + protected void AddPeers(IEnumerable peers) { if (UnconnectedPeers.Count < UnconnectedMax) diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index 0b96c4750e..330fdda37e 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -207,6 +207,7 @@ private void OnVersionPayload(VersionPayload version) if (version.Nonce == LocalNode.Nonce) { + LocalNode.Singleton.AddLocalRemoteAddress(Remote.Address); Disconnect(DisconnectReason.DuplicateConnection); return; } From 5b29aaf99b59945c2ec6606da67ba3a0a18e6853 Mon Sep 17 00:00:00 2001 From: luchuan Date: Mon, 21 Oct 2019 11:11:47 +0800 Subject: [PATCH 28/84] refactor IsDuplicateConnection --- neo/Network/P2P/LocalNode.cs | 5 +++++ neo/Network/P2P/Peer.cs | 17 ++++++----------- neo/Network/P2P/RemoteNode.cs | 1 - 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index eec7a8d3e9..04333acb4f 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -116,6 +116,11 @@ public bool IsDuplicateConnection(RemoteNode remoteNode) var version = remoteNode.Version; var remote = remoteNode.Remote; + if (version.Nonce == Nonce) + { + LocalAddresses.Add(remote.Address); + return true; + } foreach (var pair in RemoteNodes) { var remoteActorRef = pair.Key; diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index 86b0889c33..4f1a3a026c 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -35,7 +35,7 @@ private class WsConnected { public WebSocket Socket; public IPEndPoint Remote; p private ICancelable timer; protected ActorSelection Connections => Context.ActorSelection("connection_*"); - private static readonly HashSet localAddresses = new HashSet(); + protected static readonly HashSet LocalAddresses = new HashSet(); private readonly Dictionary ConnectedAddresses = new Dictionary(); protected readonly ConcurrentDictionary> ConnectedPeers = new ConcurrentDictionary>(); protected ImmutableHashSet UnconnectedPeers = ImmutableHashSet.Empty; @@ -61,19 +61,14 @@ protected virtual int ConnectingMax static Peer() { - localAddresses.UnionWith(NetworkInterface.GetAllNetworkInterfaces().SelectMany(p => p.GetIPProperties().UnicastAddresses).Select(p => p.Address.Unmap())); - } - - public void AddLocalRemoteAddress(IPAddress remoteAddress) - { - localAddresses.Add(remoteAddress); + LocalAddresses.UnionWith(NetworkInterface.GetAllNetworkInterfaces().SelectMany(p => p.GetIPProperties().UnicastAddresses).Select(p => p.Address.Unmap())); } protected void AddPeers(IEnumerable peers) { if (UnconnectedPeers.Count < UnconnectedMax) { - peers = peers.Where(p => p.Port != ListenerTcpPort || !localAddresses.Contains(p.Address)); + peers = peers.Where(p => p.Port != ListenerTcpPort || !LocalAddresses.Contains(p.Address)); ImmutableInterlocked.Update(ref UnconnectedPeers, p => p.Union(peers)); } } @@ -81,7 +76,7 @@ protected void AddPeers(IEnumerable peers) protected void ConnectToPeer(IPEndPoint endPoint, bool isTrusted = false) { endPoint = endPoint.Unmap(); - if (endPoint.Port == ListenerTcpPort && localAddresses.Contains(endPoint.Address)) return; + if (endPoint.Port == ListenerTcpPort && LocalAddresses.Contains(endPoint.Address)) return; if (isTrusted) TrustedIpAddresses.Add(endPoint.Address); if (ConnectedAddresses.TryGetValue(endPoint.Address, out int count) && count >= MaxConnectionsPerAddress) @@ -152,12 +147,12 @@ private void OnStart(ChannelsConfig config) timer = Context.System.Scheduler.ScheduleTellRepeatedlyCancelable(0, 5000, Context.Self, new Timer(), ActorRefs.NoSender); if ((ListenerTcpPort > 0 || ListenerWsPort > 0) - && localAddresses.All(p => !p.IsIPv4MappedToIPv6 || IsIntranetAddress(p)) + && LocalAddresses.All(p => !p.IsIPv4MappedToIPv6 || IsIntranetAddress(p)) && UPnP.Discover()) { try { - localAddresses.Add(UPnP.GetExternalIP()); + LocalAddresses.Add(UPnP.GetExternalIP()); if (ListenerTcpPort > 0) UPnP.ForwardPort(ListenerTcpPort, ProtocolType.Tcp, "NEO Tcp"); if (ListenerWsPort > 0) UPnP.ForwardPort(ListenerWsPort, ProtocolType.Tcp, "NEO WebSocket"); diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index 330fdda37e..0b96c4750e 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -207,7 +207,6 @@ private void OnVersionPayload(VersionPayload version) if (version.Nonce == LocalNode.Nonce) { - LocalNode.Singleton.AddLocalRemoteAddress(Remote.Address); Disconnect(DisconnectReason.DuplicateConnection); return; } From b481a03f24237060a13241179c40685257e5532c Mon Sep 17 00:00:00 2001 From: luchuan Date: Tue, 22 Oct 2019 10:27:45 +0800 Subject: [PATCH 29/84] remove remotenode after received disconnect msg --- neo/Network/P2P/Connection.cs | 1 - neo/Network/P2P/LocalNode.cs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index 6840faf90b..8be1f300e5 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -6,7 +6,6 @@ using System.Net; using System.Net.WebSockets; using System.Threading; -using System.Threading.Tasks; namespace Neo.Network.P2P { diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index 04333acb4f..3e8638c9b7 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -229,6 +229,7 @@ private void OnDisconnectPayload(DisconnectPayload payload) break; default: break; } + Context.Stop(Sender); } public static Props Props(NeoSystem system) From c9b52d696a13c9e28dca5589e02dfb6d6520ae90 Mon Sep 17 00:00:00 2001 From: luchuan Date: Tue, 22 Oct 2019 14:18:45 +0800 Subject: [PATCH 30/84] fix LocalNode#GetRandomConnectedPeers --- neo/Network/P2P/LocalNode.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index 3e8638c9b7..f924d8e04f 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -163,12 +163,16 @@ protected override void NeedMorePeers(int count) public override NetworkAddressWithTime[] GetRandomConnectedPeers(int count) { - Random rand = new Random(); - IEnumerable peers = RemoteNodes.Values - .Where(p => p.ListenerTcpPort > 0) - .GroupBy(p => p.Remote.Address, (k, g) => g.First()) - .OrderBy(p => rand.Next()) - .Take(AddrPayload.MaxCountToSend); + IEnumerable peers = RemoteNodes.Values; + if (RemoteNodes.Count > count) + { + Random rand = new Random(); + peers = RemoteNodes.Values + .Where(p => p.ListenerTcpPort > 0) + .GroupBy(p => p.Remote.Address, (k, g) => g.First()) + .OrderBy(p => rand.Next()) + .Take(count); + } return peers.Select(p => NetworkAddressWithTime.Create(p.Listener.Address, p.Version.Timestamp, p.Version.Capabilities)).ToArray(); } From d3bd21b41029e65ff9b78d651bf4c636dd5428e1 Mon Sep 17 00:00:00 2001 From: luchuan Date: Tue, 22 Oct 2019 14:35:52 +0800 Subject: [PATCH 31/84] fix LocalNode#GetRandomConnectedPeers --- neo/Network/P2P/LocalNode.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index f924d8e04f..acfcba4982 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -163,16 +163,11 @@ protected override void NeedMorePeers(int count) public override NetworkAddressWithTime[] GetRandomConnectedPeers(int count) { - IEnumerable peers = RemoteNodes.Values; - if (RemoteNodes.Count > count) - { - Random rand = new Random(); - peers = RemoteNodes.Values - .Where(p => p.ListenerTcpPort > 0) - .GroupBy(p => p.Remote.Address, (k, g) => g.First()) - .OrderBy(p => rand.Next()) - .Take(count); - } + Random rand = new Random(); + IEnumerable peers = RemoteNodes.Values + .Where(p => p.ListenerTcpPort > 0) + .OrderBy(p => rand.Next()) + .Take(count); return peers.Select(p => NetworkAddressWithTime.Create(p.Listener.Address, p.Version.Timestamp, p.Version.Capabilities)).ToArray(); } From ee3509fb8693799257701720b4128939dda62046 Mon Sep 17 00:00:00 2001 From: luchuan Date: Wed, 23 Oct 2019 21:47:51 +0800 Subject: [PATCH 32/84] fix localnode ut --- neo.UnitTests/Network/P2P/UT_LocalNode.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 753eb1f162..2b0cd0e368 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -1,4 +1,3 @@ -using Akka.Actor; using Akka.IO; using Akka.TestKit.Xunit2; using FluentAssertions; @@ -18,10 +17,10 @@ namespace Neo.UnitTests.Network.P2P [NotReRunnable] public class UT_LocalNode : TestKit { - private static NeoSystem testBlockchain; + private NeoSystem testBlockchain; - [ClassInitialize] - public static void TestSetup(TestContext ctx) + [TestInitialize] + public void TestSetup() { testBlockchain = TestBlockchain.InitializeMockNeoSystem(); } From ccb3f67cf12011e7c2a68bdc78355e0e5be988e2 Mon Sep 17 00:00:00 2001 From: luchuan Date: Fri, 1 Nov 2019 15:54:11 +0800 Subject: [PATCH 33/84] refactor connection --- neo.UnitTests/Network/P2P/UT_RemoteNode.cs | 43 ---------------------- neo/Network/P2P/Connection.cs | 31 +++++++++------- neo/Network/P2P/RemoteNode.cs | 15 ++++++-- 3 files changed, 29 insertions(+), 60 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs index e802b2fbbe..7fa4ce8304 100644 --- a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs +++ b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs @@ -134,48 +134,5 @@ public void RemoteNode_Test_Received_Duplicate_Connection() connectionTestProbeB.ExpectMsg(); } - - [TestMethod] - public void RemoteNode_Test_Received_Invalid_Data() - { - var connectionTestProbe = CreateTestProbe(); - var remoteNodeActor = ActorOfAsTestActorRef(() => new RemoteNode(testBlockchain, connectionTestProbe, null, null)); - connectionTestProbe.ExpectMsg(); // remote node will send version message - - // The `length` field of this message is 0x300000000000, which is more than PayloadMaxSize = 0x02000000 - // Message.cs#TryDeserialize will throw a FormatException - Tcp.Received received = new Tcp.Received(ByteString.FromBytes(new byte[] { 0x02, 0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 })); - var testProbe = CreateTestProbe(); - testProbe.Send(remoteNodeActor, received); // remote node will parse failed - - var tcpWrite = connectionTestProbe.ExpectMsg(); - var message = tcpWrite.Data.ToArray().AsSerializable(); - message.Command.Should().Be(MessageCommand.Disconnect); - - var disconnectionPayload = (DisconnectPayload)message.Payload; - disconnectionPayload.Reason.Should().Be(DisconnectReason.FormatException); - - connectionTestProbe.ExpectMsg(); - } - - [TestMethod] - public void Connection_Test_Timeout() - { - var connectionTestProbe = CreateTestProbe(); - var remoteNodeActor = ActorOfAsTestActorRef(() => new RemoteNode(testBlockchain, connectionTestProbe, null, null)); - connectionTestProbe.ExpectMsg(); // remote node will send version message - - var testProbe = CreateTestProbe(); - testProbe.Send(remoteNodeActor, Connection.Timer.Instance); // remote node will disconnect with `ConnectionTimeout` - - var tcpWrite = connectionTestProbe.ExpectMsg(); - var message = tcpWrite.Data.ToArray().AsSerializable(); - message.Command.Should().Be(MessageCommand.Disconnect); - - var disconnectionPayload = (DisconnectPayload)message.Payload; - disconnectionPayload.Reason.Should().Be(DisconnectReason.ConnectionTimeout); - - connectionTestProbe.ExpectMsg(); - } } } diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index 8be1f300e5..c9ddd09db9 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -1,7 +1,5 @@ using Akka.Actor; using Akka.IO; -using Neo.IO; -using Neo.Network.P2P.Payloads; using System; using System.Net; using System.Net.WebSockets; @@ -68,16 +66,27 @@ private void WsReceive() failure: ex => new Tcp.ErrorClosed(ex.Message)); } - protected void Disconnect(DisconnectReason reason, byte[] data = null) + protected void Disconnect(byte[] lastMessage = null) { disconnected = true; - var payload = DisconnectPayload.Create(reason, data); - var disconnectMessage = Message.Create(MessageCommand.Disconnect, payload); + if (lastMessage == null) + { + if (tcp != null) + { + tcp.Tell(Tcp.Abort.Instance); + } + else + { + ws.Abort(); + } + Context.Stop(Self); + return; + } if (tcp != null) { - tcp.Tell(Tcp.Write.Create(ByteString.FromBytes(disconnectMessage.ToArray()), Ack.Instance)); + tcp.Tell(Tcp.Write.Create(ByteString.FromBytes(lastMessage), Ack.Instance)); Context.SetReceiveTimeout(TimeSpan.FromSeconds(2.5)); Become(msg => { @@ -90,7 +99,7 @@ protected void Disconnect(DisconnectReason reason, byte[] data = null) } else { - ArraySegment segment = new ArraySegment(disconnectMessage.ToArray()); + ArraySegment segment = new ArraySegment(lastMessage); var task = ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, success: () => Ack.Instance, failure: ex => new Tcp.ErrorClosed(ex.Message)); @@ -113,7 +122,7 @@ protected override void OnReceive(object message) switch (message) { case Timer _: - Disconnect(DisconnectReason.ConnectionTimeout); + Disconnect(); break; case Ack _: OnAck(); @@ -135,13 +144,9 @@ private void OnReceived(ByteString data) { OnData(data); } - catch (FormatException) - { - Disconnect(DisconnectReason.FormatException); - } catch { - Disconnect(DisconnectReason.InternalError); + Disconnect(); } } diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index 0b96c4750e..5d226a85a7 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -207,17 +207,17 @@ private void OnVersionPayload(VersionPayload version) if (version.Nonce == LocalNode.Nonce) { - Disconnect(DisconnectReason.DuplicateConnection); + DisconnectWithReason(DisconnectReason.DuplicateConnection); return; } if (version.Magic != ProtocolSettings.Default.Magic) { - Disconnect(DisconnectReason.MagicNumberIncompatible, BitConverter.GetBytes(ProtocolSettings.Default.Magic)); + DisconnectWithReason(DisconnectReason.MagicNumberIncompatible, BitConverter.GetBytes(ProtocolSettings.Default.Magic)); return; } if (Remote != null && LocalNode.Singleton.IsDuplicateConnection(this)) { - Disconnect(DisconnectReason.DuplicateConnection); + DisconnectWithReason(DisconnectReason.DuplicateConnection); return; } @@ -245,7 +245,7 @@ protected override SupervisorStrategy SupervisorStrategy() { return new OneForOneStrategy(ex => { - Disconnect(DisconnectReason.InternalError); + DisconnectWithReason(DisconnectReason.InternalError); return Directive.Stop; }, loggingEnabled: false); } @@ -258,6 +258,13 @@ private Message TryParseMessage() msg_buffer = msg_buffer.Slice(length).Compact(); return msg; } + + private void DisconnectWithReason(DisconnectReason reason, byte[] data = null) + { + var payload = DisconnectPayload.Create(reason, data); + var disconnectMessage = Message.Create(MessageCommand.Disconnect, payload); + Disconnect(disconnectMessage.ToArray()); + } } internal class RemoteNodeMailbox : PriorityMailbox From d11bab241f53de13551d4ba145c8e244393d6007 Mon Sep 17 00:00:00 2001 From: mingee2018 Date: Mon, 11 Nov 2019 10:47:43 +0800 Subject: [PATCH 34/84] fix conflicts --- neo/Network/P2P/Peer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index 8785aeab23..9aa9b4af0c 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -68,7 +68,7 @@ protected void AddPeers(IEnumerable peers) { if (UnconnectedPeers.Count < UnconnectedMax) { - peers = peers.Where(p => (p.Port != ListenerTcpPort || !LocalAddresses.Contains(p.Address)) && !ConnectedPeers.Values.Contains(p)); + peers = peers.Where(p => (p.Port != ListenerTcpPort || !LocalAddresses.Contains(p.Address)) && !ConnectedPeers.Values.Any(q => q.Contains(p))); ImmutableInterlocked.Update(ref UnconnectedPeers, p => p.Union(peers)); } } From bb9bb74b6e701fab3c2d2570bd42b7a60c7329af Mon Sep 17 00:00:00 2001 From: Luchuan Date: Wed, 13 Nov 2019 10:28:15 +0800 Subject: [PATCH 35/84] fix ut bug --- neo.UnitTests/Network/P2P/UT_LocalNode.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 2b0cd0e368..965624b6ed 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -152,9 +152,9 @@ public void Test_Peer_MaxConnection_Reached() IPEndPoint remote = null; Tcp.Connected connected = null; var senderDict = new Dictionary(); - for (int i = 1; i <= LocalNode.Singleton.MaxConnections; i++) + for (int i = LocalNode.Singleton.ConnectedCount; i <= LocalNode.Singleton.MaxConnections; i++) { - remote = new IPEndPoint(IPAddress.Parse("192.168.1." + i), 8080); + remote = new IPEndPoint(IPAddress.Parse("192.169.2." + i), 8080); connected = new Tcp.Connected(remote, local); var proble = CreateTestProbe(); proble.Send(localNode, connected); From 827c7bdb4a46661b68f1f089eabbbf4e449a72d1 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Fri, 15 Nov 2019 11:28:39 +0800 Subject: [PATCH 36/84] refactor LocalNode.CheckDuplicateConnection --- neo/Network/P2P/LocalNode.cs | 6 +++++- neo/Network/P2P/RemoteNode.cs | 7 +------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index 5250f3fd64..9932d26782 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -112,7 +112,7 @@ private static IEnumerable GetIPEndPointsFromSeedList(int seedsToTak } } - public bool IsDuplicateConnection(RemoteNode remoteNode) + public bool CheckDuplicateConnection(RemoteNode remoteNode) { var version = remoteNode.Version; var remote = remoteNode.Remote; @@ -122,6 +122,10 @@ public bool IsDuplicateConnection(RemoteNode remoteNode) LocalAddresses.Add(remote.Address); return true; } + if (remote == null) + { + return false; + } foreach (var pair in RemoteNodes) { var remoteActorRef = pair.Key; diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index 5d226a85a7..316cd0f99e 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -205,17 +205,12 @@ private void OnVersionPayload(VersionPayload version) } } - if (version.Nonce == LocalNode.Nonce) - { - DisconnectWithReason(DisconnectReason.DuplicateConnection); - return; - } if (version.Magic != ProtocolSettings.Default.Magic) { DisconnectWithReason(DisconnectReason.MagicNumberIncompatible, BitConverter.GetBytes(ProtocolSettings.Default.Magic)); return; } - if (Remote != null && LocalNode.Singleton.IsDuplicateConnection(this)) + if (LocalNode.Singleton.CheckDuplicateConnection(this)) { DisconnectWithReason(DisconnectReason.DuplicateConnection); return; From f1ab573d37dba8091343fbf75195602d15a792bd Mon Sep 17 00:00:00 2001 From: Luchuan Date: Fri, 15 Nov 2019 14:42:52 +0800 Subject: [PATCH 37/84] rename DuplicateConnection to DuplicateNone and refactor ConnectedPeers --- .../Network/P2P/Payloads/UT_DisconnectPayload.cs | 6 +++--- neo.UnitTests/Network/P2P/UT_RemoteNode.cs | 2 +- neo/Network/P2P/LocalNode.cs | 12 ++++++------ neo/Network/P2P/Payloads/DisconnectPayload.cs | 2 +- neo/Network/P2P/Peer.cs | 11 +++++------ neo/Network/P2P/RemoteNode.cs | 4 ++-- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectPayload.cs b/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectPayload.cs index ff26d0e751..10d1019bfe 100644 --- a/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectPayload.cs +++ b/neo.UnitTests/Network/P2P/Payloads/UT_DisconnectPayload.cs @@ -12,7 +12,7 @@ public class UT_DisconnectPayload [TestMethod] public void Size_Get() { - var payload = DisconnectPayload.Create(DisconnectReason.DuplicateConnection, new byte[] { 0x01, 0x02 }); + var payload = DisconnectPayload.Create(DisconnectReason.DuplicateNonce, new byte[] { 0x01, 0x02 }); payload.Size.Should().Be(4); } @@ -28,7 +28,7 @@ public void Deserialize() payload.Deserialize(reader); } } - Assert.AreEqual(DisconnectReason.DuplicateConnection, payload.Reason); + Assert.AreEqual(DisconnectReason.DuplicateNonce, payload.Reason); Assert.AreEqual(2, payload.Data.Length); Assert.AreEqual(0x01, payload.Data[0]); Assert.AreEqual(0x02, payload.Data[1]); @@ -37,7 +37,7 @@ public void Deserialize() [TestMethod] public void Serialize() { - var payload = DisconnectPayload.Create(DisconnectReason.DuplicateConnection, new byte[] { 0x01, 0x02 }); + var payload = DisconnectPayload.Create(DisconnectReason.DuplicateNonce, new byte[] { 0x01, 0x02 }); payload.ToArray().ToHexString().Should().Be("03020102"); } } diff --git a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs index 7fa4ce8304..c1afea8805 100644 --- a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs +++ b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs @@ -130,7 +130,7 @@ public void RemoteNode_Test_Received_Duplicate_Connection() message.Command.Should().Be(MessageCommand.Disconnect); var disconnectionPayload = (DisconnectPayload)message.Payload; - disconnectionPayload.Reason.Should().Be(DisconnectReason.DuplicateConnection); + disconnectionPayload.Reason.Should().Be(DisconnectReason.DuplicateNonce); connectionTestProbeB.ExpectMsg(); } diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index 9932d26782..57e9a2dcff 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -112,7 +112,7 @@ private static IEnumerable GetIPEndPointsFromSeedList(int seedsToTak } } - public bool CheckDuplicateConnection(RemoteNode remoteNode) + public bool CheckDuplicateNonce(IActorRef remoteActor, RemoteNode remoteNode) { var version = remoteNode.Version; var remote = remoteNode.Remote; @@ -132,14 +132,14 @@ public bool CheckDuplicateConnection(RemoteNode remoteNode) var otherNode = pair.Value; if (otherNode != remoteNode && otherNode.Remote.Address.Equals(remote.Address) && otherNode.Version?.Nonce == version.Nonce) { - // add the duplicate address in ConnectedPeers - if (ConnectedPeers.TryGetValue(remoteActorRef, out List endPoints)) - { - endPoints.Add(remote); - } return true; } } + if (remote.Port != remoteNode.ListenerTcpPort && remoteNode.ListenerTcpPort != 0) + { + ConnectedPeers.TryUpdate(remoteActor, remoteNode.Listener, remote); + } + return false; } diff --git a/neo/Network/P2P/Payloads/DisconnectPayload.cs b/neo/Network/P2P/Payloads/DisconnectPayload.cs index 39740f26bc..3ea568aaac 100644 --- a/neo/Network/P2P/Payloads/DisconnectPayload.cs +++ b/neo/Network/P2P/Payloads/DisconnectPayload.cs @@ -7,7 +7,7 @@ public enum DisconnectReason : byte { MaxConnectionReached = 0x01, MaxConnectionPerAddressReached = 0x02, - DuplicateConnection = 0x03, + DuplicateNonce = 0x03, MagicNumberIncompatible = 0x04, ConnectionTimeout = 0x05, diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index 9aa9b4af0c..26f5a23a7c 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -37,7 +37,7 @@ private class WsConnected { public WebSocket Socket; public IPEndPoint Remote; p protected static readonly HashSet LocalAddresses = new HashSet(); private readonly Dictionary ConnectedAddresses = new Dictionary(); - protected readonly ConcurrentDictionary> ConnectedPeers = new ConcurrentDictionary>(); + protected readonly ConcurrentDictionary ConnectedPeers = new ConcurrentDictionary(); protected ImmutableHashSet UnconnectedPeers = ImmutableHashSet.Empty; protected ImmutableHashSet ConnectingPeers = ImmutableHashSet.Empty; protected HashSet TrustedIpAddresses { get; } = new HashSet(); @@ -68,7 +68,7 @@ protected void AddPeers(IEnumerable peers) { if (UnconnectedPeers.Count < UnconnectedMax) { - peers = peers.Where(p => (p.Port != ListenerTcpPort || !LocalAddresses.Contains(p.Address)) && !ConnectedPeers.Values.Any(q => q.Contains(p))); + peers = peers.Where(p => (p.Port != ListenerTcpPort || !LocalAddresses.Contains(p.Address)) && !ConnectedPeers.Values.Contains(p)); ImmutableInterlocked.Update(ref UnconnectedPeers, p => p.Union(peers)); } } @@ -81,7 +81,7 @@ protected void ConnectToPeer(IPEndPoint endPoint, bool isTrusted = false) if (isTrusted) TrustedIpAddresses.Add(endPoint.Address); if (ConnectedAddresses.TryGetValue(endPoint.Address, out int count) && count >= MaxConnectionsPerAddress) return; - if (ConnectedPeers.Values.Any(p => p.Contains(endPoint))) return; + if (ConnectedPeers.Values.Contains(endPoint)) return; ImmutableInterlocked.Update(ref ConnectingPeers, p => { if ((p.Count >= ConnectingMax && !isTrusted) || p.Contains(endPoint)) return p; @@ -199,7 +199,7 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) IActorRef connection = Context.ActorOf(ProtocolProps(Sender, remote, local), $"connection_{Guid.NewGuid()}"); Context.Watch(connection); Sender.Tell(new Tcp.Register(connection)); - ConnectedPeers.TryAdd(connection, new List { remote }); + ConnectedPeers.TryAdd(connection, remote); } } private void Disconnect(DisconnectReason reason) @@ -225,9 +225,8 @@ private void OnTcpCommandFailed(Tcp.Command cmd) private void OnTerminated(IActorRef actorRef) { - if (ConnectedPeers.TryRemove(actorRef, out List endPoints)) + if (ConnectedPeers.TryRemove(actorRef, out IPEndPoint endPoint)) { - IPEndPoint endPoint = endPoints[0]; ConnectedAddresses.TryGetValue(endPoint.Address, out int count); if (count > 0) count--; if (count == 0) diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index 316cd0f99e..64a745a250 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -210,9 +210,9 @@ private void OnVersionPayload(VersionPayload version) DisconnectWithReason(DisconnectReason.MagicNumberIncompatible, BitConverter.GetBytes(ProtocolSettings.Default.Magic)); return; } - if (LocalNode.Singleton.CheckDuplicateConnection(this)) + if (LocalNode.Singleton.CheckDuplicateNonce(Self, this)) { - DisconnectWithReason(DisconnectReason.DuplicateConnection); + DisconnectWithReason(DisconnectReason.DuplicateNonce); return; } From 1b701b8d638552f403f1ce1312eb36ed08e0fe25 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Fri, 15 Nov 2019 18:51:59 +0800 Subject: [PATCH 38/84] add limit to the LocalAddresses --- neo/Network/P2P/LocalNode.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index 57e9a2dcff..8e10db3fbb 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -119,7 +119,10 @@ public bool CheckDuplicateNonce(IActorRef remoteActor, RemoteNode remoteNode) if (version.Nonce == Nonce) { - LocalAddresses.Add(remote.Address); + if (LocalAddresses.Count < MaxConnectionsPerAddress) + { + LocalAddresses.Add(remote.Address); + } return true; } if (remote == null) From f0f922d598cdfec268688ed4fc5148361bb8e7c8 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Fri, 15 Nov 2019 18:54:08 +0800 Subject: [PATCH 39/84] change the limit to MaxConnections --- neo/Network/P2P/LocalNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index 8e10db3fbb..f14bf2d622 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -119,7 +119,7 @@ public bool CheckDuplicateNonce(IActorRef remoteActor, RemoteNode remoteNode) if (version.Nonce == Nonce) { - if (LocalAddresses.Count < MaxConnectionsPerAddress) + if (LocalAddresses.Count < MaxConnections) { LocalAddresses.Add(remote.Address); } From 967de1592e1e6a859cb727785e210fb360df9632 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Fri, 15 Nov 2019 19:06:31 +0800 Subject: [PATCH 40/84] remove assign null --- neo.UnitTests/Network/P2P/UT_LocalNode.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 965624b6ed..4044d4b463 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -83,8 +83,8 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() var local = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080); // Create the maximum number of per address connections - IPEndPoint remote = null; - Tcp.Connected connected = null; + IPEndPoint remote; + Tcp.Connected connected; var senderDict = new Dictionary(); for (int i = 1; i <= LocalNode.Singleton.MaxConnectionsPerAddress; i++) { @@ -149,8 +149,8 @@ public void Test_Peer_MaxConnection_Reached() var local = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080); // Create the maximum number of connections - IPEndPoint remote = null; - Tcp.Connected connected = null; + IPEndPoint remote; + Tcp.Connected connected; var senderDict = new Dictionary(); for (int i = LocalNode.Singleton.ConnectedCount; i <= LocalNode.Singleton.MaxConnections; i++) { From 6adc3da8665178f6e93dfce7df842859883b8aee Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 21 Nov 2019 09:26:06 +0800 Subject: [PATCH 41/84] refactor LocalNode, RemoteNode --- neo.UnitTests/Network/P2P/UT_RemoteNode.cs | 2 ++ neo/Network/P2P/Connection.cs | 38 +++------------------- neo/Network/P2P/EmptyActor.cs | 16 --------- neo/Network/P2P/LocalNode.cs | 32 ++++++++++++++++-- neo/Network/P2P/Peer.cs | 28 ++++------------ neo/Network/P2P/RemoteNode.cs | 21 +++++++++--- 6 files changed, 59 insertions(+), 78 deletions(-) delete mode 100644 neo/Network/P2P/EmptyActor.cs diff --git a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs index c1afea8805..bfcdc57bcd 100644 --- a/neo.UnitTests/Network/P2P/UT_RemoteNode.cs +++ b/neo.UnitTests/Network/P2P/UT_RemoteNode.cs @@ -59,6 +59,7 @@ public void RemoteNode_Test_Abort_DifferentMagic() var disconnectionPayload = (DisconnectPayload)message.Payload; disconnectionPayload.Reason.Should().Be(DisconnectReason.MagicNumberIncompatible); + testProbe.Send(remoteNodeActor, RemoteNode.Ack.Instance); connectionTestProbe.ExpectMsg(); } @@ -132,6 +133,7 @@ public void RemoteNode_Test_Received_Duplicate_Connection() var disconnectionPayload = (DisconnectPayload)message.Payload; disconnectionPayload.Reason.Should().Be(DisconnectReason.DuplicateNonce); + testProbe.Send(remoteNodeActorB, RemoteNode.Ack.Instance); connectionTestProbeB.ExpectMsg(); } } diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index c9ddd09db9..33108db9a7 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -66,49 +66,19 @@ private void WsReceive() failure: ex => new Tcp.ErrorClosed(ex.Message)); } - protected void Disconnect(byte[] lastMessage = null) + public void Disconnect(bool abort = false) { disconnected = true; - if (lastMessage == null) - { - if (tcp != null) - { - tcp.Tell(Tcp.Abort.Instance); - } - else - { - ws.Abort(); - } - Context.Stop(Self); - return; - } - if (tcp != null) { - tcp.Tell(Tcp.Write.Create(ByteString.FromBytes(lastMessage), Ack.Instance)); - Context.SetReceiveTimeout(TimeSpan.FromSeconds(2.5)); - Become(msg => - { - if (msg is Ack || msg is ReceiveTimeout) - { - tcp.Tell(Tcp.Abort.Instance); - Context.Stop(Self); - } - }); + tcp.Tell(abort ? (Tcp.CloseCommand)Tcp.Abort.Instance : Tcp.Close.Instance); } else { - ArraySegment segment = new ArraySegment(lastMessage); - var task = ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, - success: () => Ack.Instance, - failure: ex => new Tcp.ErrorClosed(ex.Message)); - task.ContinueWith(t => - { - ws.Abort(); - Context.Stop(Self); - }); + ws.Abort(); } + Context.Stop(Self); } protected virtual void OnAck() diff --git a/neo/Network/P2P/EmptyActor.cs b/neo/Network/P2P/EmptyActor.cs deleted file mode 100644 index 41382707a9..0000000000 --- a/neo/Network/P2P/EmptyActor.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Akka.Actor; - -namespace Neo.Network.P2P -{ - class EmptyActor : UntypedActor - { - protected override void OnReceive(object message) - { - } - - internal static Props Props() - { - return Akka.Actor.Props.Create(() => new EmptyActor()); - } - } -} diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index f14bf2d622..9fbb383a5b 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -1,4 +1,5 @@ using Akka.Actor; +using Akka.IO; using Neo.IO; using Neo.Ledger; using Neo.Network.P2P.Payloads; @@ -8,6 +9,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using System.Net.WebSockets; using System.Reflection; using System.Threading; @@ -76,7 +78,7 @@ private static IPEndPoint GetIPEndpointFromHostPort(string hostNameOrAddress, in IPHostEntry entry; try { - entry = Dns.GetHostEntry(hostNameOrAddress); + entry = System.Net.Dns.GetHostEntry(hostNameOrAddress); } catch (SocketException) { @@ -169,7 +171,7 @@ protected override void NeedMorePeers(int count) } } - public override NetworkAddressWithTime[] GetRandomConnectedPeers(int count) + public NetworkAddressWithTime[] GetRandomConnectedPeers(int count) { Random rand = new Random(); IEnumerable peers = RemoteNodes.Values @@ -221,6 +223,32 @@ private void OnSendDirectly(IInventory inventory) Connections.Tell(inventory); } + protected override void TcpDisconnect(DisconnectReason reason) + { + var disconnectMessage = CreateDisconnectMessage(reason); + var command = Tcp.Write.Create(ByteString.FromBytes(disconnectMessage.ToArray())); + + Sender.Tell(new Tcp.Register(ActorRefs.NoSender)); + Sender.Ask(command).ContinueWith(t => Sender.Tell(Tcp.Abort.Instance)); + } + + protected override void WsDisconnect(WebSocket ws, DisconnectReason reason) + { + var disconnectMessage = CreateDisconnectMessage(reason); + ArraySegment segment = new ArraySegment(disconnectMessage.ToArray()); + + ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, + failure: ex => new Tcp.ErrorClosed(ex.Message)); + ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); + } + + private Message CreateDisconnectMessage(DisconnectReason reason) + { + NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); + var payload = DisconnectPayload.Create(reason, networkAddresses.ToByteArray()); + return Message.Create(MessageCommand.Disconnect, payload); + } + private void OnDisconnectPayload(DisconnectPayload payload) { switch (payload.Reason) diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index 26f5a23a7c..c17657b7ce 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -14,7 +14,6 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Net.WebSockets; -using System.Threading; using System.Threading.Tasks; namespace Neo.Network.P2P @@ -100,8 +99,6 @@ private static bool IsIntranetAddress(IPAddress address) protected abstract void NeedMorePeers(int count); - public abstract NetworkAddressWithTime[] GetRandomConnectedPeers(int count); - protected override void OnReceive(object message) { switch (message) @@ -183,14 +180,14 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) { - Disconnect(DisconnectReason.MaxConnectionReached); + TcpDisconnect(DisconnectReason.MaxConnectionReached); return; } ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { - Disconnect(DisconnectReason.MaxConnectionPerAddressReached); + TcpDisconnect(DisconnectReason.MaxConnectionPerAddressReached); return; } else @@ -202,16 +199,7 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) ConnectedPeers.TryAdd(connection, remote); } } - private void Disconnect(DisconnectReason reason) - { - NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); - var payload = DisconnectPayload.Create(reason, networkAddresses.ToByteArray()); - var disconnect = Message.Create(MessageCommand.Disconnect, payload); - var command = Tcp.Write.Create(ByteString.FromBytes(disconnect.ToArray())); - - Sender.Tell(new Tcp.Register(Context.ActorOf(EmptyActor.Props()))); - Sender.Ask(command).ContinueWith(t => Sender.Tell(Tcp.Abort.Instance)); - } + protected abstract void TcpDisconnect(DisconnectReason reason); private void OnTcpCommandFailed(Tcp.Command cmd) { @@ -254,13 +242,7 @@ private void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { - NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); - var payload = DisconnectPayload.Create(DisconnectReason.MaxConnectionPerAddressReached, networkAddresses.ToByteArray()); - var disconnectMessage = Message.Create(MessageCommand.Disconnect, payload); - ArraySegment segment = new ArraySegment(disconnectMessage.ToArray()); - ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, - failure: ex => new Tcp.ErrorClosed(ex.Message)); - ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); + WsDisconnect(ws, DisconnectReason.MaxConnectionPerAddressReached); } else { @@ -269,6 +251,8 @@ private void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) } } + protected abstract void WsDisconnect(WebSocket ws, DisconnectReason reason); + protected override void PostStop() { timer.CancelIfNotNull(); diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index 64a745a250..f7c9229dbd 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -26,6 +26,7 @@ internal class Relay { public IInventory Inventory; } private BloomFilter bloom_filter; private bool ack = true; private bool verack = false; + private bool isWaitingForDisconnect = false; public IPEndPoint Listener => new IPEndPoint(Remote.Address, ListenerTcpPort); public int ListenerTcpPort { get; private set; } = 0; @@ -106,8 +107,15 @@ private void EnqueueMessage(Message message) protected override void OnAck() { - ack = true; - CheckMessageQueue(); + if (isWaitingForDisconnect) + { + Disconnect(true); + } + else + { + ack = true; + CheckMessageQueue(); + } } protected override void OnData(ByteString data) @@ -256,9 +264,14 @@ private Message TryParseMessage() private void DisconnectWithReason(DisconnectReason reason, byte[] data = null) { + message_queue_high.Clear(); + message_queue_low.Clear(); + var payload = DisconnectPayload.Create(reason, data); - var disconnectMessage = Message.Create(MessageCommand.Disconnect, payload); - Disconnect(disconnectMessage.ToArray()); + var message = Message.Create(MessageCommand.Disconnect, payload); + SendMessage(message); + + isWaitingForDisconnect = true; } } From 64e01fb03408a16e5096fa4804d028170a0ea85a Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 21 Nov 2019 10:39:09 +0800 Subject: [PATCH 42/84] reset test ip --- neo.UnitTests/Network/P2P/UT_LocalNode.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 4044d4b463..25bbf94982 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -146,7 +146,7 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() public void Test_Peer_MaxConnection_Reached() { var localNode = testBlockchain.LocalNode; - var local = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080); + var local = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8991); // Create the maximum number of connections IPEndPoint remote; @@ -154,7 +154,7 @@ public void Test_Peer_MaxConnection_Reached() var senderDict = new Dictionary(); for (int i = LocalNode.Singleton.ConnectedCount; i <= LocalNode.Singleton.MaxConnections; i++) { - remote = new IPEndPoint(IPAddress.Parse("192.169.2." + i), 8080); + remote = new IPEndPoint(IPAddress.Parse("191.13.2." + i), 8991); connected = new Tcp.Connected(remote, local); var proble = CreateTestProbe(); proble.Send(localNode, connected); @@ -175,7 +175,7 @@ public void Test_Peer_MaxConnection_Reached() Version = 6, Capabilities = new NodeCapability[] { - new ServerCapability(NodeCapabilityType.TcpServer, 8080) + new ServerCapability(NodeCapabilityType.TcpServer, 8991) } }; var versionReceived = new Tcp.Received(ByteString.FromBytes(Message.Create(MessageCommand.Version, payload).ToArray())); @@ -187,7 +187,7 @@ public void Test_Peer_MaxConnection_Reached() testProbe.ExpectMsg(); // remote node will send verack and change its listenerPort // create one more remote connection and localnode will disconnect with `MaxConnectionReached` - remote = new IPEndPoint(IPAddress.Parse("192.168.2.1"), 8080); + remote = new IPEndPoint(IPAddress.Parse("192.168.2.1"), 8991); connected = new Tcp.Connected(remote, local); testProbe.Send(localNode, connected); @@ -204,7 +204,7 @@ public void Test_Peer_MaxConnection_Reached() var count = DisconnectPayload.MaxDataSize; NetworkAddressWithTime[] addrs = disconnectionPayload.Data.AsSerializableArray(count); addrs.Length.Should().Be(1); - addrs[0].EndPoint.Port.Should().Be(8080); + addrs[0].EndPoint.Port.Should().Be(8991); } [TestMethod] From 76b60bcd863ca94b848f23d896afea6958018a90 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 21 Nov 2019 11:00:48 +0800 Subject: [PATCH 43/84] fix ut --- neo.UnitTests/Network/P2P/UT_LocalNode.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 25bbf94982..767b990847 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -152,14 +152,16 @@ public void Test_Peer_MaxConnection_Reached() IPEndPoint remote; Tcp.Connected connected; var senderDict = new Dictionary(); - for (int i = LocalNode.Singleton.ConnectedCount; i <= LocalNode.Singleton.MaxConnections; i++) + for (int i = LocalNode.Singleton.ConnectedCount; i < LocalNode.Singleton.MaxConnections; i++) { remote = new IPEndPoint(IPAddress.Parse("191.13.2." + i), 8991); connected = new Tcp.Connected(remote, local); var proble = CreateTestProbe(); proble.Send(localNode, connected); proble.ExpectMsg(); // register msg is earlier than version msg - proble.ExpectMsg(); // remote ndoe send version msg + var verionMsg = proble.ExpectMsg(); // remote ndoe send version msg + Message version = verionMsg.Data.ToArray().AsSerializable(); + version.Command.Should().Be(MessageCommand.Version); senderDict[remote] = proble; } From 66eb08a6cb802e5a01de66c00a1ff629d0fdb20c Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 21 Nov 2019 11:27:31 +0800 Subject: [PATCH 44/84] format --- neo/Network/P2P/Connection.cs | 5 ++--- neo/Network/P2P/Peer.cs | 1 - neo/Network/P2P/RemoteNode.cs | 2 -- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/neo/Network/P2P/Connection.cs b/neo/Network/P2P/Connection.cs index 33108db9a7..5a00a588ef 100644 --- a/neo/Network/P2P/Connection.cs +++ b/neo/Network/P2P/Connection.cs @@ -69,7 +69,6 @@ private void WsReceive() public void Disconnect(bool abort = false) { disconnected = true; - if (tcp != null) { tcp.Tell(abort ? (Tcp.CloseCommand)Tcp.Abort.Instance : Tcp.Close.Instance); @@ -92,7 +91,7 @@ protected override void OnReceive(object message) switch (message) { case Timer _: - Disconnect(); + Disconnect(true); break; case Ack _: OnAck(); @@ -116,7 +115,7 @@ private void OnReceived(ByteString data) } catch { - Disconnect(); + Disconnect(true); } } diff --git a/neo/Network/P2P/Peer.cs b/neo/Network/P2P/Peer.cs index c17657b7ce..24204d7a19 100644 --- a/neo/Network/P2P/Peer.cs +++ b/neo/Network/P2P/Peer.cs @@ -188,7 +188,6 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) if (count >= MaxConnectionsPerAddress) { TcpDisconnect(DisconnectReason.MaxConnectionPerAddressReached); - return; } else { diff --git a/neo/Network/P2P/RemoteNode.cs b/neo/Network/P2P/RemoteNode.cs index f7c9229dbd..40b30085db 100644 --- a/neo/Network/P2P/RemoteNode.cs +++ b/neo/Network/P2P/RemoteNode.cs @@ -212,7 +212,6 @@ private void OnVersionPayload(VersionPayload version) break; } } - if (version.Magic != ProtocolSettings.Default.Magic) { DisconnectWithReason(DisconnectReason.MagicNumberIncompatible, BitConverter.GetBytes(ProtocolSettings.Default.Magic)); @@ -223,7 +222,6 @@ private void OnVersionPayload(VersionPayload version) DisconnectWithReason(DisconnectReason.DuplicateNonce); return; } - SendMessage(Message.Create(MessageCommand.Verack)); } From 34d5534ff1cbac0392f5f8315f79d134caefff04 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 21 Nov 2019 13:54:28 +0800 Subject: [PATCH 45/84] Update MessageCommand.cs --- neo/Network/P2P/MessageCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/MessageCommand.cs b/neo/Network/P2P/MessageCommand.cs index 6270e1513c..bd3d5d36bd 100644 --- a/neo/Network/P2P/MessageCommand.cs +++ b/neo/Network/P2P/MessageCommand.cs @@ -11,7 +11,7 @@ public enum MessageCommand : byte Addr = 0x11, Ping = 0x18, Pong = 0x19, - Disconnect = 0x88, + Disconnect = 0x1f, //synchronization GetHeaders = 0x20, From 49c4267405db52c490b23e10c95c070ecf26e666 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 21 Nov 2019 14:00:59 +0800 Subject: [PATCH 46/84] Split classes --- neo/Network/P2P/Payloads/DisconnectPayload.cs | 14 +------------- neo/Network/P2P/Payloads/DisconnectReason.cs | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 neo/Network/P2P/Payloads/DisconnectReason.cs diff --git a/neo/Network/P2P/Payloads/DisconnectPayload.cs b/neo/Network/P2P/Payloads/DisconnectPayload.cs index 3ea568aaac..9684f93c15 100644 --- a/neo/Network/P2P/Payloads/DisconnectPayload.cs +++ b/neo/Network/P2P/Payloads/DisconnectPayload.cs @@ -3,18 +3,6 @@ namespace Neo.Network.P2P.Payloads { - public enum DisconnectReason : byte - { - MaxConnectionReached = 0x01, - MaxConnectionPerAddressReached = 0x02, - DuplicateNonce = 0x03, - MagicNumberIncompatible = 0x04, - ConnectionTimeout = 0x05, - - FormatException = 0x10, - InternalError = 0x11, - } - public class DisconnectPayload : ISerializable { public const int MaxDataSize = 5120; @@ -29,7 +17,7 @@ public static DisconnectPayload Create(DisconnectReason reason, byte[] data = nu return new DisconnectPayload { Reason = reason, - Data = data == null ? new byte[0] : data + Data = data ?? (new byte[0]) }; } diff --git a/neo/Network/P2P/Payloads/DisconnectReason.cs b/neo/Network/P2P/Payloads/DisconnectReason.cs new file mode 100644 index 0000000000..86036fa5a2 --- /dev/null +++ b/neo/Network/P2P/Payloads/DisconnectReason.cs @@ -0,0 +1,14 @@ +namespace Neo.Network.P2P.Payloads +{ + public enum DisconnectReason : byte + { + MaxConnectionReached = 0x01, + MaxConnectionPerAddressReached = 0x02, + DuplicateNonce = 0x03, + + MagicNumberIncompatible = 0x10, + FormatException = 0x11, + + InternalError = 0x20, + } +} From cb75a7650c8fb38a437aa8909f96fc6b01f0d722 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 21 Nov 2019 14:22:36 +0800 Subject: [PATCH 47/84] Update DisconnectPayload.cs --- neo/Network/P2P/Payloads/DisconnectPayload.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/Payloads/DisconnectPayload.cs b/neo/Network/P2P/Payloads/DisconnectPayload.cs index 9684f93c15..6657350db4 100644 --- a/neo/Network/P2P/Payloads/DisconnectPayload.cs +++ b/neo/Network/P2P/Payloads/DisconnectPayload.cs @@ -5,7 +5,7 @@ namespace Neo.Network.P2P.Payloads { public class DisconnectPayload : ISerializable { - public const int MaxDataSize = 5120; + public const int MaxDataSize = 1024; public DisconnectReason Reason; public byte[] Data; From 9d14691edbcec9ae6068f0d78189329d66d5ee42 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 21 Nov 2019 14:33:45 +0800 Subject: [PATCH 48/84] Update LocalNode.cs --- neo/Network/P2P/LocalNode.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index 9fbb383a5b..f2a236d048 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -244,8 +244,18 @@ protected override void WsDisconnect(WebSocket ws, DisconnectReason reason) private Message CreateDisconnectMessage(DisconnectReason reason) { - NetworkAddressWithTime[] networkAddresses = GetRandomConnectedPeers(AddrPayload.MaxCountToSend); - var payload = DisconnectPayload.Create(reason, networkAddresses.ToByteArray()); + byte[] data; + switch (reason) + { + case DisconnectReason.MaxConnectionReached: + case DisconnectReason.MaxConnectionPerAddressReached: + data = GetRandomConnectedPeers(AddrPayload.MaxCountToSend).ToByteArray(); + break; + default: + data = new byte[0]; + break; + } + var payload = DisconnectPayload.Create(reason, data); return Message.Create(MessageCommand.Disconnect, payload); } From 86efb94da8c06745cba046926581d8ea901cd5c2 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 21 Nov 2019 14:52:33 +0800 Subject: [PATCH 49/84] send disconnect msg attach with 10 addrs --- neo/Network/P2P/LocalNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index f2a236d048..d4efbe3cf6 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -249,7 +249,7 @@ private Message CreateDisconnectMessage(DisconnectReason reason) { case DisconnectReason.MaxConnectionReached: case DisconnectReason.MaxConnectionPerAddressReached: - data = GetRandomConnectedPeers(AddrPayload.MaxCountToSend).ToByteArray(); + data = GetRandomConnectedPeers(10).ToByteArray(); break; default: data = new byte[0]; From 3ab636cae7d40a583c495fa247a745ebc7b9d3db Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 21 Nov 2019 14:54:20 +0800 Subject: [PATCH 50/84] replace 10 by MinDesiredConnections --- neo/Network/P2P/LocalNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index d4efbe3cf6..b2bae11e24 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -249,7 +249,7 @@ private Message CreateDisconnectMessage(DisconnectReason reason) { case DisconnectReason.MaxConnectionReached: case DisconnectReason.MaxConnectionPerAddressReached: - data = GetRandomConnectedPeers(10).ToByteArray(); + data = GetRandomConnectedPeers(MinDesiredConnections).ToByteArray(); break; default: data = new byte[0]; From 817ba9b9ed636756a61efe5d1e11528b6695f1db Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 21 Nov 2019 15:08:51 +0800 Subject: [PATCH 51/84] fix Test_Peer_Max_Per_Address_Connection_Reached and add more assertion --- neo.UnitTests/Network/P2P/UT_LocalNode.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 767b990847..818380fe2c 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -88,13 +88,15 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() var senderDict = new Dictionary(); for (int i = 1; i <= LocalNode.Singleton.MaxConnectionsPerAddress; i++) { - remote = new IPEndPoint(IPAddress.Parse("192.168.1.1"), 8080 + i); + remote = new IPEndPoint(IPAddress.Parse("192.167.1.1"), 8080 + i); connected = new Tcp.Connected(remote, local); var proble = CreateTestProbe(); proble.Send(localNode, connected); proble.ExpectMsg(); // register msg is earlier than version msg - proble.ExpectMsg(); // remote ndoe send version msg + var verionMsg = proble.ExpectMsg(); // remote ndoe send version msg + Message version = verionMsg.Data.ToArray().AsSerializable(); + version.Command.Should().Be(MessageCommand.Version); // check version msg senderDict[remote] = proble; } @@ -122,7 +124,7 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() testProbe.ExpectMsg(); // remote node will send verack and change its listenerPort // create one more remote connection and localnode will disconnect with `MaxConnectionPerAddressReached` - remote = new IPEndPoint(IPAddress.Parse("192.168.1.1"), 8079); + remote = new IPEndPoint(IPAddress.Parse("192.167.1.1"), 8079); connected = new Tcp.Connected(remote, local); testProbe.Send(localNode, connected); @@ -139,7 +141,7 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() var count = DisconnectPayload.MaxDataSize; NetworkAddressWithTime[] addrs = disconnectionPayload.Data.AsSerializableArray(count); addrs.Length.Should().Be(1); - addrs[0].EndPoint.Address.Should().BeEquivalentTo(IPAddress.Parse("192.168.1.1")); + addrs[0].EndPoint.Address.Should().BeEquivalentTo(IPAddress.Parse("192.167.1.1")); } [TestMethod] From 6b06c23fb24f2af42f46179b1333cc98b8611a06 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 21 Nov 2019 15:11:27 +0800 Subject: [PATCH 52/84] reset MinDesiredConnections to const 10 --- neo/Network/P2P/LocalNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index b2bae11e24..d4efbe3cf6 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -249,7 +249,7 @@ private Message CreateDisconnectMessage(DisconnectReason reason) { case DisconnectReason.MaxConnectionReached: case DisconnectReason.MaxConnectionPerAddressReached: - data = GetRandomConnectedPeers(MinDesiredConnections).ToByteArray(); + data = GetRandomConnectedPeers(10).ToByteArray(); break; default: data = new byte[0]; From eb23c1dfa421b4b2e4c9ecd7c6eba78e6385ec81 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 21 Nov 2019 15:25:10 +0800 Subject: [PATCH 53/84] Process `DisconnectPayload` in `ProtocolHandler` --- neo/Network/P2P/LocalNode.cs | 21 --------------------- neo/Network/P2P/ProtocolHandler.cs | 19 +++++++++++++++++-- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index d4efbe3cf6..86a26c549b 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -200,9 +200,6 @@ protected override void OnReceive(object message) break; case RelayResultReason _: break; - case DisconnectPayload payload: - OnDisconnectPayload(payload); - break; } } @@ -259,24 +256,6 @@ private Message CreateDisconnectMessage(DisconnectReason reason) return Message.Create(MessageCommand.Disconnect, payload); } - private void OnDisconnectPayload(DisconnectPayload payload) - { - switch (payload.Reason) - { - case DisconnectReason.MaxConnectionReached: - case DisconnectReason.MaxConnectionPerAddressReached: - try - { - NetworkAddressWithTime[] addressList = payload.Data.AsSerializableArray(AddrPayload.MaxCountToSend); - AddPeers(addressList.Select(p => p.EndPoint).Where(p => p.Port > 0)); - } - catch { } - break; - default: break; - } - Context.Stop(Sender); - } - public static Props Props(NeoSystem system) { return Akka.Actor.Props.Create(() => new LocalNode(system)); diff --git a/neo/Network/P2P/ProtocolHandler.cs b/neo/Network/P2P/ProtocolHandler.cs index bc9816e039..1d09b3dca7 100644 --- a/neo/Network/P2P/ProtocolHandler.cs +++ b/neo/Network/P2P/ProtocolHandler.cs @@ -8,7 +8,6 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.Plugins; -using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -316,7 +315,23 @@ private void OnVersionMessageReceived(VersionPayload payload) private void OnDisconnectMessageReceived(DisconnectPayload payload) { - system.LocalNode.Tell(payload, Context.Parent); // As the priority of message is lower than Tcp.Close + switch (payload.Reason) + { + case DisconnectReason.MaxConnectionReached: + case DisconnectReason.MaxConnectionPerAddressReached: + try + { + var addressList = payload.Data + .AsSerializableArray(AddrPayload.MaxCountToSend) + .Select(p => p.EndPoint) + .Where(p => p.Port > 0); + system.LocalNode.Tell(new Peer.Peers { EndPoints = addressList }); + } + catch { } + break; + default: break; + } + Context.Stop(Self); } public static Props Props(NeoSystem system) From 39f655922302143da1b582ab9961cf7e2ed49a2f Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 21 Nov 2019 15:52:39 +0800 Subject: [PATCH 54/84] remove useless ut in UT_LocalNode --- neo.UnitTests/Network/P2P/UT_LocalNode.cs | 25 ----------------------- 1 file changed, 25 deletions(-) diff --git a/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 818380fe2c..009b001e4a 100644 --- a/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -210,30 +210,5 @@ public void Test_Peer_MaxConnection_Reached() addrs.Length.Should().Be(1); addrs[0].EndPoint.Port.Should().Be(8991); } - - [TestMethod] - public void Test_Received_MaxConnectionReached_Disconnection() - { - //send MaxConnectionReached disconnection - NetworkAddressWithTime[] addressWithTimes = new NetworkAddressWithTime[] - { - new NetworkAddressWithTime() - { - Timestamp = 0, - Address = IPAddress.Parse("192.167.1.1"), - Capabilities = new NodeCapability[] - { - new ServerCapability(NodeCapabilityType.TcpServer, 8080) - } - } - }; - - var payload = DisconnectPayload.Create(DisconnectReason.MaxConnectionReached, addressWithTimes.ToByteArray()); - var testProbe = CreateTestProbe(); - testProbe.Send(testBlockchain.LocalNode, payload); - - testProbe.ExpectNoMsg(); - LocalNode.Singleton.GetUnconnectedPeers().Any(p => p.Equals(new IPEndPoint(IPAddress.Parse("192.167.1.1"), 8080))).Should().BeTrue(); - } } } From a370743660da4ac1c1c4fce67f68fa64cd10cda2 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Fri, 22 Nov 2019 18:05:53 +0800 Subject: [PATCH 55/84] replace ActorRefs.NoSender by ActorRefs.Nobody --- neo/Network/P2P/LocalNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Network/P2P/LocalNode.cs b/neo/Network/P2P/LocalNode.cs index 86a26c549b..7768b69a12 100644 --- a/neo/Network/P2P/LocalNode.cs +++ b/neo/Network/P2P/LocalNode.cs @@ -225,7 +225,7 @@ protected override void TcpDisconnect(DisconnectReason reason) var disconnectMessage = CreateDisconnectMessage(reason); var command = Tcp.Write.Create(ByteString.FromBytes(disconnectMessage.ToArray())); - Sender.Tell(new Tcp.Register(ActorRefs.NoSender)); + Sender.Tell(new Tcp.Register(ActorRefs.Nobody)); Sender.Ask(command).ContinueWith(t => Sender.Tell(Tcp.Abort.Instance)); } From c4b06e046d9e72c208194e5e759397d8b91e47b2 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Tue, 26 Nov 2019 14:27:39 +0800 Subject: [PATCH 56/84] up UT_localnode --- .../neo.UnitTests/Network/P2P/UT_LocalNode.cs | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 512f3058be..9d16441323 100644 --- a/tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -93,10 +93,19 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() var proble = CreateTestProbe(); proble.Send(localNode, connected); - proble.ExpectMsg(); // register msg is earlier than version msg - var verionMsg = proble.ExpectMsg(); // remote node send version msg + + var tcpMessage = proble.ExpectMsg(); + Tcp.Write verionMsg; + if (tcpMessage is Tcp.Register) + { + verionMsg = proble.ExpectMsg(); // remote node send version msg + } + else // It may lost Tcp.Register sometimes + { + verionMsg = (Tcp.Write)tcpMessage; + } Message version = verionMsg.Data.ToArray().AsSerializable(); - version.Command.Should().Be(MessageCommand.Version); // check version msg + version.Command.Should().Be(MessageCommand.Version); senderDict[remote] = proble; } @@ -160,8 +169,17 @@ public void Test_Peer_MaxConnection_Reached() connected = new Tcp.Connected(remote, local); var proble = CreateTestProbe(); proble.Send(localNode, connected); - proble.ExpectMsg(); // register msg is earlier than version msg - var verionMsg = proble.ExpectMsg(); // remote node send version msg + + var tcpMessage = proble.ExpectMsg(); + Tcp.Write verionMsg; + if (tcpMessage is Tcp.Register) + { + verionMsg = proble.ExpectMsg(); // remote node send version msg + } + else // It may lost Tcp.Register sometimes + { + verionMsg = (Tcp.Write)tcpMessage; + } Message version = verionMsg.Data.ToArray().AsSerializable(); version.Command.Should().Be(MessageCommand.Version); From a4aba3474073b4f24ed724dfc7665cfe4e0a3df2 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Tue, 26 Nov 2019 17:54:05 +0800 Subject: [PATCH 57/84] fix ProtocolHandler.OnDisconnectMessageReceived --- src/neo/Network/P2P/ProtocolHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/ProtocolHandler.cs b/src/neo/Network/P2P/ProtocolHandler.cs index 1d09b3dca7..aaabfa21c0 100644 --- a/src/neo/Network/P2P/ProtocolHandler.cs +++ b/src/neo/Network/P2P/ProtocolHandler.cs @@ -331,7 +331,7 @@ private void OnDisconnectMessageReceived(DisconnectPayload payload) break; default: break; } - Context.Stop(Self); + Context.Stop(Context.Parent); } public static Props Props(NeoSystem system) From a4921631583f59da88b0cbab333d8fc1fd8741e9 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 28 Nov 2019 09:08:25 +0800 Subject: [PATCH 58/84] revert rand --- src/neo/Network/P2P/Peer.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index 1377543ffc..24204d7a19 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -228,8 +228,7 @@ private void OnTimer() if (ConnectedPeers.Count >= MinDesiredConnections) return; if (UnconnectedPeers.Count == 0) NeedMorePeers(MinDesiredConnections - ConnectedPeers.Count); - Random rand = new Random(); - IPEndPoint[] endpoints = UnconnectedPeers.OrderBy(p => rand.Next()).Take(MinDesiredConnections - ConnectedPeers.Count).ToArray(); + IPEndPoint[] endpoints = UnconnectedPeers.Take(MinDesiredConnections - ConnectedPeers.Count).ToArray(); ImmutableInterlocked.Update(ref UnconnectedPeers, p => p.Except(endpoints)); foreach (IPEndPoint endpoint in endpoints) { From f7a1fe29fbf88b2e75b7f85fb758fcea3328daf9 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 28 Nov 2019 09:21:26 +0800 Subject: [PATCH 59/84] add log --- tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 95f85a5246..330c0ee3a8 100644 --- a/tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -96,6 +96,7 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() else // It may lost Tcp.Register sometimes { verionMsg = (Tcp.Write)tcpMessage; + proble.ExpectMsg(); } Message version = verionMsg.Data.ToArray().AsSerializable(); version.Command.Should().Be(MessageCommand.Version); @@ -119,8 +120,8 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() }; var message = Message.Create(MessageCommand.Version, payload); var versionReceived = new Tcp.Received(ByteString.FromBytes(message.ToArray())); - var remoteAddr = LocalNode.Singleton.RemoteNodes.Values.First().Remote; - var remoteNodeActor = LocalNode.Singleton.RemoteNodes.Keys.First(); + var remoteAddr = LocalNode.Singleton.RemoteNodes.Values.Last().Remote; + var remoteNodeActor = LocalNode.Singleton.RemoteNodes.Keys.Last(); var testProbe = senderDict[remoteAddr]; testProbe.Send(remoteNodeActor, versionReceived); testProbe.ExpectMsg(); // remote node will send verack and change its listenerPort @@ -172,6 +173,7 @@ public void Test_Peer_MaxConnection_Reached() else // It may lost Tcp.Register sometimes { verionMsg = (Tcp.Write)tcpMessage; + proble.ExpectMsg(); } Message version = verionMsg.Data.ToArray().AsSerializable(); version.Command.Should().Be(MessageCommand.Version); @@ -194,8 +196,8 @@ public void Test_Peer_MaxConnection_Reached() } }; var versionReceived = new Tcp.Received(ByteString.FromBytes(Message.Create(MessageCommand.Version, payload).ToArray())); - var remoteAddr = LocalNode.Singleton.RemoteNodes.Values.First().Remote; - var remoteNodeActor = LocalNode.Singleton.RemoteNodes.Keys.First(); + var remoteAddr = LocalNode.Singleton.RemoteNodes.Values.Last().Remote; + var remoteNodeActor = LocalNode.Singleton.RemoteNodes.Keys.Last(); var testProbe = senderDict[remoteAddr]; testProbe.Send(remoteNodeActor, versionReceived); From f566864f9a0bf8c9c09be544f8adeb372116da1d Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 28 Nov 2019 09:31:28 +0800 Subject: [PATCH 60/84] add comments --- tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs b/tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs index 330c0ee3a8..4eba078acc 100644 --- a/tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/tests/neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -93,7 +93,7 @@ public void Test_Peer_Max_Per_Address_Connection_Reached() { verionMsg = proble.ExpectMsg(); // remote node send version msg } - else // It may lost Tcp.Register sometimes + else // It may delay Tcp.Register sometimes { verionMsg = (Tcp.Write)tcpMessage; proble.ExpectMsg(); @@ -170,7 +170,7 @@ public void Test_Peer_MaxConnection_Reached() { verionMsg = proble.ExpectMsg(); // remote node send version msg } - else // It may lost Tcp.Register sometimes + else // It may delay Tcp.Register sometimes { verionMsg = (Tcp.Write)tcpMessage; proble.ExpectMsg(); From 28b734953a971f7b1a0d4085eb9f2c05053efd9a Mon Sep 17 00:00:00 2001 From: Luchuan Date: Mon, 2 Dec 2019 10:10:56 +0800 Subject: [PATCH 61/84] replace Context.Stop(Parent) by Context.watch --- src/neo/Network/P2P/ProtocolHandler.cs | 2 +- src/neo/Network/P2P/RemoteNode.cs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/ProtocolHandler.cs b/src/neo/Network/P2P/ProtocolHandler.cs index 66ffea7aef..b30b318bd9 100644 --- a/src/neo/Network/P2P/ProtocolHandler.cs +++ b/src/neo/Network/P2P/ProtocolHandler.cs @@ -331,7 +331,7 @@ private void OnDisconnectMessageReceived(DisconnectPayload payload) break; default: break; } - Context.Stop(Context.Parent); + Context.Stop(Self); } public static Props Props(NeoSystem system) diff --git a/src/neo/Network/P2P/RemoteNode.cs b/src/neo/Network/P2P/RemoteNode.cs index 40b30085db..ec2fc5ceda 100644 --- a/src/neo/Network/P2P/RemoteNode.cs +++ b/src/neo/Network/P2P/RemoteNode.cs @@ -39,6 +39,7 @@ public RemoteNode(NeoSystem system, object connection, IPEndPoint remote, IPEndP { this.system = system; this.protocol = Context.ActorOf(ProtocolHandler.Props(system)); + Context.Watch(this.protocol); LocalNode.Singleton.RemoteNodes.TryAdd(Self, this); var capabilities = new List @@ -152,6 +153,9 @@ protected override void OnReceive(object message) case PingPayload payload: OnPingPayload(payload); break; + case Terminated child: + Context.Stop(Self); + break; } } From 78219617c1144e2a2fe1dad17226f974ffd4a2f8 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Mon, 2 Dec 2019 11:02:23 +0800 Subject: [PATCH 62/84] Fix whitespace formatting --- src/neo/Network/P2P/ProtocolHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/ProtocolHandler.cs b/src/neo/Network/P2P/ProtocolHandler.cs index e5317724e9..fbb0724dc8 100644 --- a/src/neo/Network/P2P/ProtocolHandler.cs +++ b/src/neo/Network/P2P/ProtocolHandler.cs @@ -367,7 +367,7 @@ private void OnDisconnectMessageReceived(DisconnectPayload payload) } Context.Stop(Self); } - + private void OnTimer() { RefreshPendingKnownHashes(); From fe0319ac01cb13e04f109ade6f5cfb7cb93d5d90 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Tue, 3 Dec 2019 16:17:41 +0800 Subject: [PATCH 63/84] optimize code in DisconnectPayload.cs --- src/neo/Network/P2P/Payloads/DisconnectPayload.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/DisconnectPayload.cs b/src/neo/Network/P2P/Payloads/DisconnectPayload.cs index 6657350db4..9c82dfd2ba 100644 --- a/src/neo/Network/P2P/Payloads/DisconnectPayload.cs +++ b/src/neo/Network/P2P/Payloads/DisconnectPayload.cs @@ -1,4 +1,5 @@ using Neo.IO; +using System; using System.IO; namespace Neo.Network.P2P.Payloads @@ -17,7 +18,7 @@ public static DisconnectPayload Create(DisconnectReason reason, byte[] data = nu return new DisconnectPayload { Reason = reason, - Data = data ?? (new byte[0]) + Data = data ?? Array.Empty() }; } From 3e4aee419948d0eaa496bb2fe1b3a637c171ca77 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Tue, 3 Dec 2019 16:35:47 +0800 Subject: [PATCH 64/84] refactor LocalNode & Peer.cs --- src/neo/Network/P2P/LocalNode.cs | 54 ++++++++++++++++++++++++++------ src/neo/Network/P2P/Peer.cs | 42 ++----------------------- 2 files changed, 47 insertions(+), 49 deletions(-) diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index 7768b69a12..7e07aedba5 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Net; using System.Net.Sockets; @@ -220,23 +221,56 @@ private void OnSendDirectly(IInventory inventory) Connections.Tell(inventory); } - protected override void TcpDisconnect(DisconnectReason reason) + protected override void OnTcpConnected(IPEndPoint remote, IPEndPoint local) { - var disconnectMessage = CreateDisconnectMessage(reason); - var command = Tcp.Write.Create(ByteString.FromBytes(disconnectMessage.ToArray())); + ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); + if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) + { + SendTcpDisconnectReason(DisconnectReason.MaxConnectionReached); + return; + } - Sender.Tell(new Tcp.Register(ActorRefs.Nobody)); - Sender.Ask(command).ContinueWith(t => Sender.Tell(Tcp.Abort.Instance)); + ConnectedAddresses.TryGetValue(remote.Address, out int count); + if (count >= MaxConnectionsPerAddress) + { + SendTcpDisconnectReason(DisconnectReason.MaxConnectionPerAddressReached); + } + else + { + ConnectedAddresses[remote.Address] = count + 1; + IActorRef connection = Context.ActorOf(ProtocolProps(Sender, remote, local), $"connection_{Guid.NewGuid()}"); + Context.Watch(connection); + Sender.Tell(new Tcp.Register(connection)); + ConnectedPeers.TryAdd(connection, remote); + } } - protected override void WsDisconnect(WebSocket ws, DisconnectReason reason) + protected override void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) + { + ConnectedAddresses.TryGetValue(remote.Address, out int count); + if (count >= MaxConnectionsPerAddress) + { + var disconnectMessage = CreateDisconnectMessage(DisconnectReason.MaxConnectionPerAddressReached); + ArraySegment segment = new ArraySegment(disconnectMessage.ToArray()); + + ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, + failure: ex => new Tcp.ErrorClosed(ex.Message)); + ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); + } + else + { + ConnectedAddresses[remote.Address] = count + 1; + Context.ActorOf(ProtocolProps(ws, remote, local), $"connection_{Guid.NewGuid()}"); + } + } + + protected void SendTcpDisconnectReason(DisconnectReason reason) { var disconnectMessage = CreateDisconnectMessage(reason); - ArraySegment segment = new ArraySegment(disconnectMessage.ToArray()); + var command = Tcp.Write.Create(ByteString.FromBytes(disconnectMessage.ToArray())); - ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, - failure: ex => new Tcp.ErrorClosed(ex.Message)); - ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); + Sender.Tell(new Tcp.Register(ActorRefs.Nobody)); + Sender.Ask(command).ContinueWith(t => Sender.Tell(Tcp.Abort.Instance)); } private Message CreateDisconnectMessage(DisconnectReason reason) diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index f26372105c..97c5fd3fb1 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -36,7 +36,7 @@ private class WsConnected { public WebSocket Socket; public IPEndPoint Remote; p protected ActorSelection Connections => Context.ActorSelection("connection_*"); protected static readonly HashSet LocalAddresses = new HashSet(); - private readonly Dictionary ConnectedAddresses = new Dictionary(); + protected readonly Dictionary ConnectedAddresses = new Dictionary(); protected readonly ConcurrentDictionary ConnectedPeers = new ConcurrentDictionary(); protected ImmutableHashSet UnconnectedPeers = ImmutableHashSet.Empty; protected ImmutableHashSet ConnectingPeers = ImmutableHashSet.Empty; @@ -175,30 +175,8 @@ private void OnStart(ChannelsConfig config) } } - private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) - { - ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); - if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) - { - TcpDisconnect(DisconnectReason.MaxConnectionReached); - return; - } + protected abstract void OnTcpConnected(IPEndPoint remote, IPEndPoint local); - ConnectedAddresses.TryGetValue(remote.Address, out int count); - if (count >= MaxConnectionsPerAddress) - { - TcpDisconnect(DisconnectReason.MaxConnectionPerAddressReached); - } - else - { - ConnectedAddresses[remote.Address] = count + 1; - IActorRef connection = Context.ActorOf(ProtocolProps(Sender, remote, local), $"connection_{Guid.NewGuid()}"); - Context.Watch(connection); - Sender.Tell(new Tcp.Register(connection)); - ConnectedPeers.TryAdd(connection, remote); - } - } - protected abstract void TcpDisconnect(DisconnectReason reason); private void OnTcpCommandFailed(Tcp.Command cmd) { @@ -236,21 +214,7 @@ private void OnTimer() } } - private void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) - { - ConnectedAddresses.TryGetValue(remote.Address, out int count); - if (count >= MaxConnectionsPerAddress) - { - WsDisconnect(ws, DisconnectReason.MaxConnectionPerAddressReached); - } - else - { - ConnectedAddresses[remote.Address] = count + 1; - Context.ActorOf(ProtocolProps(ws, remote, local), $"connection_{Guid.NewGuid()}"); - } - } - - protected abstract void WsDisconnect(WebSocket ws, DisconnectReason reason); + protected abstract void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local); protected override void PostStop() { From b465fac7bd15c56df5c921dce48b5c9f18a47f56 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 12 Dec 2019 11:43:54 +0800 Subject: [PATCH 65/84] reset --- src/neo/Network/P2P/LocalNode.cs | 45 -------------------------------- src/neo/Network/P2P/Peer.cs | 44 +++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 47 deletions(-) diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index 7e07aedba5..c13132d809 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -6,11 +6,9 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Net; using System.Net.Sockets; -using System.Net.WebSockets; using System.Reflection; using System.Threading; @@ -221,49 +219,6 @@ private void OnSendDirectly(IInventory inventory) Connections.Tell(inventory); } - protected override void OnTcpConnected(IPEndPoint remote, IPEndPoint local) - { - ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); - if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) - { - SendTcpDisconnectReason(DisconnectReason.MaxConnectionReached); - return; - } - - ConnectedAddresses.TryGetValue(remote.Address, out int count); - if (count >= MaxConnectionsPerAddress) - { - SendTcpDisconnectReason(DisconnectReason.MaxConnectionPerAddressReached); - } - else - { - ConnectedAddresses[remote.Address] = count + 1; - IActorRef connection = Context.ActorOf(ProtocolProps(Sender, remote, local), $"connection_{Guid.NewGuid()}"); - Context.Watch(connection); - Sender.Tell(new Tcp.Register(connection)); - ConnectedPeers.TryAdd(connection, remote); - } - } - - protected override void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) - { - ConnectedAddresses.TryGetValue(remote.Address, out int count); - if (count >= MaxConnectionsPerAddress) - { - var disconnectMessage = CreateDisconnectMessage(DisconnectReason.MaxConnectionPerAddressReached); - ArraySegment segment = new ArraySegment(disconnectMessage.ToArray()); - - ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, - failure: ex => new Tcp.ErrorClosed(ex.Message)); - ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); - } - else - { - ConnectedAddresses[remote.Address] = count + 1; - Context.ActorOf(ProtocolProps(ws, remote, local), $"connection_{Guid.NewGuid()}"); - } - } - protected void SendTcpDisconnectReason(DisconnectReason reason) { var disconnectMessage = CreateDisconnectMessage(reason); diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index 97c5fd3fb1..79f4a31928 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -15,6 +15,7 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Net.WebSockets; +using System.Threading; using System.Threading.Tasks; namespace Neo.Network.P2P @@ -175,7 +176,29 @@ private void OnStart(ChannelsConfig config) } } - protected abstract void OnTcpConnected(IPEndPoint remote, IPEndPoint local); + private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) + { + ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); + if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) + { + SendTcpDisconnectReason(DisconnectReason.MaxConnectionReached); + return; + } + + ConnectedAddresses.TryGetValue(remote.Address, out int count); + if (count >= MaxConnectionsPerAddress) + { + SendTcpDisconnectReason(DisconnectReason.MaxConnectionPerAddressReached); + } + else + { + ConnectedAddresses[remote.Address] = count + 1; + IActorRef connection = Context.ActorOf(ProtocolProps(Sender, remote, local), $"connection_{Guid.NewGuid()}"); + Context.Watch(connection); + Sender.Tell(new Tcp.Register(connection)); + ConnectedPeers.TryAdd(connection, remote); + } + } private void OnTcpCommandFailed(Tcp.Command cmd) @@ -214,7 +237,24 @@ private void OnTimer() } } - protected abstract void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local); + private void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) + { + ConnectedAddresses.TryGetValue(remote.Address, out int count); + if (count >= MaxConnectionsPerAddress) + { + var disconnectMessage = CreateDisconnectMessage(DisconnectReason.MaxConnectionPerAddressReached); + ArraySegment segment = new ArraySegment(disconnectMessage.ToArray()); + + ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, + failure: ex => new Tcp.ErrorClosed(ex.Message)); + ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); + } + else + { + ConnectedAddresses[remote.Address] = count + 1; + Context.ActorOf(ProtocolProps(ws, remote, local), $"connection_{Guid.NewGuid()}"); + } + } protected override void PostStop() { From f3e9a9b64b8c0484f1024a2ed9e7725b6377f24b Mon Sep 17 00:00:00 2001 From: Luchuan Date: Mon, 16 Dec 2019 11:14:46 +0800 Subject: [PATCH 66/84] format --- src/neo/Network/P2P/Peer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index 4c8ca0175c..c975371e9c 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -229,7 +229,6 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) protected abstract bool PreTcpConnectedCheck(IPEndPoint remote, IPEndPoint local, out Tcp.Message errorMsg); - /// /// Will be triggered when a Tcp.CommandFailed message is received. /// If it's a Tcp.Connect command, remove the related endpoint from ConnectingPeers. From eacfef58255f1557adfe977022733188f5ccf3ca Mon Sep 17 00:00:00 2001 From: Luchuan Date: Tue, 7 Jan 2020 20:30:23 +0800 Subject: [PATCH 67/84] add more comments --- src/neo/Network/P2P/LocalNode.cs | 29 ++++++++++++++++++++++++++ src/neo/Network/P2P/ProtocolHandler.cs | 4 ++++ src/neo/Network/P2P/RemoteNode.cs | 5 +++++ 3 files changed, 38 insertions(+) diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index 75cf9cf393..7e4bb82c35 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -122,6 +122,13 @@ internal static IPEndPoint GetIpEndPoint(string hostAndPort) return null; } + /// + /// Check duplicated duplicated Nonce. Usually it occurs when a new remote connection is established, which checks its counterpart's Nonce value.
+ /// If Nonce is the same we check if the Remote can be added to the known LocalAddresses.
+ /// If it is equal to the Nonce of other RemoteNode, we just return true, else we'll return false and update the Listener address of the connected remote node. + ///
+ /// Remote node actor + /// Remote node public bool CheckDuplicateNonce(IActorRef remoteActor, RemoteNode remoteNode) { var version = remoteNode.Version; @@ -189,6 +196,11 @@ protected override void NeedMorePeers(int count) } } + /// + /// Get a maximum number of count random peer currently connected with the node. + /// + /// + /// public NetworkAddressWithTime[] GetRandomConnectedPeers(int count) { Random rand = new Random(); @@ -244,6 +256,12 @@ private void OnSendDirectly(IInventory inventory) Connections.Tell(inventory); } + /// + /// TCP connection establishment pre-check includes MaxConnections, MaxConnectionsPerAddress. If the check fails, it'll return false and error messages. + /// + /// + /// + /// protected override bool PreTcpConnectedCheck(IPEndPoint remote, IPEndPoint local, out Tcp.Message errorMsg) { if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) @@ -264,6 +282,13 @@ protected override bool PreTcpConnectedCheck(IPEndPoint remote, IPEndPoint local return true; } + /// + /// Websocket connection establishment pre-check includes MaxConnectionsPerAddress. If the check fails, it'll return false and error messages. + /// + /// + /// + /// + /// protected override bool PreWsConnectedCheck(IPEndPoint remote, IPEndPoint local, out ArraySegment errorMsg) { ConnectedAddresses.TryGetValue(remote.Address, out int count); @@ -277,6 +302,10 @@ protected override bool PreWsConnectedCheck(IPEndPoint remote, IPEndPoint local, return true; } + /// + /// Create disconnect message with reason + /// + /// Disconnect reason private Message CreateDisconnectMessage(DisconnectReason reason) { byte[] data; diff --git a/src/neo/Network/P2P/ProtocolHandler.cs b/src/neo/Network/P2P/ProtocolHandler.cs index 6a951640fc..73e11e1287 100644 --- a/src/neo/Network/P2P/ProtocolHandler.cs +++ b/src/neo/Network/P2P/ProtocolHandler.cs @@ -371,6 +371,10 @@ private void OnVersionMessageReceived(VersionPayload payload) Context.Parent.Tell(payload); } + /// + /// Processe received disconnect messages and close the connection + /// + /// Disconnect message private void OnDisconnectMessageReceived(DisconnectPayload payload) { switch (payload.Reason) diff --git a/src/neo/Network/P2P/RemoteNode.cs b/src/neo/Network/P2P/RemoteNode.cs index ea452cc662..7103fc99d3 100644 --- a/src/neo/Network/P2P/RemoteNode.cs +++ b/src/neo/Network/P2P/RemoteNode.cs @@ -277,6 +277,11 @@ private Message TryParseMessage() return msg; } + /// + /// Send a disconnect message and empty the message queue, waiting for the ack message to arrive and close the connection + /// + /// Disconnet reason + /// Additional data private void DisconnectWithReason(DisconnectReason reason, byte[] data = null) { message_queue_high.Clear(); From bc1135e92da7e3b80ce051982fc96a1423ca028c Mon Sep 17 00:00:00 2001 From: Luchuan Date: Tue, 7 Jan 2020 21:06:13 +0800 Subject: [PATCH 68/84] remove useless line --- src/neo/Network/P2P/LocalNode.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index 57b66dc99a..cb060b387c 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -305,7 +305,6 @@ protected override bool PreTcpConnectedCheck(IPEndPoint remote, IPEndPoint local /// /// /// - /// protected override bool PreWsConnectedCheck(IPEndPoint remote, IPEndPoint local, out ArraySegment errorMsg) { ConnectedAddresses.TryGetValue(remote.Address, out int count); From 3ab6a926fa104ccc285a40034841d2133780fb1c Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 15 Mar 2020 16:57:38 +0800 Subject: [PATCH 69/84] optimize --- src/neo/Network/P2P/LocalNode.cs | 11 ++++++----- src/neo/Network/P2P/RemoteNode.cs | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index cb060b387c..757a3f8f0f 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -23,6 +23,7 @@ internal class SendDirectly { public IInventory Inventory; } public const uint ProtocolVersion = 0; private const int MaxCountFromSeedList = 5; + private const int PeersToReturnOnDisconnect = 10; private readonly IPEndPoint[] SeedList = new IPEndPoint[ProtocolSettings.Default.SeedList.Length]; private static readonly object lockObj = new object(); @@ -142,6 +143,10 @@ public bool CheckDuplicateNonce(IActorRef remoteActor, RemoteNode remoteNode) var version = remoteNode.Version; var remote = remoteNode.Remote; + if (remote is null) + { + return false; + } if (version.Nonce == Nonce) { if (LocalAddresses.Count < MaxConnections) @@ -150,10 +155,6 @@ public bool CheckDuplicateNonce(IActorRef remoteActor, RemoteNode remoteNode) } return true; } - if (remote == null) - { - return false; - } foreach (var pair in RemoteNodes) { var remoteActorRef = pair.Key; @@ -329,7 +330,7 @@ private Message CreateDisconnectMessage(DisconnectReason reason) { case DisconnectReason.MaxConnectionReached: case DisconnectReason.MaxConnectionPerAddressReached: - data = GetRandomConnectedPeers(10).ToByteArray(); + data = GetRandomConnectedPeers(PeersToReturnOnDisconnect).ToByteArray(); break; default: data = new byte[0]; diff --git a/src/neo/Network/P2P/RemoteNode.cs b/src/neo/Network/P2P/RemoteNode.cs index 7103fc99d3..cb08c98fe0 100644 --- a/src/neo/Network/P2P/RemoteNode.cs +++ b/src/neo/Network/P2P/RemoteNode.cs @@ -263,7 +263,7 @@ protected override SupervisorStrategy SupervisorStrategy() { return new OneForOneStrategy(ex => { - DisconnectWithReason(DisconnectReason.InternalError); + Disconnect(true); return Directive.Stop; }, loggingEnabled: false); } From 65d412831712060c54f7d14bb57ec60f031f3222 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 15 Mar 2020 17:10:03 +0800 Subject: [PATCH 70/84] add commments to trigger github action --- src/neo/Network/P2P/LocalNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index 757a3f8f0f..27b1e06f44 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -160,7 +160,7 @@ public bool CheckDuplicateNonce(IActorRef remoteActor, RemoteNode remoteNode) var remoteActorRef = pair.Key; var otherNode = pair.Value; if (otherNode != remoteNode && otherNode.Remote.Address.Equals(remote.Address) && otherNode.Version?.Nonce == version.Nonce) - { + {// filter duplicate connections return true; } } From 8e9ddb30c75fdbdaad459a49102c68089bb77169 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Tue, 24 Mar 2020 16:36:13 +0800 Subject: [PATCH 71/84] Remove empty line --- src/neo/Network/P2P/Peer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index c975371e9c..0a0ff8e1c8 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -41,7 +41,6 @@ private class WsConnected { public WebSocket Socket; public IPEndPoint Remote; p /// /// A dictionary that stores the connected nodes. /// - protected readonly ConcurrentDictionary ConnectedPeers = new ConcurrentDictionary(); /// /// An ImmutableHashSet that stores the Peers received: 1) from other nodes or 2) from default file. From ff7c040babb7abf11258c6b304c4b5c0bcda0c58 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Wed, 25 Mar 2020 14:47:37 +0800 Subject: [PATCH 72/84] remove add localaddress when the same nonce --- src/neo/Network/P2P/LocalNode.cs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index 27b1e06f44..486f51e78d 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -143,21 +143,11 @@ public bool CheckDuplicateNonce(IActorRef remoteActor, RemoteNode remoteNode) var version = remoteNode.Version; var remote = remoteNode.Remote; - if (remote is null) - { - return false; - } - if (version.Nonce == Nonce) - { - if (LocalAddresses.Count < MaxConnections) - { - LocalAddresses.Add(remote.Address); - } - return true; - } + if (remote is null) return false; + if (version.Nonce == Nonce) return true; + foreach (var pair in RemoteNodes) { - var remoteActorRef = pair.Key; var otherNode = pair.Value; if (otherNode != remoteNode && otherNode.Remote.Address.Equals(remote.Address) && otherNode.Version?.Nonce == version.Nonce) {// filter duplicate connections From c1710e103bb9229291b9df110d32690f19ef2e45 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Wed, 25 Mar 2020 15:03:57 +0800 Subject: [PATCH 73/84] private --- src/neo/Network/P2P/Peer.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index 0a0ff8e1c8..b7410d73b3 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -36,7 +36,7 @@ private class WsConnected { public WebSocket Socket; public IPEndPoint Remote; p private ICancelable timer; protected ActorSelection Connections => Context.ActorSelection("connection_*"); - protected static readonly HashSet LocalAddresses = new HashSet(); + private static readonly HashSet localAddresses = new HashSet(); protected readonly Dictionary ConnectedAddresses = new Dictionary(); /// /// A dictionary that stores the connected nodes. @@ -73,7 +73,7 @@ protected virtual int ConnectingMax static Peer() { - LocalAddresses.UnionWith(NetworkInterface.GetAllNetworkInterfaces().SelectMany(p => p.GetIPProperties().UnicastAddresses).Select(p => p.Address.Unmap())); + localAddresses.UnionWith(NetworkInterface.GetAllNetworkInterfaces().SelectMany(p => p.GetIPProperties().UnicastAddresses).Select(p => p.Address.Unmap())); } /// @@ -86,7 +86,7 @@ protected void AddPeers(IEnumerable peers) { // Do not select peers to be added that are already on the ConnectedPeers // If the address is the same, the ListenerTcpPort should be different - peers = peers.Where(p => (p.Port != ListenerTcpPort || !LocalAddresses.Contains(p.Address)) && !ConnectedPeers.Values.Contains(p)); + peers = peers.Where(p => (p.Port != ListenerTcpPort || !localAddresses.Contains(p.Address)) && !ConnectedPeers.Values.Contains(p)); ImmutableInterlocked.Update(ref UnconnectedPeers, p => p.Union(peers)); } } @@ -96,7 +96,7 @@ protected void ConnectToPeer(IPEndPoint endPoint, bool isTrusted = false) endPoint = endPoint.Unmap(); // If the address is the same, the ListenerTcpPort should be different, otherwise, return - if (endPoint.Port == ListenerTcpPort && LocalAddresses.Contains(endPoint.Address)) return; + if (endPoint.Port == ListenerTcpPort && localAddresses.Contains(endPoint.Address)) return; if (isTrusted) TrustedIpAddresses.Add(endPoint.Address); // If connections with the peer greater than or equal to MaxConnectionsPerAddress, return. @@ -170,12 +170,12 @@ private void OnStart(ChannelsConfig config) // schedule time to trigger `OnTimer` event every TimerMillisecondsInterval ms timer = Context.System.Scheduler.ScheduleTellRepeatedlyCancelable(0, 5000, Context.Self, new Timer(), ActorRefs.NoSender); if ((ListenerTcpPort > 0 || ListenerWsPort > 0) - && LocalAddresses.All(p => !p.IsIPv4MappedToIPv6 || IsIntranetAddress(p)) + && localAddresses.All(p => !p.IsIPv4MappedToIPv6 || IsIntranetAddress(p)) && UPnP.Discover()) { try { - LocalAddresses.Add(UPnP.GetExternalIP()); + localAddresses.Add(UPnP.GetExternalIP()); if (ListenerTcpPort > 0) UPnP.ForwardPort(ListenerTcpPort, ProtocolType.Tcp, "NEO Tcp"); if (ListenerWsPort > 0) UPnP.ForwardPort(ListenerWsPort, ProtocolType.Tcp, "NEO WebSocket"); From 2a6aa642b388b50b83b268229b548cd5a823faa1 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Wed, 25 Mar 2020 15:34:43 +0800 Subject: [PATCH 74/84] add OnTcpConnected virutal modifier --- src/neo/Network/P2P/LocalNode.cs | 44 +++++++++++++++----------------- src/neo/Network/P2P/Peer.cs | 23 ++--------------- 2 files changed, 23 insertions(+), 44 deletions(-) diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index 71be38fd4a..5e765a8756 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using System.Net.WebSockets; using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -262,49 +263,46 @@ private void OnRelayDirectly(IInventory inventory) private void OnSendDirectly(IInventory inventory) => SendToRemoteNodes(inventory); - /// - /// TCP connection establishment pre-check includes MaxConnections, MaxConnectionsPerAddress. If the check fails, it'll return false and error messages. - /// - /// - /// - /// - protected override bool PreTcpConnectedCheck(IPEndPoint remote, IPEndPoint local, out Tcp.Message errorMsg) + protected override void OnTcpConnected(IPEndPoint remote, IPEndPoint local) { + // Pre-check includes MaxConnections, MaxConnectionsPerAddress. If the check fails, it'll seed the error message. + Tcp.Message errorMsg = null; if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) { Message reason = CreateDisconnectMessage(DisconnectReason.MaxConnectionReached); errorMsg = Tcp.Write.Create(ByteString.FromBytes(reason.ToArray())); - return false; } - ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { Message reason = CreateDisconnectMessage(DisconnectReason.MaxConnectionPerAddressReached); errorMsg = Tcp.Write.Create(ByteString.FromBytes(reason.ToArray())); - return false; } - errorMsg = null; - return true; + if (errorMsg != null) + { + Sender.Tell(new Tcp.Register(ActorRefs.Nobody)); + Sender.Ask(errorMsg).ContinueWith(t => Sender.Tell(Tcp.Abort.Instance)); + return; + } + + base.OnTcpConnected(remote, local); } - /// - /// Websocket connection establishment pre-check includes MaxConnectionsPerAddress. If the check fails, it'll return false and error messages. - /// - /// - /// - /// - protected override bool PreWsConnectedCheck(IPEndPoint remote, IPEndPoint local, out ArraySegment errorMsg) + protected override void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) { + // Pre-check includes MaxConnectionsPerAddress. If the check fails, it'll send the error message. ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { var disconnectMessage = CreateDisconnectMessage(DisconnectReason.MaxConnectionPerAddressReached); - errorMsg = new ArraySegment(disconnectMessage.ToArray()); - return false; + var errorMsg = new ArraySegment(disconnectMessage.ToArray()); + ws.SendAsync(errorMsg, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, + failure: ex => new Tcp.ErrorClosed(ex.Message)); + ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); + return; } - errorMsg = null; - return true; + + base.OnWsConnected(ws, remote, local); } /// diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index 0a0ff8e1c8..f8e4b5456b 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -208,16 +208,9 @@ private void OnStart(ChannelsConfig config) /// /// The remote endpoint of TCP connection. /// The local endpoint of TCP connection. - private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) + protected virtual void OnTcpConnected(IPEndPoint remote, IPEndPoint local) { ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); - if (!PreTcpConnectedCheck(remote, local, out Tcp.Message errorMsg)) - { - Sender.Tell(new Tcp.Register(ActorRefs.Nobody)); - Sender.Ask(errorMsg).ContinueWith(t => Sender.Tell(Tcp.Abort.Instance)); - return; - } - ConnectedAddresses.TryGetValue(remote.Address, out int count); ConnectedAddresses[remote.Address] = count + 1; IActorRef connection = Context.ActorOf(ProtocolProps(Sender, remote, local), $"connection_{Guid.NewGuid()}"); @@ -226,8 +219,6 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) ConnectedPeers.TryAdd(connection, remote); } - protected abstract bool PreTcpConnectedCheck(IPEndPoint remote, IPEndPoint local, out Tcp.Message errorMsg); - /// /// Will be triggered when a Tcp.CommandFailed message is received. /// If it's a Tcp.Connect command, remove the related endpoint from ConnectingPeers. @@ -272,23 +263,13 @@ private void OnTimer() } } - private void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) + protected virtual void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) { - if (!PreWsConnectedCheck(remote, local, out ArraySegment errorMsg)) - { - ws.SendAsync(errorMsg, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, - failure: ex => new Tcp.ErrorClosed(ex.Message)); - ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); - return; - } - ConnectedAddresses.TryGetValue(remote.Address, out int count); ConnectedAddresses[remote.Address] = count + 1; Context.ActorOf(ProtocolProps(ws, remote, local), $"connection_{Guid.NewGuid()}"); } - protected abstract bool PreWsConnectedCheck(IPEndPoint remote, IPEndPoint local, out ArraySegment errorMsg); - protected override void PostStop() { timer.CancelIfNotNull(); From 05b1cfd26a939d729c324f020e47ae299a890c6d Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 26 Mar 2020 09:48:41 +0800 Subject: [PATCH 75/84] add Disconnect method --- src/neo/Network/P2P/Peer.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index d387435e3c..2bf0beca5f 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -247,6 +247,11 @@ private void OnTerminated(IActorRef actorRef) } } + protected virtual void Disconnect() + { + Sender.Tell(Tcp.Abort.Instance); + } + private void OnTimer() { // Check if the number of desired connections is already enough From a3e2818ec4b118031ccda17edf0c8575366e8d1d Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 26 Mar 2020 14:38:44 +0800 Subject: [PATCH 76/84] refactor Disconnect to TcpDisconnect and WsDisconnect --- src/neo/Network/P2P/LocalNode.cs | 20 +++++++------------- src/neo/Network/P2P/Peer.cs | 30 ++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index 5e765a8756..1c36d1c355 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -266,22 +266,19 @@ private void OnRelayDirectly(IInventory inventory) protected override void OnTcpConnected(IPEndPoint remote, IPEndPoint local) { // Pre-check includes MaxConnections, MaxConnectionsPerAddress. If the check fails, it'll seed the error message. - Tcp.Message errorMsg = null; + Message reason = null; if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) { - Message reason = CreateDisconnectMessage(DisconnectReason.MaxConnectionReached); - errorMsg = Tcp.Write.Create(ByteString.FromBytes(reason.ToArray())); + reason = CreateDisconnectMessage(DisconnectReason.MaxConnectionReached); } ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { - Message reason = CreateDisconnectMessage(DisconnectReason.MaxConnectionPerAddressReached); - errorMsg = Tcp.Write.Create(ByteString.FromBytes(reason.ToArray())); + reason = CreateDisconnectMessage(DisconnectReason.MaxConnectionPerAddressReached); } - if (errorMsg != null) + if (reason != null) { - Sender.Tell(new Tcp.Register(ActorRefs.Nobody)); - Sender.Ask(errorMsg).ContinueWith(t => Sender.Tell(Tcp.Abort.Instance)); + TcpDisconnect(reason.ToArray(), false); return; } @@ -294,11 +291,8 @@ protected override void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoin ConnectedAddresses.TryGetValue(remote.Address, out int count); if (count >= MaxConnectionsPerAddress) { - var disconnectMessage = CreateDisconnectMessage(DisconnectReason.MaxConnectionPerAddressReached); - var errorMsg = new ArraySegment(disconnectMessage.ToArray()); - ws.SendAsync(errorMsg, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, - failure: ex => new Tcp.ErrorClosed(ex.Message)); - ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); + var reason = CreateDisconnectMessage(DisconnectReason.MaxConnectionPerAddressReached); + WsDisconnect(ws, reason.ToArray()); return; } diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index 2bf0beca5f..00c2ace1fc 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -247,9 +247,21 @@ private void OnTerminated(IActorRef actorRef) } } - protected virtual void Disconnect() + protected void TcpDisconnect(byte[] lastMsg = null, bool connected = true) { - Sender.Tell(Tcp.Abort.Instance); + if (!connected && lastMsg != null) + { + Sender.Tell(new Tcp.Register(ActorRefs.Nobody)); + } + + if (lastMsg is null) + { + Sender.Tell(Tcp.Abort.Instance); + } + else + { + Sender.Ask(Tcp.Write.Create(ByteString.FromBytes(lastMsg.ToArray()))).ContinueWith(t => Sender.Tell(Tcp.Abort.Instance)); + } } private void OnTimer() @@ -275,6 +287,20 @@ protected virtual void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint Context.ActorOf(ProtocolProps(ws, remote, local), $"connection_{Guid.NewGuid()}"); } + protected void WsDisconnect(WebSocket ws, byte[] lastMsg = null) + { + if (lastMsg is null) + { + ws.Abort(); + } + else + { + ws.SendAsync(new ArraySegment(lastMsg), WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, + failure: ex => new Tcp.ErrorClosed(ex.Message)); + ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); + } + } + protected override void PostStop() { timer.CancelIfNotNull(); From bd3bf6c1634f699cf6e299888681b078f45ef7bd Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 26 Mar 2020 17:22:17 +0800 Subject: [PATCH 77/84] add virtual TcpDisconnect, WsDisconnect with reason argument --- src/neo/Network/P2P/LocalNode.cs | 38 +++++----------------- src/neo/Network/P2P/Peer.cs | 55 ++++++++++++++++---------------- 2 files changed, 35 insertions(+), 58 deletions(-) diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index 1c36d1c355..6a459a1829 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -263,40 +263,18 @@ private void OnRelayDirectly(IInventory inventory) private void OnSendDirectly(IInventory inventory) => SendToRemoteNodes(inventory); - protected override void OnTcpConnected(IPEndPoint remote, IPEndPoint local) + protected override void TcpDisconnect(DisconnectReason reason) { - // Pre-check includes MaxConnections, MaxConnectionsPerAddress. If the check fails, it'll seed the error message. - Message reason = null; - if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) - { - reason = CreateDisconnectMessage(DisconnectReason.MaxConnectionReached); - } - ConnectedAddresses.TryGetValue(remote.Address, out int count); - if (count >= MaxConnectionsPerAddress) - { - reason = CreateDisconnectMessage(DisconnectReason.MaxConnectionPerAddressReached); - } - if (reason != null) - { - TcpDisconnect(reason.ToArray(), false); - return; - } - - base.OnTcpConnected(remote, local); + var message = CreateDisconnectMessage(reason); + Sender.Ask(Tcp.Write.Create(ByteString.FromBytes(message.ToArray()))).ContinueWith(t => Sender.Tell(Tcp.Abort.Instance)); } - protected override void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) + protected override void WsDisconnect(WebSocket ws, DisconnectReason reason) { - // Pre-check includes MaxConnectionsPerAddress. If the check fails, it'll send the error message. - ConnectedAddresses.TryGetValue(remote.Address, out int count); - if (count >= MaxConnectionsPerAddress) - { - var reason = CreateDisconnectMessage(DisconnectReason.MaxConnectionPerAddressReached); - WsDisconnect(ws, reason.ToArray()); - return; - } - - base.OnWsConnected(ws, remote, local); + var message = CreateDisconnectMessage(reason); + ws.SendAsync(new ArraySegment(message.ToArray()), WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, + failure: ex => new Tcp.ErrorClosed(ex.Message)); + ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); } /// diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index 00c2ace1fc..a2860f3566 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -208,10 +208,24 @@ private void OnStart(ChannelsConfig config) /// /// The remote endpoint of TCP connection. /// The local endpoint of TCP connection. - protected virtual void OnTcpConnected(IPEndPoint remote, IPEndPoint local) + private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) { - ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); + // Pre-check includes MaxConnections, MaxConnectionsPerAddress. If the check fails, it'll seed the error message. + if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) + { + Sender.Tell(new Tcp.Register(ActorRefs.Nobody)); + TcpDisconnect(DisconnectReason.MaxConnectionReached); + return; + } ConnectedAddresses.TryGetValue(remote.Address, out int count); + if (count >= MaxConnectionsPerAddress) + { + Sender.Tell(new Tcp.Register(ActorRefs.Nobody)); + TcpDisconnect(DisconnectReason.MaxConnectionPerAddressReached); + return; + } + + ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); ConnectedAddresses[remote.Address] = count + 1; IActorRef connection = Context.ActorOf(ProtocolProps(Sender, remote, local), $"connection_{Guid.NewGuid()}"); Context.Watch(connection); @@ -247,21 +261,9 @@ private void OnTerminated(IActorRef actorRef) } } - protected void TcpDisconnect(byte[] lastMsg = null, bool connected = true) + protected virtual void TcpDisconnect(DisconnectReason reason) { - if (!connected && lastMsg != null) - { - Sender.Tell(new Tcp.Register(ActorRefs.Nobody)); - } - - if (lastMsg is null) - { - Sender.Tell(Tcp.Abort.Instance); - } - else - { - Sender.Ask(Tcp.Write.Create(ByteString.FromBytes(lastMsg.ToArray()))).ContinueWith(t => Sender.Tell(Tcp.Abort.Instance)); - } + Sender.Tell(Tcp.Abort.Instance); } private void OnTimer() @@ -280,25 +282,22 @@ private void OnTimer() } } - protected virtual void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) + private void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) { ConnectedAddresses.TryGetValue(remote.Address, out int count); + if (count >= MaxConnectionsPerAddress) + { + WsDisconnect(ws, DisconnectReason.MaxConnectionPerAddressReached); + return; + } + ConnectedAddresses[remote.Address] = count + 1; Context.ActorOf(ProtocolProps(ws, remote, local), $"connection_{Guid.NewGuid()}"); } - protected void WsDisconnect(WebSocket ws, byte[] lastMsg = null) + protected virtual void WsDisconnect(WebSocket ws, DisconnectReason reason) { - if (lastMsg is null) - { - ws.Abort(); - } - else - { - ws.SendAsync(new ArraySegment(lastMsg), WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, - failure: ex => new Tcp.ErrorClosed(ex.Message)); - ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "close ws", CancellationToken.None); - } + ws.Abort(); } protected override void PostStop() From fa5ce65e371a3506b1610cfeb4f00f3b30225779 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 26 Mar 2020 17:34:06 +0800 Subject: [PATCH 78/84] add comments to trigger github action, skip UT_ProtocolSettings fail --- src/neo/Network/P2P/LocalNode.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index 6a459a1829..c0463b3d23 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -263,6 +263,10 @@ private void OnRelayDirectly(IInventory inventory) private void OnSendDirectly(IInventory inventory) => SendToRemoteNodes(inventory); + /// + /// Disconnect tcp connection with reason message + /// + /// protected override void TcpDisconnect(DisconnectReason reason) { var message = CreateDisconnectMessage(reason); @@ -278,7 +282,7 @@ protected override void WsDisconnect(WebSocket ws, DisconnectReason reason) } /// - /// Create disconnect message with reason + /// Create disconnect message with reason and attached with connected peers' addresses. /// /// Disconnect reason private Message CreateDisconnectMessage(DisconnectReason reason) From 07934f65faa4848e1e0120b78fee7173fd242e1d Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 27 Mar 2020 14:20:24 +0800 Subject: [PATCH 79/84] private --- src/neo/Network/P2P/Peer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index a2860f3566..acd03df221 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -37,7 +37,7 @@ private class WsConnected { public WebSocket Socket; public IPEndPoint Remote; p protected ActorSelection Connections => Context.ActorSelection("connection_*"); private static readonly HashSet localAddresses = new HashSet(); - protected readonly Dictionary ConnectedAddresses = new Dictionary(); + private readonly Dictionary ConnectedAddresses = new Dictionary(); /// /// A dictionary that stores the connected nodes. /// From 55e654fc3410043b7c71773ab39874b032134fb6 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Fri, 27 Mar 2020 14:30:24 +0800 Subject: [PATCH 80/84] reset remove peers from ConnectingPeers --- src/neo/Network/P2P/Peer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index a2860f3566..1eba7b99cf 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -210,6 +210,8 @@ private void OnStart(ChannelsConfig config) /// The local endpoint of TCP connection. private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) { + ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); + // Pre-check includes MaxConnections, MaxConnectionsPerAddress. If the check fails, it'll seed the error message. if (MaxConnections != -1 && ConnectedPeers.Count >= MaxConnections && !TrustedIpAddresses.Contains(remote.Address)) { @@ -224,8 +226,7 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) TcpDisconnect(DisconnectReason.MaxConnectionPerAddressReached); return; } - - ImmutableInterlocked.Update(ref ConnectingPeers, p => p.Remove(remote)); + ConnectedAddresses[remote.Address] = count + 1; IActorRef connection = Context.ActorOf(ProtocolProps(Sender, remote, local), $"connection_{Guid.NewGuid()}"); Context.Watch(connection); From 04ea624939600800c55d7048ca5c97b37f761695 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Fri, 27 Mar 2020 14:33:48 +0800 Subject: [PATCH 81/84] foramt --- src/neo/Network/P2P/Peer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index 4320c3c07a..6433919634 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -226,7 +226,7 @@ private void OnTcpConnected(IPEndPoint remote, IPEndPoint local) TcpDisconnect(DisconnectReason.MaxConnectionPerAddressReached); return; } - + ConnectedAddresses[remote.Address] = count + 1; IActorRef connection = Context.ActorOf(ProtocolProps(Sender, remote, local), $"connection_{Guid.NewGuid()}"); Context.Watch(connection); From b56613b30877c2c2b9142cd5a86942adb2d69310 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Tue, 14 Apr 2020 11:33:44 +0800 Subject: [PATCH 82/84] format --- src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index 55542e46b4..e3eef1eb5d 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -338,7 +338,6 @@ private void OnVerackMessageReceived() private void OnVersionMessageReceived(VersionPayload payload) { - Version = payload; foreach (NodeCapability capability in payload.Capabilities) { From 615fcda6f25e7650b24163df0757b06a4330aaaa Mon Sep 17 00:00:00 2001 From: Luchuan Date: Tue, 14 Apr 2020 11:36:39 +0800 Subject: [PATCH 83/84] format --- src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index e3eef1eb5d..e7eb4f05a1 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -337,7 +337,7 @@ private void OnVerackMessageReceived() } private void OnVersionMessageReceived(VersionPayload payload) - { + { Version = payload; foreach (NodeCapability capability in payload.Capabilities) { From 626bc8c1d36a0cb9b8aae4696068a92c55e7f0eb Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Fri, 5 Jun 2020 13:58:16 +0800 Subject: [PATCH 84/84] remove CheckDuplicateNonce --- src/neo/Network/P2P/LocalNode.cs | 31 ------------------- .../Network/P2P/RemoteNode.ProtocolHandler.cs | 2 +- 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index 32e92efc9a..aadc21531c 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -130,37 +130,6 @@ internal static IPEndPoint GetIpEndPoint(string hostAndPort) return null; } - /// - /// Check duplicated duplicated Nonce. Usually it occurs when a new remote connection is established, which checks its counterpart's Nonce value.
- /// If Nonce is the same we check if the Remote can be added to the known LocalAddresses.
- /// If it is equal to the Nonce of other RemoteNode, we just return true, else we'll return false and update the Listener address of the connected remote node. - ///
- /// Remote node actor - /// Remote node - public bool CheckDuplicateNonce(IActorRef remoteActor, RemoteNode remoteNode) - { - var version = remoteNode.Version; - var remote = remoteNode.Remote; - - if (remote is null) return false; - if (version.Nonce == Nonce) return true; - - foreach (var pair in RemoteNodes) - { - var otherNode = pair.Value; - if (otherNode != remoteNode && otherNode.Remote.Address.Equals(remote.Address) && otherNode.Version?.Nonce == version.Nonce) - {// filter duplicate connections - return true; - } - } - if (remote.Port != remoteNode.ListenerTcpPort && remoteNode.ListenerTcpPort != 0) - { - ConnectedPeers.TryUpdate(remoteActor, remoteNode.Listener, remote); - } - - return false; - } - public IEnumerable GetRemoteNodes() { return RemoteNodes.Values; diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index 384dcc0ac5..63b3bc9b6a 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -361,7 +361,7 @@ private void OnVersionMessageReceived(VersionPayload payload) DisconnectWithReason(DisconnectReason.MagicNumberIncompatible, BitConverter.GetBytes(ProtocolSettings.Default.Magic)); return; } - if (LocalNode.Singleton.CheckDuplicateNonce(Self, this)) + if (LocalNode.Singleton.RemoteNodes.Values.Where(p => p != this).Any(p => p.Remote.Address.Equals(Remote.Address) && p.Version?.Nonce == payload.Nonce)) { DisconnectWithReason(DisconnectReason.DuplicateNonce); return;