Skip to content

Commit

Permalink
add open_channel2 message
Browse files Browse the repository at this point in the history
  • Loading branch information
nGoline committed Nov 14, 2024
1 parent bc0b6d5 commit c89f1af
Show file tree
Hide file tree
Showing 16 changed files with 578 additions and 42 deletions.
2 changes: 2 additions & 0 deletions src/NLightning.Bolt11/NLightning.Bolt11.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

<ItemGroup>
<Compile Include="..\NLightning.Common\BitUtils\*.cs" LinkBase="Common\BitUtils"/>
<Compile Include="..\NLightning.Common\Constants\ChainConstants.cs" LinkBase="Common\Constants"/>
<Compile Include="..\NLightning.Common\Constants\CryptoConstants.cs" LinkBase="Common\Constants"/>
<Compile Include="..\NLightning.Common\Constants\NetworkConstants.cs" LinkBase="Common\Constants"/>
<Compile Include="..\NLightning.Common\Crypto\Ciphers\*.cs" LinkBase="Common\Crypto\Ciphers"/>
Expand All @@ -46,6 +47,7 @@
<Compile Include="..\NLightning.Common\Factories\Crypto\CryptoFactory.cs" LinkBase="Common\Factories"/>
<Compile Include="..\NLightning.Common\Interfaces\Crypto\*.cs" LinkBase="Common\Interfaces"/>
<Compile Include="..\NLightning.Common\Managers\*.cs" LinkBase="Common\Managers"/>
<Compile Include="..\NLightning.Common\Types\ChainHash.cs" LinkBase="Common\Types"/>
<Compile Include="..\NLightning.Common\Types\Network.cs" LinkBase="Common\Types"/>
<Compile Include="..\NLightning.Common\Types\ShortChannelId.cs" LinkBase="Common\Types"/>
<Compile Include="..\NLightning.Bolts\BOLT9\**\*.cs" LinkBase="Bolts\BOLT9"/>
Expand Down
45 changes: 45 additions & 0 deletions src/NLightning.Bolts/BOLT2/Messages/OpenChannel2Message.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Runtime.Serialization;

namespace NLightning.Bolts.BOLT2.Messages;

using Base;
using Bolts.Constants;
using Exceptions;
using Payloads;

/// <summary>
/// Represents an open_channel2 message.
/// </summary>
/// <remarks>
/// The open_channel2 message is sent to another peer in order to start the channel negotiation.
/// The message type is 64.
/// </remarks>
/// <param name="payload"></param>
public sealed class OpenChannel2Message(OpenChannel2Payload payload) : BaseMessage(MessageTypes.OPEN_CHANNEL_2, payload)
{
/// <summary>
/// The payload of the message.
/// </summary>
public new OpenChannel2Payload Payload { get => (OpenChannel2Payload)base.Payload; }

/// <summary>
/// Deserialize a OpenChannel2Message from a stream.
/// </summary>
/// <param name="stream">The stream to deserialize from.</param>
/// <returns>The deserialized OpenChannel2Message.</returns>
/// <exception cref="MessageSerializationException">Error deserializing OpenChannel2Message</exception>
public static async Task<OpenChannel2Message> DeserializeAsync(Stream stream)
{
try
{
// Deserialize payload
var payload = await OpenChannel2Payload.DeserializeAsync(stream);

return new OpenChannel2Message(payload);
}
catch (SerializationException e)
{
throw new MessageSerializationException("Error deserializing OpenChannel2Message", e);
}
}
}
1 change: 0 additions & 1 deletion src/NLightning.Bolts/BOLT2/Messages/TxAbortMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ namespace NLightning.Bolts.BOLT2.Messages;
/// The message type is 74.
/// </remarks>
/// <param name="payload">The tx_abort payload.</param>
/// <param name="extension">The TLV extension.</param>
public sealed class TxAbortMessage(TxAbortPayload payload) : BaseMessage(MessageTypes.TX_ABORT, payload)
{
/// <inheritdoc/>
Expand Down
269 changes: 269 additions & 0 deletions src/NLightning.Bolts/BOLT2/Payloads/OpenChannel2Payload.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
using System.Runtime.Serialization;
using NBitcoin;

namespace NLightning.Bolts.BOLT2.Payloads;

using Common.BitUtils;
using Common.Managers;
using Interfaces;

/// <summary>
/// Represents the payload for the open_channel2 message.
/// </summary>
/// <remarks>
/// Initializes a new instance of the OpenChannel2Payload class.
/// This class depends on the initialized singleton class <see cref="Common.Managers.ConfigManager"/>.
/// This class also depends on the initialized singleton class <seealso cref="Common.Managers.SecureKeyManager"/>.
/// </remarks>
public class OpenChannel2Payload : IMessagePayload
{
/// <summary>
/// The chain_hash value denotes the exact blockchain that the opened channel will reside within.
/// </summary>
public ChainHash ChainHash { get; }

/// <summary>
/// The temporary_channel_id is used to identify this channel on a per-peer basis until the funding transaction
/// is established, at which point it is replaced by the channel_id, which is derived from the funding transaction.
/// </summary>
public ChannelId ChannelId { get; set; }

/// <summary>
/// funding_feerate_perkw indicates the fee rate that the opening node will pay for the funding transaction in
/// satoshi per 1000-weight, as described in BOLT-3, Appendix F
/// </summary>
public uint FundingFeeRatePerKw { get; set; }

/// <summary>
/// commitment_feerate_perkw indicates the fee rate that will be paid for the commitment transaction in
/// satoshi per 1000-weight, as described in BOLT-3, Appendix F
/// </summary>
public uint CommitmentFeeRatePerKw { get; set; }

/// <summary>
/// funding_satoshis is the amount the sender is putting into the channel.
/// </summary>
public ulong FundingSatoshis { get; set; }

/// <summary>
/// dust_limit_satoshis is the threshold below which outputs should not be generated for this node's commitment or
/// HTLC transactions
/// </summary>
public ulong DustLimitSatoshis { get; }

/// <summary>
/// max_htlc_value_in_flight_msat is a cap on total value of outstanding HTLCs offered by the remote node, which
/// allows the local node to limit its exposure to HTLCs
/// </summary>
public ulong MaxHtlcValueInFlightMsat { get; }

/// <summary>
/// htlc_minimum_msat indicates the smallest value HTLC this node will accept.
/// </summary>
public ulong HtlcMinimumMsat { get; }

/// <summary>
/// to_self_delay is how long (in blocks) the other node will have to wait in case of breakdown before redeeming
/// its own funds.
/// </summary>
public ushort ToSelfDelay { get; }

/// <summary>
/// max_accepted_htlcs limits the number of outstanding HTLCs the remote node can offer.
/// </summary>
public ushort MaxAcceptedHtlcs { get; }

/// <summary>
/// locktime is the locktime for the funding transaction.
/// </summary>
public uint Locktime { get; }

/// <summary>
/// funding_pubkey is the public key in the 2-of-2 multisig script of the funding transaction output.
/// </summary>
public PubKey FundingPubKey { get; set; }

/// <summary>
/// revocation_basepoint is used to regenerate the scripts required for the penalty transaction
/// </summary>
public PubKey RevocationBasepoint { get; set; }

/// <summary>
/// delayed_payment_basepoint is used to regenerate the scripts required for the penalty transaction
/// </summary>
public PubKey DelayedPaymentBasepoint { get; set; }

/// <summary>
/// htlc_basepoint is used to produce HTLC signatures for the protocol
/// </summary>
public PubKey HtlcBasepoint { get; set; }

/// <summary>
/// first_per_commitment_point is the per-commitment point used for the first commitment transaction
/// </summary>
public PubKey FirstPerCommitmentPoint { get; set; }

/// <summary>
/// second_per_commitment_point is the per-commitment point used for the first commitment transaction
/// </summary>
public PubKey SecondPerCommitmentPoint { get; set; }

/// <summary>
/// Only the least-significant bit of channel_flags is currently defined: announce_channel. This indicates whether
/// the initiator of the funding flow wishes to advertise this channel publicly to the network
/// </summary>
public ChannelFlags ChannelFlags { get; set; }

/// <summary>
///
/// </summary>
public TlvStream? OpeningTlvs { get; set; }

public OpenChannel2Payload(ChannelId channelId, uint fundingFeeRatePerKw, uint commitmentFeeRatePerKw, ulong fundingSatoshis, PubKey fundingPubKey, PubKey revocationBasepoint, PubKey delayedPaymentBasepoint, PubKey htlcBasepoint, PubKey firstPerCommitmentPoint, PubKey secondPerCommitmentPoint, ChannelFlags channelFlags, TlvStream? openingTlvs = null)
{
ChainHash = ConfigManager.Instance.Network.ChainHash;
DustLimitSatoshis = ConfigManager.Instance.DustLimitSatoshis;
MaxHtlcValueInFlightMsat = ConfigManager.Instance.MaxHtlcValueInFlightMsat;
HtlcMinimumMsat = ConfigManager.Instance.HtlcMinimumMsat;
ToSelfDelay = ConfigManager.Instance.ToSelfDelay;
MaxAcceptedHtlcs = ConfigManager.Instance.MaxAcceptedHtlcs;
Locktime = ConfigManager.Instance.Locktime;
ChannelId = channelId;
FundingFeeRatePerKw = fundingFeeRatePerKw;
CommitmentFeeRatePerKw = commitmentFeeRatePerKw;
FundingSatoshis = fundingSatoshis;
FundingPubKey = fundingPubKey;
RevocationBasepoint = revocationBasepoint;
DelayedPaymentBasepoint = delayedPaymentBasepoint;
HtlcBasepoint = htlcBasepoint;
FirstPerCommitmentPoint = firstPerCommitmentPoint;
SecondPerCommitmentPoint = secondPerCommitmentPoint;
ChannelFlags = channelFlags;
OpeningTlvs = openingTlvs;
}

private OpenChannel2Payload(ChainHash chainHash, ChannelId channelId, uint fundingFeeRatePerKw, uint commitmentFeeRatePerKw, ulong fundingSatoshis, ulong dustLimitSatoshis, ulong maxHtlcValueInFlightMsat, ulong htlcMinimumMsat, ushort toSelfDelay, ushort maxAcceptedHtlcs, uint locktime, PubKey fundingPubKey, PubKey revocationBasepoint, PubKey delayedPaymentBasepoint, PubKey htlcBasepoint, PubKey firstPerCommitmentPoint, PubKey secondPerCommitmentPoint, ChannelFlags channelFlags, TlvStream? openingTlvs = null)
{
ChainHash = chainHash;
ChannelId = channelId;
FundingFeeRatePerKw = fundingFeeRatePerKw;
CommitmentFeeRatePerKw = commitmentFeeRatePerKw;
FundingSatoshis = fundingSatoshis;
DustLimitSatoshis = dustLimitSatoshis;
MaxHtlcValueInFlightMsat = maxHtlcValueInFlightMsat;
HtlcMinimumMsat = htlcMinimumMsat;
ToSelfDelay = toSelfDelay;
MaxAcceptedHtlcs = maxAcceptedHtlcs;
Locktime = locktime;
FundingPubKey = fundingPubKey;
RevocationBasepoint = revocationBasepoint;
DelayedPaymentBasepoint = delayedPaymentBasepoint;
HtlcBasepoint = htlcBasepoint;
FirstPerCommitmentPoint = firstPerCommitmentPoint;
SecondPerCommitmentPoint = secondPerCommitmentPoint;
ChannelFlags = channelFlags;
OpeningTlvs = openingTlvs;
}

/// <inheritdoc/>
public async Task SerializeAsync(Stream stream)
{
await ChainHash.SerializeAsync(stream);
await ChannelId.SerializeAsync(stream);
await stream.WriteAsync(EndianBitConverter.GetBytesBigEndian(FundingFeeRatePerKw));
await stream.WriteAsync(EndianBitConverter.GetBytesBigEndian(CommitmentFeeRatePerKw));
await stream.WriteAsync(EndianBitConverter.GetBytesBigEndian(FundingSatoshis));
await stream.WriteAsync(EndianBitConverter.GetBytesBigEndian(DustLimitSatoshis));
await stream.WriteAsync(EndianBitConverter.GetBytesBigEndian(MaxHtlcValueInFlightMsat));
await stream.WriteAsync(EndianBitConverter.GetBytesBigEndian(HtlcMinimumMsat));
await stream.WriteAsync(EndianBitConverter.GetBytesBigEndian(ToSelfDelay));
await stream.WriteAsync(EndianBitConverter.GetBytesBigEndian(MaxAcceptedHtlcs));
await stream.WriteAsync(EndianBitConverter.GetBytesBigEndian(Locktime));
await stream.WriteAsync(FundingPubKey.ToBytes());
await stream.WriteAsync(RevocationBasepoint.ToBytes());
await stream.WriteAsync(DelayedPaymentBasepoint.ToBytes());
await stream.WriteAsync(HtlcBasepoint.ToBytes());
await stream.WriteAsync(FirstPerCommitmentPoint.ToBytes());
await stream.WriteAsync(SecondPerCommitmentPoint.ToBytes());
await ChannelFlags.SerializeAsync(stream);
if (OpeningTlvs is not null)
{
await OpeningTlvs.SerializeAsync(stream);
}
}

/// <summary>
/// Deserializes the payload from a stream.
/// </summary>
/// <param name="stream">The stream to deserialize from.</param>
/// <returns>The deserialized payload.</returns>
/// <exception cref="SerializationException">Error deserializing Payload</exception>
public static async Task<OpenChannel2Payload> DeserializeAsync(Stream stream)
{
try
{
var chainHash = await ChainHash.DeserializeAsync(stream);
var channelId = await ChannelId.DeserializeAsync(stream);

var bytes = new byte[sizeof(uint)];
await stream.ReadExactlyAsync(bytes);
var fundingFeeRatePerKw = EndianBitConverter.ToUInt32BigEndian(bytes);

await stream.ReadExactlyAsync(bytes);
var commitmentFeeRatePerKw = EndianBitConverter.ToUInt32BigEndian(bytes);

bytes = new byte[sizeof(ulong)];
await stream.ReadExactlyAsync(bytes);
var fundingSatoshis = EndianBitConverter.ToUInt64BigEndian(bytes);

await stream.ReadExactlyAsync(bytes);
var dustLimitSatoshis = EndianBitConverter.ToUInt64BigEndian(bytes);

await stream.ReadExactlyAsync(bytes);
var maxHtlcValueInFlightMsat = EndianBitConverter.ToUInt64BigEndian(bytes);

await stream.ReadExactlyAsync(bytes);
var htlcMinimumMsat = EndianBitConverter.ToUInt64BigEndian(bytes);

bytes = new byte[sizeof(ushort)];
await stream.ReadExactlyAsync(bytes);
var toSelfDelay = EndianBitConverter.ToUInt16BigEndian(bytes);

await stream.ReadExactlyAsync(bytes);
var maxAcceptedHtlcs = EndianBitConverter.ToUInt16BigEndian(bytes);

bytes = new byte[sizeof(uint)];
await stream.ReadExactlyAsync(bytes);
var locktime = EndianBitConverter.ToUInt32BigEndian(bytes);

bytes = new byte[33];
await stream.ReadExactlyAsync(bytes);
var fundingPubKey = new PubKey(bytes);

await stream.ReadExactlyAsync(bytes);
var revocationBasepoint = new PubKey(bytes);

await stream.ReadExactlyAsync(bytes);
var delayedPaymentBasepoint = new PubKey(bytes);

await stream.ReadExactlyAsync(bytes);
var htlcBasepoint = new PubKey(bytes);

await stream.ReadExactlyAsync(bytes);
var firstPerCommitmentPoint = new PubKey(bytes);

await stream.ReadExactlyAsync(bytes);
var secondPerCommitmentPoint = new PubKey(bytes);

var channelFlags = await ChannelFlags.DeserializeAsync(stream);

var openingTlvs = await TlvStream.DeserializeAsync(stream);

return new OpenChannel2Payload(chainHash, channelId, fundingFeeRatePerKw, commitmentFeeRatePerKw, fundingSatoshis, dustLimitSatoshis, maxHtlcValueInFlightMsat, htlcMinimumMsat, toSelfDelay, maxAcceptedHtlcs, locktime, fundingPubKey, revocationBasepoint, delayedPaymentBasepoint, htlcBasepoint, firstPerCommitmentPoint, secondPerCommitmentPoint, channelFlags, openingTlvs);
}
catch (Exception e)
{
throw new SerializationException("Error deserializing OpenChannel2Payload", e);
}
}
}
3 changes: 1 addition & 2 deletions src/NLightning.Bolts/BOLT2/Payloads/TxAbortPayload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ namespace NLightning.Bolts.BOLT2.Payloads;
/// Represents the payload for the tx_abort message.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="TxAbortPayload"/> class.
/// Initializes a new instance of the TxAbortPayload class.
/// </remarks>
/// <param name="channelId">The channel ID.</param>
/// <param name="length">The data length.</param>
/// <param name="data">The data.</param>
public class TxAbortPayload(ChannelId channelId, byte[] data) : IMessagePayload
{
Expand Down
3 changes: 2 additions & 1 deletion src/NLightning.Bolts/Constants/MessageTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public static class MessageTypes
FUNDING_SIGNED = 35,
FUNDING_LOCKED = 36,
SHUTDOWN = 38,
CLOSING_SIGNED = 39;
CLOSING_SIGNED = 39,
OPEN_CHANNEL_2 = 64;
#endregion

#region Interactive Transaction Construction
Expand Down
16 changes: 16 additions & 0 deletions src/NLightning.Bolts/Exceptions/ChannelException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Diagnostics.CodeAnalysis;

namespace NLightning.Bolts.Exceptions;

/// <summary>
/// Represents an exception that is thrown when a channel error occurs.
/// </summary>
/// <remarks>
/// We usually want to close the connection when this exception is thrown.
/// </remarks>
[ExcludeFromCodeCoverage]
public class ChannelException : ErrorException
{
public ChannelException(string message) : base(message) { }
public ChannelException(string message, Exception innerException) : base(message, innerException) { }
}
2 changes: 1 addition & 1 deletion src/NLightning.Bolts/NLightning.Bolts.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</PropertyGroup>

<PropertyGroup Condition="$(Configuration.Contains('Debug'))">
<DefineConstants>DEBUG;$(DefineConstants)</DefineConstants>
<DefineConstants>$(DefineConstants);DEBUG</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(Configuration.Contains('Release'))">
Expand Down
Loading

0 comments on commit c89f1af

Please sign in to comment.