Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable compression by p2p #3655

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Neo.CLI/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,15 @@ public StorageSettings() { }
public class P2PSettings
{
public ushort Port { get; }
public bool EnableCompression { get; }
public int MinDesiredConnections { get; }
public int MaxConnections { get; }
public int MaxConnectionsPerAddress { get; }

public P2PSettings(IConfigurationSection section)
{
Port = section.GetValue<ushort>(nameof(Port), 10333);
EnableCompression = section.GetValue(nameof(EnableCompression), Peer.DefaultEnableCompression);
MinDesiredConnections = section.GetValue(nameof(MinDesiredConnections), Peer.DefaultMinDesiredConnections);
MaxConnections = section.GetValue(nameof(MaxConnections), Peer.DefaultMaxConnections);
MaxConnectionsPerAddress = section.GetValue(nameof(MaxConnectionsPerAddress), 3);
Expand Down
1 change: 1 addition & 0 deletions src/Neo.CLI/config.fs.mainnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"P2P": {
"Port": 40333,
"EnableCompression": true,
"MinDesiredConnections": 10,
"MaxConnections": 40,
"MaxConnectionsPerAddress": 3
Expand Down
1 change: 1 addition & 0 deletions src/Neo.CLI/config.fs.testnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"P2P": {
"Port": 50333,
"EnableCompression": true,
"MinDesiredConnections": 10,
"MaxConnections": 40,
"MaxConnectionsPerAddress": 3
Expand Down
1 change: 1 addition & 0 deletions src/Neo.CLI/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"P2P": {
"Port": 10333,
"EnableCompression": true,
"MinDesiredConnections": 10,
"MaxConnections": 40,
"MaxConnectionsPerAddress": 3
Expand Down
1 change: 1 addition & 0 deletions src/Neo.CLI/config.mainnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"P2P": {
"Port": 10333,
"EnableCompression": true,
"MinDesiredConnections": 10,
"MaxConnections": 40,
"MaxConnectionsPerAddress": 3
Expand Down
1 change: 1 addition & 0 deletions src/Neo.CLI/config.testnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"P2P": {
"Port": 20333,
"EnableCompression": true,
"MinDesiredConnections": 10,
"MaxConnections": 40,
"MaxConnectionsPerAddress": 3
Expand Down
44 changes: 44 additions & 0 deletions src/Neo/Network/P2P/Capabilities/DisableCompressionCapability.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (C) 2015-2024 The Neo Project.
//
// DisableCompressionCapability.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Neo.IO;
using System;
using System.IO;

namespace Neo.Network.P2P.Capabilities
{
/// <summary>
/// This capability disable the compression p2p mechanism.
/// </summary>
public class DisableCompressionCapability : NodeCapability
{
public override int Size =>
base.Size + // Type
1; // Zero (empty VarBytes or String)

/// <summary>
/// Initializes a new instance of the <see cref="DisableCompressionCapability"/> class.
/// </summary>
public DisableCompressionCapability() : base(NodeCapabilityType.DisableCompression) { }

protected override void DeserializeWithoutType(ref MemoryReader reader)
{
var zero = reader.ReadByte(); // Zero-length byte array or string (see UnknownCapability).
if (zero != 0)
throw new FormatException("DisableCompression has some data");
}

protected override void SerializeWithoutType(BinaryWriter writer)
{
writer.Write((byte)0);
}
}
}
5 changes: 5 additions & 0 deletions src/Neo/Network/P2P/Capabilities/NodeCapabilityType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public enum NodeCapabilityType : byte
[Obsolete]
WsServer = 0x02,

/// <summary>
/// Disable p2p compression
/// </summary>
DisableCompression = 0x03,

#endregion

#region Data availability
Expand Down
5 changes: 5 additions & 0 deletions src/Neo/Network/P2P/ChannelsConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public class ChannelsConfig
/// </summary>
public IPEndPoint Tcp { get; set; }

/// <summary>
/// Enable compression.
/// </summary>
public bool EnableCompression { get; set; } = Peer.DefaultEnableCompression;

/// <summary>
/// Minimum desired connections.
/// </summary>
Expand Down
67 changes: 54 additions & 13 deletions src/Neo/Network/P2P/Message.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,35 +47,54 @@ public class Message : ISerializable
/// </summary>
public ISerializable Payload;

private ReadOnlyMemory<byte> _payload_compressed;
private ReadOnlyMemory<byte>
_payload_raw,
_payload_compressed;

/// <summary>
/// True if the message is compressed
/// </summary>
public bool IsCompressed => Flags.HasFlag(MessageFlags.Compressed);

public int Size => sizeof(MessageFlags) + sizeof(MessageCommand) + _payload_compressed.GetVarSize();

/// <summary>
/// True if the message should be compressed
/// </summary>
/// <param name="command">Command</param>
/// <returns>True if allow the compression</returns>
private static bool ShallICompress(MessageCommand command)
{
return
command == MessageCommand.Block ||
command == MessageCommand.Extensible ||
command == MessageCommand.Transaction ||
command == MessageCommand.Headers ||
command == MessageCommand.Addr ||
command == MessageCommand.MerkleBlock ||
command == MessageCommand.FilterLoad ||
command == MessageCommand.FilterAdd;
}

/// <summary>
/// Creates a new instance of the <see cref="Message"/> class.
/// </summary>
/// <param name="command">The command of the message.</param>
/// <param name="payload">The payload of the message. For the messages that don't require a payload, it should be <see langword="null"/>.</param>
/// <returns></returns>
/// <returns><see cref="Message"/></returns>
public static Message Create(MessageCommand command, ISerializable payload = null)
{
var tryCompression = ShallICompress(command);

Message message = new()
{
Flags = MessageFlags.None,
Command = command,
Payload = payload,
_payload_compressed = payload?.ToArray() ?? Array.Empty<byte>()
_payload_raw = payload?.ToArray() ?? Array.Empty<byte>()
};

bool tryCompression =
command == MessageCommand.Block ||
command == MessageCommand.Extensible ||
command == MessageCommand.Transaction ||
command == MessageCommand.Headers ||
command == MessageCommand.Addr ||
command == MessageCommand.MerkleBlock ||
command == MessageCommand.FilterLoad ||
command == MessageCommand.FilterAdd;
message._payload_compressed = message._payload_raw;

// Try compression
if (tryCompression && message._payload_compressed.Length > CompressionMinSize)
Expand All @@ -94,7 +113,7 @@ public static Message Create(MessageCommand command, ISerializable payload = nul
private void DecompressPayload()
{
if (_payload_compressed.Length == 0) return;
ReadOnlyMemory<byte> decompressed = Flags.HasFlag(MessageFlags.Compressed)
var decompressed = Flags.HasFlag(MessageFlags.Compressed)
? _payload_compressed.Span.DecompressLz4(PayloadMaxSize)
: _payload_compressed;
Payload = ReflectionCache<MessageCommand>.CreateSerializable(Command, decompressed);
Expand All @@ -115,6 +134,28 @@ void ISerializable.Serialize(BinaryWriter writer)
writer.WriteVarBytes(_payload_compressed.Span);
}

public byte[] ToArray(bool enablecompression)
{
if (enablecompression || !IsCompressed)
{
return this.ToArray();
}
else
{
// Avoid compression

using MemoryStream ms = new();
using BinaryWriter writer = new(ms, Utility.StrictUTF8, true);

writer.Write((byte)(Flags & ~MessageFlags.Compressed));
writer.Write((byte)Command);
writer.WriteVarBytes(_payload_raw.Span);

writer.Flush();
return ms.ToArray();
}
}

internal static int TryDeserialize(ByteString data, out Message msg)
{
msg = null;
Expand Down
13 changes: 12 additions & 1 deletion src/Neo/Network/P2P/Payloads/VersionPayload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ public class VersionPayload : ISerializable
/// </summary>
public string UserAgent;

/// <summary>
/// True if allow compression
/// </summary>
public bool AllowCompression;

/// <summary>
/// The capabilities of the node.
/// </summary>
Expand All @@ -76,15 +81,19 @@ public class VersionPayload : ISerializable
/// <returns></returns>
public static VersionPayload Create(uint network, uint nonce, string userAgent, params NodeCapability[] capabilities)
{
return new VersionPayload
var ret = new VersionPayload
{
Network = network,
Version = LocalNode.ProtocolVersion,
Timestamp = DateTime.Now.ToTimestamp(),
Nonce = nonce,
UserAgent = userAgent,
Capabilities = capabilities,
// Computed
AllowCompression = !capabilities.Any(u => u is DisableCompressionCapability)
};

return ret;
}

void ISerializable.Deserialize(ref MemoryReader reader)
Expand All @@ -102,6 +111,8 @@ void ISerializable.Deserialize(ref MemoryReader reader)
var capabilities = Capabilities.Where(c => c is not UnknownCapability);
if (capabilities.Select(p => p.Type).Distinct().Count() != capabilities.Count())
throw new FormatException();

AllowCompression = !capabilities.Any(u => u is DisableCompressionCapability);
}

void ISerializable.Serialize(BinaryWriter writer)
Expand Down
12 changes: 11 additions & 1 deletion src/Neo/Network/P2P/Peer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ public class Connect

private class Timer { }

/// <summary>
/// The default value for enable compression.
/// </summary>
public const bool DefaultEnableCompression = true;

/// <summary>
/// The default minimum number of desired connections.
/// </summary>
Expand Down Expand Up @@ -113,6 +118,11 @@ private class Timer { }
/// </summary>
public int MinDesiredConnections { get; private set; } = DefaultMinDesiredConnections;

/// <summary>
/// Indicates if the compression is enabled.
/// </summary>
public bool EnableCompression { get; private set; } = DefaultEnableCompression;

/// <summary>
/// Indicates the maximum number of connections.
/// </summary>
Expand Down Expand Up @@ -228,7 +238,7 @@ protected override void OnReceive(object message)
private void OnStart(ChannelsConfig config)
{
ListenerTcpPort = config.Tcp?.Port ?? 0;

EnableCompression = config.EnableCompression;
MinDesiredConnections = config.MinDesiredConnections;
MaxConnections = config.MaxConnections;
MaxConnectionsPerAddress = config.MaxConnectionsPerAddress;
Expand Down
9 changes: 7 additions & 2 deletions src/Neo/Network/P2P/RemoteNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,14 @@ private void OnStartProtocol()
new FullNodeCapability(NativeContract.Ledger.CurrentIndex(system.StoreView))
};

if (!localNode.EnableCompression)
{
capabilities.Add(new DisableCompressionCapability());
roman-khimov marked this conversation as resolved.
Show resolved Hide resolved
}

if (localNode.ListenerTcpPort > 0) capabilities.Add(new ServerCapability(NodeCapabilityType.TcpServer, (ushort)localNode.ListenerTcpPort));

SendMessage(Message.Create(MessageCommand.Version, VersionPayload.Create(system.Settings.Network, LocalNode.Nonce, LocalNode.UserAgent, capabilities.ToArray())));
SendMessage(Message.Create(MessageCommand.Version, VersionPayload.Create(system.Settings.Network, LocalNode.Nonce, LocalNode.UserAgent, [.. capabilities])));
}

protected override void PostStop()
Expand All @@ -229,7 +234,7 @@ internal static Props Props(NeoSystem system, LocalNode localNode, object connec
private void SendMessage(Message message)
{
ack = false;
SendData(ByteString.FromBytes(message.ToArray()));
SendData(ByteString.FromBytes(message.ToArray(Version.AllowCompression)));
sentCommands[(byte)message.Command] = true;
}

Expand Down
Loading