<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>dunxen.dev — Blog</title><description>Long-form posts from dunxen.dev</description><link>https://dunxen.dev/</link><language>en-us</language><image><url>https://dunxen.dev/favicon.png</url><title>dunxen.dev — Blog</title><link>https://dunxen.dev</link></image><atom:link href="https://dunxen.dev/blog/rss.xml" rel="self" type="application/rss+xml"/><item><title>A Look at LDK’s Dual-funded Channels Implementation</title><link>https://dunxen.dev/blog/dual-funding-in-ldk/</link><guid isPermaLink="true">https://dunxen.dev/blog/dual-funding-in-ldk/</guid><pubDate>Thu, 06 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dual-funded channels — or V2-established channels as referred to in the BOLT 2 Lightning Network
specification — have been a long time coming. This protocol has already been adopted by the Eclair
and Core Lightning (CLN) node implementations. We take a closer look at the progress and architecture
of the dual-funded channel implementation in the Lightning Development Kit (LDK), and what makes this challenging.&lt;/p&gt;
&lt;h2 id=&quot;relevant-background-on-ldks-architecture&quot; class=&quot;anchor&quot;&gt;&lt;a class=&quot;anchor-link&quot; href=&quot;#relevant-background-on-ldks-architecture&quot;&gt;#&lt;/a&gt;Relevant background on LDK’s architecture&lt;/h2&gt;
&lt;p&gt;You may be aware that the base LDK project — the &lt;a href=&quot;https://crates.io/crates/lightning&quot;&gt;lightning&lt;/a&gt; crate, its language bindings, and friends — is a library
for plugging into the Lightning Network, handling all the intricacies of the specification and leaving a significant
amount of flexibility for the developer integrating LDK into their application. Consequently, LDK must make more
abstractions around interfaces that are not made by Lightning Network node implementations such as LND, CLN, and
Eclair which act as standalone daemons out of the box.&lt;/p&gt;
&lt;p&gt;One instance of such an abstraction is making few assumptions of the environment in which the application lives.
It may be embedded, as is the case for &lt;a href=&quot;https://github.com/lightning-signer/validating-lightning-signer&quot;&gt;Validating Lightning Signer&lt;/a&gt; (VLS), and would need to work in a no-std world.
In other words, LDK does not expect an operating system.&lt;/p&gt;
&lt;h3 id=&quot;interfacing-with-the-world&quot; class=&quot;anchor&quot;&gt;&lt;a class=&quot;anchor-link&quot; href=&quot;#interfacing-with-the-world&quot;&gt;#&lt;/a&gt;Interfacing with the world&lt;/h3&gt;
&lt;p&gt;LDK provides the interfaces (&lt;code&gt;traits&lt;/code&gt; in Rust) that developers can implement to provide essential functionality needed
for the operation of a Lightning Network node, such as persistence, signing, and networking. LDK also makes no
assumptions around the existence of a particular Bitcoin node implementation such as Bitcoin Core or btcd, so it
cannot rely on ‘ye old faithful and familiar Bitcoin Core RPCs to peek at what’s happening at the base layer.
All communication into and outside LDK’s very specific view of the Lightning Network protocol is via the shuffling
of bytes through a developer’s implementation of the required interfaces.&lt;/p&gt;
&lt;h3 id=&quot;event-handling&quot; class=&quot;anchor&quot;&gt;&lt;a class=&quot;anchor-link&quot; href=&quot;#event-handling&quot;&gt;#&lt;/a&gt;Event Handling&lt;/h3&gt;
&lt;p&gt;One unique example of a trait in LDK that a developer would need to implement is the &lt;code&gt;EventHandler&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-high-contrast github-dark-high-contrast&quot; style=&quot;--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt; trait&lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt; EventHandler&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#66707B;--shiki-dark:#BDC4CC&quot;&gt;    // Required method&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;    fn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#622CBC;--shiki-dark:#DBB7FF&quot;&gt; handle_event&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#023B95;--shiki-dark:#91CBFF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;, event&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt; Event&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt; Result&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;&amp;#x3C;(), &lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;ReplayEvent&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The single required method, &lt;code&gt;handle_event()&lt;/code&gt;, must be implemented to handle the various user-actionable &lt;code&gt;Event&lt;/code&gt;s
generated by LDK, of which there are many variants (currently &lt;a href=&quot;https://docs.rs/lightning/0.1.1/lightning/events/enum.Event.html&quot;&gt;for v0.1.1&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-high-contrast github-dark-high-contrast&quot; style=&quot;--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt; enum&lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt; Event&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    FundingGenerationReady&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    FundingTxBroadcastSafe&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    PaymentClaimable&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    PaymentClaimed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},rd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    ConnectionNeeded&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    InvoiceReceived&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    PaymentSent&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    PaymentFailed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    PaymentPathSuccessful&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    PaymentPathFailed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    ProbeSuccessful&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    ProbeFailed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    PendingHTLCsForwardable&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    HTLCIntercepted&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    SpendableOutputs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    PaymentForwarded&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    ChannelPending&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    ChannelReady&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    ChannelClosed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    DiscardFunding&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    OpenChannelRequest&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    HTLCHandlingFailed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#622CBC;--shiki-dark:#DBB7FF&quot;&gt;    BumpTransaction&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;BumpTransactionEvent&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    OnionMessageIntercepted&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;    OnionMessagePeerConnected&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Specifically looking at the &lt;code&gt;OpenChannelRequest&lt;/code&gt; variant, if we do not specify the automatic acceptance of inbound
channels under certain conditions, we receive an event with all the relevant information about the proposed inbound
channel from a peer.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-high-contrast github-dark-high-contrast&quot; style=&quot;--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;OpenChannelRequest&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;    temporary_channel_id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt; ChannelId&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;    counterparty_node_id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt; PublicKey&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;    funding_satoshis&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt; u64&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;    channel_negotiation_type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt; InboundChannelFunds&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;    channel_type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt; ChannelTypeFeatures&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;    is_announced&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt; bool&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;    params&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0111F;--shiki-dark:#FF9492&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt; ChannelParameters&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#0E1116;--shiki-dark:#F0F3F6&quot;&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In particular, the &lt;code&gt;channel_negotiation_type&lt;/code&gt; field would specify whether this request is for an inbound dual-funded
channel, or the &lt;code&gt;push_msats&lt;/code&gt; value for an inbound V1 channel.&lt;/p&gt;
&lt;h3 id=&quot;background-tasks&quot; class=&quot;anchor&quot;&gt;&lt;a class=&quot;anchor-link&quot; href=&quot;#background-tasks&quot;&gt;#&lt;/a&gt;Background tasks&lt;/h3&gt;
&lt;p&gt;LDK makes progress in state via user-called methods, and messages received from peers. There are still many tasks
that need to be completed in the background, not dependent on receiving peer messages or user method calls.
These include management of feerate estimates for our outbound channels, managing peer connectivity, expiring
outbound payments, and so forth. In order to make progress in this case, the &lt;code&gt;ChannelManager::timer_tick_occurred()&lt;/code&gt;
method must be called every minute.&lt;/p&gt;
&lt;h2 id=&quot;the-current-implementation-design-and-status-of-dual-funded-channels-in-ldk&quot; class=&quot;anchor&quot;&gt;&lt;a class=&quot;anchor-link&quot; href=&quot;#the-current-implementation-design-and-status-of-dual-funded-channels-in-ldk&quot;&gt;#&lt;/a&gt;The current implementation design and status of dual-funded channels in LDK&lt;/h2&gt;
&lt;p&gt;Although still in-progress, there are some design considerations we can discuss about LDK’s implementation of
dual-funded channels.&lt;/p&gt;
&lt;h3 id=&quot;the-interactive-transaction-constructor&quot; class=&quot;anchor&quot;&gt;&lt;a class=&quot;anchor-link&quot; href=&quot;#the-interactive-transaction-constructor&quot;&gt;#&lt;/a&gt;The interactive transaction constructor&lt;/h3&gt;
&lt;p&gt;Dual-funded and splicing both depend on the interactive transaction construction protocol, specified in
&lt;a href=&quot;https://github.com/lightning/bolts/blob/5f31faa0b6e2cdbe32171d79464305f90bda9585/02-peer-protocol.md#interactive-transaction-construction&quot;&gt;BOLT 2&lt;/a&gt;.
In LDK this is &lt;a href=&quot;https://github.com/lightningdevkit/rust-lightning/blob/c5fd164f1db6773c6561c1d54bfbafdca8c6278c/lightning/src/ln/interactivetxs.rs&quot;&gt;implemented as a type-safe state machine&lt;/a&gt;
that is driven to a completely constructed funding transaction that is ready for interactive signing.&lt;/p&gt;
&lt;p&gt;BOLT 2 also provides an example of a message exchange between the channel initiator and channel acceptor during
interactive transaction construction:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-high-contrast github-dark-high-contrast&quot; style=&quot;--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  +--------+                         +--------+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  |        |--(1)- tx_add_input ----&gt;|        |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  |        |&amp;#x3C;-(2)- tx_complete ------|        |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  |        |--(3)- tx_add_output ---&gt;|        |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  |        |&amp;#x3C;-(4)- tx_complete ------|        |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  |        |--(5)- tx_add_input ----&gt;|        |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  |   A    |&amp;#x3C;-(6)- tx_add_input -----|    B   |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  |        |--(7)- tx_remove_output &gt;|        |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  |        |&amp;#x3C;-(8)- tx_add_output ----|        |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  |        |--(9)- tx_complete -----&gt;|        |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  |        |&amp;#x3C;-(10) tx_complete ------|        |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  +--------+                         +--------+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;LDK encapsulates this state machine in the internal &lt;code&gt;InteractiveTxConstructor&lt;/code&gt; struct which is held by pending
dual-funded channels.&lt;/p&gt;
&lt;h3 id=&quot;public-apis-for-dual-funded-channels&quot; class=&quot;anchor&quot;&gt;&lt;a class=&quot;anchor-link&quot; href=&quot;#public-apis-for-dual-funded-channels&quot;&gt;#&lt;/a&gt;Public APIs for dual-funded channels&lt;/h3&gt;
&lt;p&gt;In order to support dual-funded channels, we need to introduce some public methods to &lt;code&gt;ChannelManager&lt;/code&gt; for
creating and accepting dual-funded channels, and signing their funding transactions. Opening dual-funded
channels will use a new &lt;code&gt;create_dual_funded_channel&lt;/code&gt; method where a user will need to provide the funding
inputs to be added during interactive transaction construction. Similarly for accepting dual-funded channels
where the acceptor will be contributing, inputs would also need to be provided to that method.&lt;/p&gt;
&lt;p&gt;A major difference comes up during signing the funding transaction. With V1 channels we would expect the user
to create and sign the funding transaction based on information we give to them such as the funding outpoint, etc.
In the case of dual-funded channels, the funding transaction is interactively constructed and we need to provide
the unsigned transaction to the user via an event so that they can sign the inputs they provided and provide those
witnesses back to &lt;code&gt;ChannelManager&lt;/code&gt; for that specific &lt;code&gt;ChannelId&lt;/code&gt;. For either case, LDK handles the broadcasting of
the funding transaction when it is safe to do so.&lt;/p&gt;
&lt;h3 id=&quot;the-status-of-dual-funding-in-ldk&quot; class=&quot;anchor&quot;&gt;&lt;a class=&quot;anchor-link&quot; href=&quot;#the-status-of-dual-funding-in-ldk&quot;&gt;#&lt;/a&gt;The status of dual-funding in LDK&lt;/h3&gt;
&lt;p&gt;A lot of work has gone into internal refactoring in &lt;code&gt;Channel&lt;/code&gt; and &lt;code&gt;ChannelManager&lt;/code&gt; to pave the way for dual-funding
(and splicing) support. LDK — being a library by nature — made some of the dual-funding implementation details a
little tricky with some outstanding challenges, such as interactive RBF, still needing to be solved.&lt;/p&gt;
&lt;p&gt;There is internal support for accepting dual-funded channels at the moment (since v0.1.0), but it is cfg-flagged
at the moment as some quirks are ironed out. Full support for creating and accepting dual-funded
channels — without RBF support — can be expected in LDK v0.2.0.&lt;/p&gt;</content:encoded></item><item><title>Offline BOLT 11 Invoices on Lightning with ECDH</title><link>https://dunxen.dev/blog/offline-lightning-invoices/</link><guid isPermaLink="true">https://dunxen.dev/blog/offline-lightning-invoices/</guid><pubDate>Sun, 21 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you’ve played around with the Lightning Network, you’ve most definitely come across a BOLT 11 invoice. It’s usually encoded as a QR code for conveniently scanning with your phone’s camera. It includes things like the receiving node’s public key, an amount with a unit suffix, a payment hash, a note, an expiry, maybe some routing hints, etc. These invoices are generated on-the-fly by the receiving node that generates a payment preimage which it keeps secret until the &lt;a href=&quot;https://rusty.ozlabs.org/?p=462&quot;&gt;HTLCs&lt;/a&gt; have made their way across the route.&lt;/p&gt;
&lt;p&gt;If we wanted to enable Lightning payments on a vending machine, for example, you might think that you’d need integrate an always-online node within the vending machine, or have it connected to some remote node to generate the invoices, or even duplicate the private key of the receiving node. However, with the help of ECDH, described in a message in the &lt;a href=&quot;https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-June/002009.html&quot;&gt;Lightning dev mailing list&lt;/a&gt;, we don’t need the vending machine to be online at all!&lt;/p&gt;
&lt;p&gt;There are a few key elements to making this work.&lt;/p&gt;
&lt;h2 id=&quot;elliptic-curve-diffie-hellman-ecdh&quot; class=&quot;anchor&quot;&gt;&lt;a class=&quot;anchor-link&quot; href=&quot;#elliptic-curve-diffie-hellman-ecdh&quot;&gt;#&lt;/a&gt;Elliptic-Curve Diffie-Hellman (ECDH)&lt;/h2&gt;
&lt;p&gt;ECDH allows us to use elliptic-curve public–private key pairs to establish a shared secret.&lt;/p&gt;
&lt;p&gt;Suppose Alice has an ECDSA secp256k1 public key A and private key a, and Bob has public key B and private key b. Alice can compute the point aB, and Bob can compute the point bA.&lt;/p&gt;
&lt;p&gt;Note that if G is the generator point for the elliptic curve, then:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-high-contrast github-dark-high-contrast&quot; style=&quot;--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;aB = a(bG) = (ab)G = (ba)G = b(aG) = bA&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(By the corresponding associativity and commutativity rules of the associated groups)&lt;/p&gt;
&lt;p&gt;So &lt;code&gt;aB&lt;/code&gt; (or equivalently, &lt;code&gt;bA&lt;/code&gt;) is the shared secret that could be used for symmetric encryption if desired (taking the x-coordinate for example).&lt;/p&gt;
&lt;p&gt;This provides an opportunity for us to do something interesting.&lt;/p&gt;
&lt;p&gt;Let’s say that the vending machine is an “offline” node that generates an ephemeral private key &lt;code&gt;k&lt;/code&gt; and corresponding public key &lt;code&gt;K&lt;/code&gt; (node ID). Suppose there is also an “online” node with public key &lt;code&gt;N&lt;/code&gt; that is owned by the vending machine company. The vending machine then generates an invoice with some routing hints that the payment should go through node &lt;code&gt;N&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So we declare &lt;code&gt;N&lt;/code&gt; as an intermediary routing node for &lt;code&gt;K&lt;/code&gt;, which is actually impossible to route to since it is offline / disconnnected from the Lightning Network.&lt;/p&gt;
&lt;p&gt;This is where the trick comes in. The preimage is specifically constructed as &lt;code&gt;hmac-sha256(x, amount)&lt;/code&gt;, where &lt;code&gt;x&lt;/code&gt; is the shared secret between &lt;code&gt;N&lt;/code&gt; and &lt;code&gt;K&lt;/code&gt; (x-coordinate of &lt;code&gt;kN&lt;/code&gt;. The amount is stored in the 8 byte short channel ID between &lt;code&gt;N&lt;/code&gt; and &lt;code&gt;K&lt;/code&gt;. A channel that does not really exist.&lt;/p&gt;
&lt;h2 id=&quot;routing-to-a-non-existent-node&quot; class=&quot;anchor&quot;&gt;&lt;a class=&quot;anchor-link&quot; href=&quot;#routing-to-a-non-existent-node&quot;&gt;#&lt;/a&gt;Routing to a non-existent node&lt;/h2&gt;
&lt;p&gt;Now a customer walks up to the vending machine, and being a forward-thinking #LaserRaysUntil100k human, decides to pay with their non-custodial mobile Lightning wallet. They scan the BOLT 11 invoice generated by the vending machine and their wallet (node) picks up the routing hints. It then attempts to route the payment to &lt;code&gt;K&lt;/code&gt; along some route via &lt;code&gt;N&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now when &lt;code&gt;N&lt;/code&gt; is asked to route a payment to an unknown node, it calculates the ECDH shared secret &lt;code&gt;x&lt;/code&gt;. It then uses this, along with the amount encoded in the short channel ID to reconstruct a preimage with &lt;code&gt;hmac-sha256(x, amount)&lt;/code&gt;. The payment hash is derived from that and if it matches the payment hash in the accepted HTLC, then it can claim the amount.&lt;/p&gt;
&lt;p&gt;I plan to make a little Web simulation that demonstrates this a bit better at some stage! Until then, ride the Lightning!&lt;/p&gt;</content:encoded></item></channel></rss>