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

Add lifespan to messages #1171

Merged
merged 9 commits into from
Jan 29, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ To be released.
- Removed `trustedStateValidators` parameter from `Swarm<T>.PreloadAsync()`
method. [[#1117]]
- Added `IActionContext.BlockAction` property. [[#1143]]
- Added nullable `TimeSpan`-typed `messageLifespan` parameter into
`NetMQTransport()` constructor. [[#1171]]


### Backward-incompatible network protocol changes

Expand All @@ -49,6 +52,9 @@ To be released.
- `RecentStates` message type (with the type number `0x13`)
- `GetBlockStates` message type (with the type number `0x22`)
- `BlockStates` message type (with the type number `0x23`)
- `Swarm<T>` became to ignore messages made earlier than a certain amount of
time, which is configured by `SwarmOptions.MessageLifespan`.
[[#1160], [#1171]]

### Backward-incompatible storage format changes

Expand Down Expand Up @@ -119,6 +125,8 @@ To be released.
- Added `InvalidBlockPreEvaluationHashException` class. [[#1148]]
- Added the parameter `validate` which is `true` by default,
to `Transaction<T>.Deserialize()`. [[#1149]]
- Added `SwarmOptions.MessageLifespan` property. [[#1171]]
- Added `InvalidTimestampException` class. [[#1171]]

### Behavioral changes

Expand Down Expand Up @@ -211,11 +219,13 @@ To be released.
[#1149]: https://github.com/planetarium/libplanet/pull/1149
[#1152]: https://github.com/planetarium/libplanet/pull/1152
[#1155]: https://github.com/planetarium/libplanet/issues/1155
[#1160]: https://github.com/planetarium/libplanet/issues/1160
[#1162]: https://github.com/planetarium/libplanet/pull/1162
[#1163]: https://github.com/planetarium/libplanet/pull/1163
[#1165]: https://github.com/planetarium/libplanet/pull/1165
[#1168]: https://github.com/planetarium/libplanet/pull/1168
[#1170]: https://github.com/planetarium/libplanet/pull/1170
[#1171]: https://github.com/planetarium/libplanet/pull/1171
[#1172]: https://github.com/planetarium/libplanet/pull/1172


Expand Down
5 changes: 3 additions & 2 deletions Libplanet.Tests/Net/Messages/BlockHashesTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ public void DataFrames()
var privKey = new PrivateKey();
AppProtocolVersion ver = AppProtocolVersion.Sign(privKey, 3);
Peer peer = new BoundPeer(privKey.PublicKey, new DnsEndPoint("0.0.0.0", 1234));
NetMQFrame[] frames =
msg.ToNetMQMessage(privKey, peer, ver).Skip(Message.CommonFrames).ToArray();
NetMQFrame[] frames = msg.ToNetMQMessage(privKey, peer, DateTimeOffset.UtcNow, ver)
.Skip(Message.CommonFrames)
.ToArray();
var restored = new BlockHashes(frames);
Assert.Equal(msg.StartIndex, restored.StartIndex);
Assert.Equal(msg.Hashes, restored.Hashes);
Expand Down
66 changes: 65 additions & 1 deletion Libplanet.Tests/Net/Messages/MessageTest.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Immutable;
using Libplanet.Crypto;
using Libplanet.Net;
Expand Down Expand Up @@ -25,14 +26,19 @@ public void DifferentAppProtocolVersionWithSameStructure()
ImmutableArray<byte>.Empty,
default(Address));
var message = new Ping();
var netMQMessage = message.ToNetMQMessage(privateKey, peer, validAppProtocolVersion);
var netMQMessage = message.ToNetMQMessage(
privateKey,
peer,
DateTimeOffset.UtcNow,
validAppProtocolVersion);

Assert.Throws<DifferentAppProtocolVersionException>(() =>
Message.Parse(
netMQMessage,
true,
invalidAppProtocolVersion,
ImmutableHashSet<PublicKey>.Empty,
null,
null));
}

Expand All @@ -58,7 +64,65 @@ public void DifferentAppProtocolVersionWithDifferentStructure()
true,
invalidAppProtocolVersion,
ImmutableHashSet<PublicKey>.Empty,
null,
null));
}

[Fact]
public void InvalidTimestamp()
{
var privateKey = new PrivateKey();
var peer = new Peer(privateKey.PublicKey);
var futureOffset = DateTimeOffset.MaxValue;
var pastOffset = DateTimeOffset.MinValue;
var appProtocolVersion = new AppProtocolVersion(
1,
new Bencodex.Types.Integer(0),
ImmutableArray<byte>.Empty,
default(Address));
var message = new Ping();
NetMQMessage futureRaw =
message.ToNetMQMessage(privateKey, peer, futureOffset, appProtocolVersion);
// Messages from the future throws InvalidTimestampException.
Assert.Throws<InvalidTimestampException>(() =>
Message.Parse(
futureRaw,
true,
appProtocolVersion,
ImmutableHashSet<PublicKey>.Empty,
null,
TimeSpan.FromSeconds(1)));
NetMQMessage pastRaw =
message.ToNetMQMessage(privateKey, peer, pastOffset, appProtocolVersion);
// Messages from the far past throws InvalidTimestampException.
Assert.Throws<InvalidTimestampException>(() =>
Message.Parse(
pastRaw,
true,
appProtocolVersion,
ImmutableHashSet<PublicKey>.Empty,
null,
TimeSpan.FromSeconds(1)));
}

[Fact]
public void Parse()
{
var privateKey = new PrivateKey();
var peer = new Peer(privateKey.PublicKey);
var dateTimeOffset = DateTimeOffset.UtcNow;
var appProtocolVersion = new AppProtocolVersion(
1,
new Bencodex.Types.Integer(0),
ImmutableArray<byte>.Empty,
default(Address));
var message = new Ping();
NetMQMessage raw =
message.ToNetMQMessage(privateKey, peer, dateTimeOffset, appProtocolVersion);
var parsed = Message.Parse(raw, true, appProtocolVersion, null, null, null);
Assert.Equal(peer, parsed.Remote);
Assert.Equal(appProtocolVersion, parsed.Version);
Assert.Equal(dateTimeOffset, parsed.Timestamp);
}
}
}
32 changes: 27 additions & 5 deletions Libplanet.Tests/Net/SwarmTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,11 @@ public async Task GetMultipleBlocksAtOnce()
{
var request = new GetBlocks(hashes.Select(pair => pair.Item2), 2);
socket.SendMultipartMessage(
request.ToNetMQMessage(privateKey, swarmB.AsPeer, swarmB.AppProtocolVersion)
request.ToNetMQMessage(
privateKey,
swarmB.AsPeer,
DateTimeOffset.UtcNow,
swarmB.AppProtocolVersion)
);

NetMQMessage response = socket.ReceiveMultipartMessage();
Expand All @@ -597,6 +601,7 @@ public async Task GetMultipleBlocksAtOnce()
true,
swarmA.AppProtocolVersion,
swarmA.TrustedAppProtocolVersionSigners,
null,
null);
Libplanet.Net.Messages.Blocks blockMessage =
(Libplanet.Net.Messages.Blocks)parsedMessage;
Expand All @@ -609,6 +614,7 @@ public async Task GetMultipleBlocksAtOnce()
true,
swarmA.AppProtocolVersion,
swarmA.TrustedAppProtocolVersionSigners,
null,
null);
blockMessage = (Libplanet.Net.Messages.Blocks)parsedMessage;

Expand Down Expand Up @@ -2374,7 +2380,11 @@ public async Task BlockDemand()
var request =
new BlockHeaderMessage(swarm.BlockChain.Genesis.Hash, higherBlock.Header);
socket.SendMultipartMessage(
request.ToNetMQMessage(privateKey1, sender1, swarm.AppProtocolVersion)
request.ToNetMQMessage(
privateKey1,
sender1,
DateTimeOffset.UtcNow,
swarm.AppProtocolVersion)
);
await swarm.BlockHeaderReceived.WaitAsync();
await Task.Delay(100);
Expand All @@ -2385,7 +2395,11 @@ public async Task BlockDemand()
request =
new BlockHeaderMessage(swarm.BlockChain.Genesis.Hash, lowerBlock.Header);
socket.SendMultipartMessage(
request.ToNetMQMessage(privateKey2, sender2, swarm.AppProtocolVersion)
request.ToNetMQMessage(
privateKey2,
sender2,
DateTimeOffset.UtcNow,
swarm.AppProtocolVersion)
);
await swarm.BlockHeaderReceived.WaitAsync();
// Await for context change
Expand All @@ -2401,7 +2415,11 @@ await Task.Delay(
request =
new BlockHeaderMessage(swarm.BlockChain.Genesis.Hash, higherBlock.Header);
socket.SendMultipartMessage(
request.ToNetMQMessage(privateKey1, sender1, swarm.AppProtocolVersion)
request.ToNetMQMessage(
privateKey1,
sender1,
DateTimeOffset.UtcNow,
swarm.AppProtocolVersion)
);
await swarm.BlockHeaderReceived.WaitAsync();
await Task.Delay(100);
Expand All @@ -2413,7 +2431,11 @@ await Task.Delay(
request =
new BlockHeaderMessage(swarm.BlockChain.Genesis.Hash, lowerBlock.Header);
socket.SendMultipartMessage(
request.ToNetMQMessage(privateKey2, sender2, swarm.AppProtocolVersion)
request.ToNetMQMessage(
privateKey2,
sender2,
DateTimeOffset.UtcNow,
swarm.AppProtocolVersion)
);
await swarm.BlockHeaderReceived.WaitAsync();
await Task.Delay(100);
Expand Down
77 changes: 77 additions & 0 deletions Libplanet/Net/InvalidTimestampException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#nullable enable
using System;
using System.Runtime.Serialization;

namespace Libplanet.Net
{
[Serializable]
public class InvalidTimestampException : Exception
dahlia marked this conversation as resolved.
Show resolved Hide resolved
{
internal InvalidTimestampException(
string message,
DateTimeOffset createdOffset,
TimeSpan lifespan,
DateTimeOffset currentOffset,
Exception innerException
)
: base(message, innerException)
{
CreatedOffset = createdOffset;
Lifespan = lifespan;
CurrentOffset = currentOffset;
}

internal InvalidTimestampException(
string message,
DateTimeOffset createdOffset,
TimeSpan lifespan,
DateTimeOffset currentOffset)
: base(message)
{
CreatedOffset = createdOffset;
Lifespan = lifespan;
CurrentOffset = currentOffset;
}

protected InvalidTimestampException(
SerializationInfo info,
StreamingContext context
)
: base(info, context)
{
CreatedOffset = info.GetValue(nameof(CreatedOffset), typeof(DateTimeOffset))
is DateTimeOffset createdOffset
? createdOffset
: throw new SerializationException(
$"{nameof(CreatedOffset)} is expected to be a non-null " +
$"{nameof(DateTimeOffset)}.");
Lifespan = info.GetValue(nameof(Lifespan), typeof(TimeSpan))
is TimeSpan lifetime
? lifetime
: throw new SerializationException(
$"{nameof(Lifespan)} is expected to be a non-null " +
$"{nameof(TimeSpan)}.");
CurrentOffset = info.GetValue(nameof(CurrentOffset), typeof(DateTimeOffset))
is DateTimeOffset currentOffset
? currentOffset
: throw new SerializationException(
$"{nameof(CurrentOffset)} is expected to be a non-null " +
$"{nameof(DateTimeOffset)}.");
}

internal DateTimeOffset CreatedOffset { get; }

internal TimeSpan Lifespan { get; }

internal DateTimeOffset CurrentOffset { get; }

public override void GetObjectData(
SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue(nameof(CreatedOffset), CreatedOffset);
info.AddValue(nameof(Lifespan), Lifespan);
info.AddValue(nameof(CurrentOffset), CurrentOffset);
}
}
}
Loading