-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
360 additions
and
1 deletion.
There are no files selected for viewing
71 changes: 71 additions & 0 deletions
71
src/NLightning.Bolts/BOLT2/Messages/ChannelReestablishMessage.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
using System.Runtime.Serialization; | ||
|
||
namespace NLightning.Bolts.BOLT2.Messages; | ||
|
||
using Base; | ||
using Bolts.Constants; | ||
using Common.Constants; | ||
using Common.TLVs; | ||
using Exceptions; | ||
using Payloads; | ||
|
||
/// <summary> | ||
/// Represents a channel_reestablish message. | ||
/// </summary> | ||
/// <remarks> | ||
/// The channel_reestablish message is sent when a connection is lost. | ||
/// The message type is 136. | ||
/// </remarks> | ||
public sealed class ChannelReestablishMessage : BaseMessage | ||
{ | ||
/// <summary> | ||
/// The payload of the message. | ||
/// </summary> | ||
public new ChannelReestablishPayload Payload { get => (ChannelReestablishPayload)base.Payload; } | ||
|
||
public NextFundingTlv? NextFundingTlv { get; } | ||
|
||
public ChannelReestablishMessage(ChannelReestablishPayload payload, NextFundingTlv? nextFundingTlv = null) | ||
: base(MessageTypes.CHANNEL_REESTABLISH, payload) | ||
{ | ||
NextFundingTlv = nextFundingTlv; | ||
|
||
if (NextFundingTlv is not null) | ||
{ | ||
Extension = new TlvStream(); | ||
Extension.Add(NextFundingTlv); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Deserialize a ChannelReestablishMessage from a stream. | ||
/// </summary> | ||
/// <param name="stream">The stream to deserialize from.</param> | ||
/// <returns>The deserialized ChannelReestablishMessage.</returns> | ||
/// <exception cref="MessageSerializationException">Error deserializing ChannelReestablishMessage</exception> | ||
public static async Task<ChannelReestablishMessage> DeserializeAsync(Stream stream) | ||
{ | ||
try | ||
{ | ||
// Deserialize payload | ||
var payload = await ChannelReestablishPayload.DeserializeAsync(stream); | ||
|
||
// Deserialize extension | ||
var extension = await TlvStream.DeserializeAsync(stream); | ||
if (extension is null) | ||
{ | ||
return new ChannelReestablishMessage(payload); | ||
} | ||
|
||
var nextFundingTlv = extension.TryGetTlv(TlvConstants.NEXT_FUNDING, out var tlv) | ||
? NextFundingTlv.FromTlv(tlv!) | ||
: null; | ||
|
||
return new ChannelReestablishMessage(payload, nextFundingTlv); | ||
} | ||
catch (SerializationException e) | ||
{ | ||
throw new MessageSerializationException("Error deserializing ChannelReestablishMessage", e); | ||
} | ||
} | ||
} |
86 changes: 86 additions & 0 deletions
86
src/NLightning.Bolts/BOLT2/Payloads/ChannelReestablishPayload.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
using NBitcoin; | ||
|
||
namespace NLightning.Bolts.BOLT2.Payloads; | ||
|
||
using Common.BitUtils; | ||
using Exceptions; | ||
using Interfaces; | ||
|
||
/// <summary> | ||
/// Represents the payload for the channel_reestablish message. | ||
/// </summary> | ||
/// <remarks> | ||
/// Initializes a new instance of the ChannelReestablishPayload class. | ||
/// </remarks> | ||
/// <param name="channelId">The channel ID.</param> | ||
public class ChannelReestablishPayload(ChannelId channelId, ulong nextCommitmentNumber, ulong nextRevocationNumber, ReadOnlyMemory<byte> yourLastPerCommitmentSecret, PubKey myCurrentPerCommitmentPoint) : IMessagePayload | ||
{ | ||
/// <summary> | ||
/// Gets the channel ID. | ||
/// </summary> | ||
public ChannelId ChannelId { get; } = channelId; | ||
|
||
/// <summary> | ||
/// The commitment transaction counter | ||
/// </summary> | ||
public ulong NextCommitmentNumber { get; } = nextCommitmentNumber; | ||
|
||
/// <summary> | ||
/// The commitment counter it expects for the next revoke and ack message | ||
/// </summary> | ||
public ulong NextRevocationNumber { get; } = nextRevocationNumber; | ||
|
||
/// <summary> | ||
/// The last per commitment secret received | ||
/// </summary> | ||
public ReadOnlyMemory<byte> YourLastPerCommitmentSecret { get; } = yourLastPerCommitmentSecret; | ||
|
||
/// <summary> | ||
/// The current per commitment point | ||
/// </summary> | ||
public PubKey MyCurrentPerCommitmentPoint { get; } = myCurrentPerCommitmentPoint; | ||
|
||
/// <inheritdoc/> | ||
public async Task SerializeAsync(Stream stream) | ||
{ | ||
await ChannelId.SerializeAsync(stream); | ||
await stream.WriteAsync(EndianBitConverter.GetBytesBigEndian(NextCommitmentNumber)); | ||
await stream.WriteAsync(EndianBitConverter.GetBytesBigEndian(NextRevocationNumber)); | ||
await stream.WriteAsync(YourLastPerCommitmentSecret); | ||
await stream.WriteAsync(MyCurrentPerCommitmentPoint.ToBytes()); | ||
} | ||
|
||
/// <summary> | ||
/// Deserializes the payload from a stream. | ||
/// </summary> | ||
/// <param name="stream">The stream to deserialize from.</param> | ||
/// <returns>The deserialized payload.</returns> | ||
/// <exception cref="PayloadSerializationException">Error deserializing Payload</exception> | ||
public static async Task<ChannelReestablishPayload> DeserializeAsync(Stream stream) | ||
{ | ||
try | ||
{ | ||
var channelId = await ChannelId.DeserializeAsync(stream); | ||
|
||
var buffer = new byte[sizeof(ulong)]; | ||
await stream.ReadExactlyAsync(buffer); | ||
var nextCommitmentNumber = EndianBitConverter.ToUInt64BigEndian(buffer); | ||
|
||
await stream.ReadExactlyAsync(buffer); | ||
var nextRevocationNumber = EndianBitConverter.ToUInt64BigEndian(buffer); | ||
|
||
var yourLastPerCommitmentSecret = new byte[32]; | ||
await stream.ReadExactlyAsync(yourLastPerCommitmentSecret); | ||
|
||
buffer = new byte[33]; | ||
await stream.ReadExactlyAsync(buffer); | ||
var myCurrentPerCommitmentPoint = new PubKey(buffer); | ||
|
||
return new ChannelReestablishPayload(channelId, nextCommitmentNumber, nextRevocationNumber, yourLastPerCommitmentSecret, myCurrentPerCommitmentPoint); | ||
} | ||
catch (Exception e) | ||
{ | ||
throw new PayloadSerializationException("Error deserializing ChannelReestablishPayload", e); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
namespace NLightning.Common.TLVs; | ||
|
||
using Constants; | ||
using Types; | ||
|
||
/// <summary> | ||
/// Blinded Path TLV. | ||
/// </summary> | ||
/// <remarks> | ||
/// The blinded path TLV is used in the UpdateAddHtlcMessage to communicate the blinded path key. | ||
/// </remarks> | ||
public class NextFundingTlv : Tlv | ||
{ | ||
/// <summary> | ||
/// The blinded path key | ||
/// </summary> | ||
public byte[] NextFundingTxId { get; } | ||
|
||
public NextFundingTlv(byte[] nextFundingTxId) : base(TlvConstants.NEXT_FUNDING) | ||
{ | ||
NextFundingTxId = nextFundingTxId; | ||
|
||
Value = NextFundingTxId; | ||
Length = Value.Length; | ||
} | ||
|
||
/// <summary> | ||
/// Cast NextFundingTlv from a Tlv. | ||
/// </summary> | ||
/// <param name="tlv">The tlv to cast from.</param> | ||
/// <returns>The cast NextFundingTlv.</returns> | ||
/// <exception cref="InvalidCastException">Error casting NextFundingTlv</exception> | ||
public static NextFundingTlv FromTlv(Tlv tlv) | ||
{ | ||
if (tlv.Type != TlvConstants.NEXT_FUNDING) | ||
{ | ||
throw new InvalidCastException("Invalid TLV type"); | ||
} | ||
|
||
if (tlv.Length != 32) | ||
{ | ||
throw new InvalidCastException("Invalid length"); | ||
} | ||
|
||
return new NextFundingTlv(tlv.Value); | ||
} | ||
} |
123 changes: 123 additions & 0 deletions
123
test/NLightning.Bolts.Tests/BOLT2/Messages/TxChannelReestablishMessageTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
using NBitcoin; | ||
|
||
namespace NLightning.Bolts.Tests.BOLT2.Messages; | ||
|
||
using Bolts.BOLT2.Messages; | ||
using Bolts.BOLT2.Payloads; | ||
using Common.TLVs; | ||
using Common.Types; | ||
using Exceptions; | ||
using Utils; | ||
|
||
public class ChannelReestablishMessageTests | ||
{ | ||
#region Deserialize | ||
[Fact] | ||
public async Task Given_ValidStream_When_DeserializeAsync_Then_ReturnsChannelReestablishMessage() | ||
{ | ||
// Arrange | ||
var expectedChannelId = ChannelId.Zero; | ||
var expectedNextCommitmentNumber = 1UL; | ||
var expectedNextRevocationNumber = 2UL; | ||
var expectedYourLastPerCommitmentSecret = "567cbdadb00b825448b2e414487d73a97f657f0634166d3ab3f3a2cc1042eda5".ToByteArray(); | ||
var expectedMyCurrentPerCommitmentPoint = new PubKey("02c93ca7dca44d2e45e3cc5419d92750f7fb3a0f180852b73a621f4051c0193a75".ToByteArray()); | ||
var stream = new MemoryStream("000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000002567CBDADB00B825448B2E414487D73A97F657F0634166D3AB3F3A2CC1042EDA502C93CA7DCA44D2E45E3CC5419D92750F7FB3A0F180852B73A621F4051C0193A75".ToByteArray()); | ||
|
||
// Act | ||
var message = await ChannelReestablishMessage.DeserializeAsync(stream); | ||
|
||
// Assert | ||
Assert.Equal(expectedChannelId, message.Payload.ChannelId); | ||
Assert.Equal(expectedNextCommitmentNumber, message.Payload.NextCommitmentNumber); | ||
Assert.Equal(expectedNextRevocationNumber, message.Payload.NextRevocationNumber); | ||
Assert.Equal(expectedYourLastPerCommitmentSecret, message.Payload.YourLastPerCommitmentSecret); | ||
Assert.Equal(expectedMyCurrentPerCommitmentPoint, message.Payload.MyCurrentPerCommitmentPoint); | ||
Assert.Null(message.Extension); | ||
} | ||
|
||
[Fact] | ||
public async Task Given_ValidStream_When_DeserializeAsync_Then_ReturnsChannelReestablishMessageWithExtensions() | ||
{ | ||
// Arrange | ||
var expectedChannelId = ChannelId.Zero; | ||
var expectedNextCommitmentNumber = 1UL; | ||
var expectedNextRevocationNumber = 2UL; | ||
var expectedYourLastPerCommitmentSecret = "567cbdadb00b825448b2e414487d73a97f657f0634166d3ab3f3a2cc1042eda5".ToByteArray(); | ||
var expectedMyCurrentPerCommitmentPoint = new PubKey("02c93ca7dca44d2e45e3cc5419d92750f7fb3a0f180852b73a621f4051c0193a75".ToByteArray()); | ||
var nextFundingTlv = new NextFundingTlv("567cbdadb00b825448b2e414487d73a97f657f0634166d3ab3f3a2cc1042eda5".ToByteArray()); | ||
var stream = new MemoryStream("000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000002567CBDADB00B825448B2E414487D73A97F657F0634166D3AB3F3A2CC1042EDA502C93CA7DCA44D2E45E3CC5419D92750F7FB3A0F180852B73A621F4051C0193A750020567CBDADB00B825448B2E414487D73A97F657F0634166D3AB3F3A2CC1042EDA5".ToByteArray()); | ||
|
||
// Act | ||
var message = await ChannelReestablishMessage.DeserializeAsync(stream); | ||
|
||
// Assert | ||
Assert.Equal(expectedChannelId, message.Payload.ChannelId); | ||
Assert.Equal(expectedNextCommitmentNumber, message.Payload.NextCommitmentNumber); | ||
Assert.Equal(expectedNextRevocationNumber, message.Payload.NextRevocationNumber); | ||
Assert.Equal(expectedYourLastPerCommitmentSecret, message.Payload.YourLastPerCommitmentSecret); | ||
Assert.Equal(expectedMyCurrentPerCommitmentPoint, message.Payload.MyCurrentPerCommitmentPoint); | ||
Assert.NotNull(message.Extension); | ||
Assert.NotNull(message.NextFundingTlv); | ||
Assert.Equal(nextFundingTlv, message.NextFundingTlv); | ||
} | ||
|
||
[Fact] | ||
public async Task Given_InvalidStreamContent_When_DeserializeAsync_Then_ThrowsMessageSerializationException() | ||
{ | ||
// Arrange | ||
var invalidStream = new MemoryStream("000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000002567CBDADB00B825448B2E414487D73A97F657F0634166D3AB3F3A2CC1042EDA502C93CA7DCA44D2E45E3CC5419D92750F7FB3A0F180852B73A621F4051C0193A750002".ToByteArray()); | ||
|
||
// Act & Assert | ||
await Assert.ThrowsAsync<MessageSerializationException>(() => ChannelReestablishMessage.DeserializeAsync(invalidStream)); | ||
} | ||
#endregion | ||
|
||
#region Serialize | ||
[Fact] | ||
public async Task Given_ValidPayload_When_SerializeAsync_Then_WritesCorrectDataToStream() | ||
{ | ||
// Arrange | ||
var channelId = ChannelId.Zero; | ||
var nextCommitmentNumber = 1UL; | ||
var nextRevocationNumber = 2UL; | ||
var yourLastPerCommitmentSecret = "567cbdadb00b825448b2e414487d73a97f657f0634166d3ab3f3a2cc1042eda5".ToByteArray(); | ||
var myCurrentPerCommitmentPoint = new PubKey("02c93ca7dca44d2e45e3cc5419d92750f7fb3a0f180852b73a621f4051c0193a75".ToByteArray()); | ||
var message = new ChannelReestablishMessage(new ChannelReestablishPayload(channelId, nextCommitmentNumber, nextRevocationNumber, yourLastPerCommitmentSecret, myCurrentPerCommitmentPoint)); | ||
var stream = new MemoryStream(); | ||
var expectedBytes = "0088000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000002567CBDADB00B825448B2E414487D73A97F657F0634166D3AB3F3A2CC1042EDA502C93CA7DCA44D2E45E3CC5419D92750F7FB3A0F180852B73A621F4051C0193A75".ToByteArray(); | ||
|
||
// Act | ||
await message.SerializeAsync(stream); | ||
stream.Position = 0; | ||
var result = new byte[stream.Length]; | ||
_ = await stream.ReadAsync(result); | ||
|
||
// Assert | ||
Assert.Equal(expectedBytes, result); | ||
} | ||
|
||
[Fact] | ||
public async Task Given_ValidExtensions_When_SerializeAsync_Then_WritesCorrectDataToStream() | ||
{ | ||
// Arrange | ||
var channelId = ChannelId.Zero; | ||
var nextCommitmentNumber = 1UL; | ||
var nextRevocationNumber = 2UL; | ||
var yourLastPerCommitmentSecret = "567cbdadb00b825448b2e414487d73a97f657f0634166d3ab3f3a2cc1042eda5".ToByteArray(); | ||
var myCurrentPerCommitmentPoint = new PubKey("02c93ca7dca44d2e45e3cc5419d92750f7fb3a0f180852b73a621f4051c0193a75".ToByteArray()); | ||
var nextFundingTlv = new NextFundingTlv("567cbdadb00b825448b2e414487d73a97f657f0634166d3ab3f3a2cc1042eda5".ToByteArray()); | ||
var message = new ChannelReestablishMessage(new ChannelReestablishPayload(channelId, nextCommitmentNumber, nextRevocationNumber, yourLastPerCommitmentSecret, myCurrentPerCommitmentPoint), nextFundingTlv); | ||
var stream = new MemoryStream(); | ||
var expectedBytes = "0088000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000002567CBDADB00B825448B2E414487D73A97F657F0634166D3AB3F3A2CC1042EDA502C93CA7DCA44D2E45E3CC5419D92750F7FB3A0F180852B73A621F4051C0193A750020567CBDADB00B825448B2E414487D73A97F657F0634166D3AB3F3A2CC1042EDA5".ToByteArray(); | ||
|
||
// Act | ||
await message.SerializeAsync(stream); | ||
stream.Position = 0; | ||
var result = new byte[stream.Length]; | ||
_ = await stream.ReadAsync(result); | ||
|
||
// Assert | ||
Assert.Equal(expectedBytes, result); | ||
} | ||
#endregion | ||
} |