Skip to content

Commit

Permalink
Merge pull request #3997 from greymistcube/refactor/messagerequest
Browse files Browse the repository at this point in the history
Refactor `MessageRequest` and `IMessageCodec`
  • Loading branch information
greymistcube authored Nov 25, 2024
2 parents 41e0c51 + 4238acb commit 71b6280
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 127 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ To be released.

### Backward-incompatible API changes

- Changed `IMessageCodec.Encode(MessageContent, PrivateKey,
AppProtocolVersion, BoundPeer, DateTimeOffset, byte[]?)` to
`IMessageCodec.Encode(Message, PrivateKey)`. [[#3997]]

### Backward-incompatible network protocol changes

### Backward-incompatible storage format changes
Expand All @@ -24,6 +28,8 @@ To be released.

### CLI tools

[#3997]: https://github.com/planetarium/libplanet/pull/3997


Version 5.4.0
-------------
Expand Down
25 changes: 5 additions & 20 deletions src/Libplanet.Net/Messages/IMessageCodec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,17 @@ public interface IMessageCodec<T>
{
/// <summary>
/// Encodes the message to <see typeref="T"/>-typed instance with given
/// <paramref name="privateKey"/> and <paramref name="peer"/>.
/// <paramref name="privateKey"/> for signing.
/// </summary>
/// <param name="content">The message body to encode.</param>
/// <param name="message">The message to encode.</param>
/// <param name="privateKey">The <see cref="PrivateKey"/> to sign the encoded message.
/// </param>
/// <param name="appProtocolVersion">The <see cref="AppProtocolVersion"/> of
/// the transport layer.</param>
/// <param name="peer">The <see cref="BoundPeer"/>-typed representation of
/// the transport layer.
/// <seealso cref="ITransport.AsPeer"/></param>
/// <param name="timestamp">The <see cref="DateTimeOffset"/> of the time
/// <paramref name="content"/> is encoded.
/// </param>
/// <param name="identity">The byte array identifies the message to match between
/// message and its respond used in <see cref="NetMQ"/>.</param>
/// <returns>A <see typeref="T"/> containing the signed <see cref="MessageContent"/>.
/// </returns>
/// <exception cref="InvalidCredentialException">Thrown when <paramref name="privateKey"/>'s
/// <see cref="PublicKey"/> does not match that of <paramref name="peer"/>.</exception>
T Encode(
MessageContent content,
PrivateKey privateKey,
AppProtocolVersion appProtocolVersion,
BoundPeer peer,
DateTimeOffset timestamp,
byte[]? identity);
/// <see cref="PublicKey"/> does not match that of <paramref name="message.Remote"/>.
/// </exception>
T Encode(Message message, PrivateKey privateKey);

/// <summary>
/// Decodes given <see typeref="T"/>-typed <paramref name="encoded"/> into
Expand Down
52 changes: 15 additions & 37 deletions src/Libplanet.Net/Messages/NetMQMessageCodec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ public class NetMQMessageCodec : IMessageCodec<NetMQMessage>
public static readonly int CommonFrames =
Enum.GetValues(typeof(MessageFrame)).Length;

private const string TimestampFormat = "yyyy-MM-ddTHH:mm:ss.ffffffZ";

private readonly Codec _codec;

/// <summary>
Expand Down Expand Up @@ -53,70 +51,50 @@ public enum MessageFrame
Sign = 4,
}

/// <inheritdoc/>
/// <inheritdoc cref="IMessageCodec{T}.Encode"/>
public NetMQMessage Encode(
MessageContent content,
PrivateKey privateKey,
AppProtocolVersion appProtocolVersion,
BoundPeer peer,
DateTimeOffset timestamp,
byte[]? identity = null)
Message message,
PrivateKey privateKey)
{
if (!privateKey.PublicKey.Equals(peer.PublicKey))
if (!privateKey.PublicKey.Equals(message.Remote.PublicKey))
{
throw new InvalidCredentialException(
$"An invalid private key was provided: " +
$"the provided private key's expected public key is {peer.PublicKey} " +
$"An invalid private key was provided: the provided private key's " +
$"expected public key is {message.Remote.PublicKey} " +
$"but its actual public key is {privateKey.PublicKey}.",
peer.PublicKey,
message.Remote.PublicKey,
privateKey.PublicKey);
}

var netMqMessage = new NetMQMessage();

// Write body (by concrete class)
foreach (byte[] frame in content.DataFrames)
foreach (byte[] frame in message.Content.DataFrames)
{
netMqMessage.Append(frame);
}

// Write headers. (inverse order, version-type-peer-timestamp)
netMqMessage.Push(timestamp.Ticks);
netMqMessage.Push(_codec.Encode(peer.Bencoded));
netMqMessage.Push((int)content.Type);
netMqMessage.Push(appProtocolVersion.Token);
netMqMessage.Push(message.Timestamp.Ticks);
netMqMessage.Push(_codec.Encode(message.Remote.Bencoded));
netMqMessage.Push((int)message.Content.Type);
netMqMessage.Push(message.Version.Token);

// Make and insert signature
byte[] signature = privateKey.Sign(netMqMessage.ToByteArray());
List<NetMQFrame> frames = netMqMessage.ToList();
frames.Insert((int)MessageFrame.Sign, new NetMQFrame(signature));
netMqMessage = new NetMQMessage(frames);

if (identity != null)
if (message.Identity is { })
{
netMqMessage.Push(identity);
netMqMessage.Push(message.Identity);
}

return netMqMessage;
}

/// <summary>
/// Parses a <see cref="MessageContent.MessageType"/> from given <see cref="NetMQMessage"/>.
/// </summary>
/// <param name="encoded">A encoded <see cref="NetMQMessage"/>.</param>
/// <param name="reply">A flag to express whether the target is a reply of other message.
/// </param>
/// <exception cref="IndexOutOfRangeException">Thrown if given <see cref="NetMQMessage"/>
/// has not enough <see cref="NetMQFrame"/> for parsing a message type.</exception>
/// <returns>Returns a <see cref="MessageContent.MessageType"/> of given
/// <paramref name="encoded"/>. If given value cannot be
/// interpreted in <see cref="MessageContent.MessageType"/>,
/// this would return a integer number.</returns>
public MessageContent.MessageType ParseMessageType(NetMQMessage encoded, bool reply)
=> (MessageContent.MessageType)encoded[(int)MessageFrame.Type + (reply ? 0 : 1)]
.ConvertToInt32();

/// <inheritdoc/>
/// <inheritdoc cref="IMessageCodec{T}.Decode"/>
public Message Decode(NetMQMessage encoded, bool reply)
{
if (encoded.FrameCount == 0)
Expand Down
12 changes: 7 additions & 5 deletions src/Libplanet.Net/Transports/BoundPeerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ public static AppProtocolVersion QueryAppProtocolVersionNetMQ(
var ping = new PingMsg();
var netMQMessageCodec = new NetMQMessageCodec();
NetMQMessage request = netMQMessageCodec.Encode(
ping,
privateKey,
default,
new BoundPeer(privateKey.PublicKey, new DnsEndPoint("0.0.0.0", 0)),
DateTimeOffset.UtcNow);
new Message(
ping,
default,
new BoundPeer(privateKey.PublicKey, new DnsEndPoint("0.0.0.0", 0)),
DateTimeOffset.UtcNow,
null),
privateKey);

TimeSpan timeoutNotNull = timeout ?? TimeSpan.FromSeconds(5);
try
Expand Down
Loading

0 comments on commit 71b6280

Please sign in to comment.