<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://olaniran.space/feed.xml" rel="self" type="application/atom+xml" /><link href="https://olaniran.space/" rel="alternate" type="text/html" /><updated>2026-09-13T21:46:09+00:00</updated><id>https://olaniran.space/feed.xml</id><title type="html">Olaniran Afouda — Fintech and Bitcoin Architecture</title><subtitle>I&apos;m Olaniran, a backend engineer in Benin building Bitcoin and Lightning payments: Mobile Money to Lightning, ledgers, and payouts that survive slow providers.</subtitle><entry xml:lang="en"><title type="html">Why Lightning payments fail — and what happens next</title><link href="https://olaniran.space/2025/03/19/lightning-routing-failures/" rel="alternate" type="text/html" title="Why Lightning payments fail — and what happens next" /><published>2025-03-19T00:00:00+00:00</published><updated>2025-03-19T00:00:00+00:00</updated><id>https://olaniran.space/2025/03/19/lightning-routing-failures</id><content type="html" xml:base="https://olaniran.space/2025/03/19/lightning-routing-failures/"><![CDATA[<p>A Lightning payment can die for boring reasons — a node went offline, a channel ran dry, a fee was too low. I collected the failure modes I kept running into, so you can recognize them faster than I did.</p>

<h2 id="channel-disabled">Channel disabled</h2>

<p>To make a payment in the Lightning Network we need a channel that we can use to transfer data between two or more partners (routing payments).
Since the Lightning Protocol is a hot system which requires all concerned nodes to be online to process an operation (unlike Bitcoin):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The fact that (i.e. in a routing payment),
any channel can go offline during the payment can be a cause of failure in that payment processing.
</code></pre></div></div>

<p><img src="/assets/images/lpd/topic-003-img1.png" alt="Channel Disabled" /></p>

<h2 id="temporarily-disabled-channel">Temporarily disabled channel</h2>

<p>Temporarily disabling a channel is similar to our previous cause: channel disabled.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>In this case it is marked as temporary, so the node might come back online soon and the channel will be available again (i.e. hardware maintenance).
</code></pre></div></div>

<p><img src="/assets/images/lpd/topic-003-img2.png" alt="Temporarily Channel Disabled" /></p>

<h2 id="permanent-node-failure">Permanent node failure</h2>

<p>This is the most severe failure in the Lightning Protocol.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Firstly, Lightning doesn't have an explicit notion of wallet and backup. For this reason, if your node goes down for any reason, there is a chance you could lose most of your funds.

From another point of view, every other node that had a channel with you will see its funds locked in the channel for a certain time (the to_self_delay property).
</code></pre></div></div>

<p><img src="/assets/images/lpd/topic-003-img3.png" alt="Permanent channel disabled" /></p>

<h2 id="insufficient-channel-capacity">Insufficient channel capacity</h2>

<p>This is the most common source of failure in a payment channel.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>That means the channel doesn't have enough funds to process the payment.
</code></pre></div></div>

<p>Let’s say we want to pay a 25_000-sat invoice.
We have opened a channel with enough capacity (<code class="language-plaintext highlighter-rouge">1_000_000 sats</code>) with node B,
and node B has opened a channel with <code class="language-plaintext highlighter-rouge">20_000 sats</code> to our destination.</p>

<p><code class="language-plaintext highlighter-rouge">20_000 sats is less than 25_000 sats, so node B doesn't have enough satoshis to forward our payment to node C.</code></p>

<p><img src="/assets/images/lpd/topic-003-img4.png" alt="channel capacity" /></p>

<h2 id="incorrect-payment-details">Incorrect payment details</h2>

<p>This is a common cause of payment failure between two people.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>It occurs when, in a payment — routing payment — channel, the recipient gets the wrong hash or amount instead of the ones expected.
</code></pre></div></div>

<h2 id="insufficient-payment-fees">Insufficient payment fees</h2>

<p>The fee set is not enough for a node to process a payment. This can be fixed by increasing the fee for the payment.</p>

<p><img src="/assets/images/lpd/topic-003-img5.png" alt="insufficient_fee" /></p>

<h2 id="expired-htlc">Expired HTLC</h2>

<p>In the Lightning Network, the Hash Timelocked Contract is one of the most resilient mechanisms to handle complex routing payment failures.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>If the payment is not processed before the HTLC timeout expires, the payment fails and the funds are refunded to each owner in the routing payment system.
</code></pre></div></div>

<p>You can read more about <a href="/2025/03/09/hash-timelocked-contract/">HTLCs here</a>.</p>

<p><img src="/assets/images/lpd/topic-001-htlc-img3.png" alt="HTLC_timeout" /></p>

<h2 id="required-node-feature-missing">Required node feature missing</h2>

<p>This failure occurs when a payment requires a specific protocol feature that a node in the routing path doesn’t support.</p>

<p>The <code class="language-plaintext highlighter-rouge">Required Node Feature Missing</code> error in the Lightning Network is an important but relatively technical routing failure.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>When a Lightning Network payment is being routed, it needs to pass through multiple nodes to reach its destination.
Each node might support different features or capabilities, as the Lightning Network protocol has evolved over time with various upgrades and improvements.
</code></pre></div></div>

<p>For example:</p>

<ul>
  <li>Multi-part payments (MPP) require nodes to understand how to handle payment fragments</li>
  <li>HODL invoices require specific timelock handling</li>
  <li>TLV (Type-Length-Value) extension fields for additional payment data</li>
  <li>Anchor outputs for more flexible fee management</li>
  <li>Newer hash functions or cryptographic primitives</li>
</ul>

<p><code class="language-plaintext highlighter-rouge">This can result from incompatibilities between the versions of the Lightning implementations run by nodes.</code></p>

<p><img src="/assets/images/lpd/topic-003-img6.png" alt="RNF" /></p>]]></content><author><name></name></author><category term="lightning" /><category term="seminar" /><category term="routing" /><summary type="html"><![CDATA[Dead channels, low capacity, wrong fees, expired HTLCs: the real reasons Lightning payments fail, with examples from routing a payment.]]></summary></entry><entry xml:lang="en"><title type="html">How Lightning nodes trust each other: MAC and HMAC, simply explained</title><link href="https://olaniran.space/2025/03/12/mac-hmac-in-lightning/" rel="alternate" type="text/html" title="How Lightning nodes trust each other: MAC and HMAC, simply explained" /><published>2025-03-12T00:00:00+00:00</published><updated>2025-03-12T00:00:00+00:00</updated><id>https://olaniran.space/2025/03/12/mac-hmac-in-lightning</id><content type="html" xml:base="https://olaniran.space/2025/03/12/mac-hmac-in-lightning/"><![CDATA[<p>If anyone could rewrite messages between Lightning nodes, payments would fall apart. I dug into where MAC and HMAC actually sit in the protocol, and why they matter. Here is the plain-English version.</p>

<h2 id="where-are-mac-and-hmac-implemented-in-the-lightning-protocol">Where are MAC and HMAC implemented in the Lightning Protocol?</h2>

<p>Let’s start with the basics first.</p>

<h3 id="what-are-mac-and-hmac">What are MAC and HMAC?</h3>

<p>MAC stands for Message Authentication Code. It is a tag we use to prove that the message we are sending is authentic — not altered — and that it came from the right sender.
A MAC is a one-way function, meaning that it is easy to compute the MAC of a message, but it is hard to compute the message from the MAC.</p>

<p>Let’s take an example without and with a MAC.</p>

<ul>
  <li><em>Without a MAC</em></li>
</ul>

<p>In this context, we have two nodes, Olaniran and John. Since we have an open channel, we have a way to communicate between us. Actually <code class="language-plaintext highlighter-rouge">Olaniran</code> can send a message to John, and he can respond back to <code class="language-plaintext highlighter-rouge">Olaniran</code>.</p>

<p>Our current configuration looks like:</p>

<p><img src="/assets/images/lpd/topic-002-init.png" alt="img1" /></p>

<p>In this case, we are exposed to rewriting attacks, where an attacker node can intercept the message and rewrite it. This is a problem because we can’t be sure if the message is authentic or not.</p>

<p><img src="/assets/images/lpd/topic-002-img1.png" alt="img2" /></p>

<ul>
  <li><em>With a MAC</em></li>
</ul>

<p>To prevent this, we are going to add a kind of tag to the message. This tag is called a MAC (Message Authentication Code).</p>

<p><img src="/assets/images/lpd/topic-002-img2.png" alt="mac" />
<img src="/assets/images/lpd/topic-002-img22.png" alt="mac" /></p>

<p>But another problem remains: how do we ensure that we pass the message and the key K in the right order so that our partner can verify the authenticity and integrity of our message?</p>

<p>Since <code class="language-plaintext highlighter-rouge">MAC(message, key)</code> is different from <code class="language-plaintext highlighter-rouge">MAC(key, message)</code>, we have to define an order to create the MAC tag.</p>

<p><img src="/assets/images/lpd/topic-002-img3.png" alt="mac-msg-key-order" /></p>

<p>At this point, we can introduce <code class="language-plaintext highlighter-rouge">HMAC, which is a MAC implementation based on hash functions</code>.</p>

<p><img src="/assets/images/lpd/topic-002-img4.png" alt="hmac-msg-key-order" /></p>

<p>HMAC is now here to provide:</p>

<ul>
  <li>More privacy</li>
  <li>Message integrity and authenticity</li>
  <li>Key integrity and authenticity</li>
</ul>

<h2 id="why-and-where">Why and where?</h2>

<p>From this we can conclude that MAC and HMAC are essentially used to prove the authenticity of communications and messages between nodes.</p>

<p>In Lightning, it covers:</p>

<ul>
  <li>Message transport</li>
  <li>Onion routing</li>
  <li>Payment channels (channel state)</li>
  <li>Hashed Timelock Contracts (HTLCs)</li>
</ul>]]></content><author><name></name></author><category term="lightning" /><category term="seminar" /><category term="cryptography" /><summary type="html"><![CDATA[Where MAC and HMAC live in Lightning — message transport, onion routing, channels — and why they stop attackers from rewriting payments.]]></summary></entry><entry xml:lang="en"><title type="html">HTLCs explained: how Lightning moves money without trust</title><link href="https://olaniran.space/2025/03/09/hash-timelocked-contract/" rel="alternate" type="text/html" title="HTLCs explained: how Lightning moves money without trust" /><published>2025-03-09T00:00:00+00:00</published><updated>2025-03-09T00:00:00+00:00</updated><id>https://olaniran.space/2025/03/09/hash-timelocked-contract</id><content type="html" xml:base="https://olaniran.space/2025/03/09/hash-timelocked-contract/"><![CDATA[<p>I kept hearing “HTLC” and nodding along — until I had to explain it myself. Here is the simple version I wish someone gave me: how Lightning moves sats across people you don’t trust, using a hash and a deadline.</p>

<h2 id="what-is-an-htlc">What is an HTLC?</h2>

<p>A Hash Timelocked Contract is basically a contract between two entities (nodes) in the Lightning Network. This contract says:</p>

<p>If you are able to prove to me you made a payment of <code class="language-plaintext highlighter-rouge">X satoshis</code> with a secret which hashes to this <code class="language-plaintext highlighter-rouge">Hash</code> before <code class="language-plaintext highlighter-rouge">X units of time</code>, you can spend these <code class="language-plaintext highlighter-rouge">Y &gt;= X satoshis</code>, otherwise, I’ll get back my funds.</p>

<p>Let’s take an example to understand this better.
Let’s say I want to send 2300 sats to Fadi but I do not have an open channel with her.</p>

<p>I have an open channel with Ariel and have <code class="language-plaintext highlighter-rouge">10_998 sats</code> as channel capacity. By the <code class="language-plaintext highlighter-rouge">pathfinding</code> algorithm, I found the shortest path to Fadi through Ariel.</p>

<p>Our actual configuration looks like:</p>

<p><img src="/assets/images/lpd/topic-001-htlc-pathfinding.png" alt="Pathfinding" /></p>

<h2 id="how-does-an-htlc-work-in-that-configuration">How does an HTLC work in that configuration?</h2>

<p>To send some sats to Fadi I need to get an invoice from her, maybe through her blog or when she sends it to me. The invoice will contain the following information: <code class="language-plaintext highlighter-rouge">amount</code>, <code class="language-plaintext highlighter-rouge">hash</code> and <code class="language-plaintext highlighter-rouge">expiration</code>.</p>

<p><img src="/assets/images/lpd/topic-001-htlc-img1.png" alt="invoice" /></p>

<p>Let’s focus on the <code class="language-plaintext highlighter-rouge">hash</code> part. The hash is a hash of the secret which will be used to prove the payment.</p>

<p>Since I use this route found by pathfinding, we will now call it a <code class="language-plaintext highlighter-rouge">routed payment</code>, with the route: <code class="language-plaintext highlighter-rouge">I -&gt; Ariel -&gt; Velia -&gt; Fadi</code></p>

<p>I need to make a contract with Ariel to send 2300 sats to Fadi that says:</p>

<p>If he is able to prove he successfully made this transfer with 30s left, he can spend the 3000 sats we both signed in a 2-of-2 multisig address, otherwise I will get back my funds.</p>

<p>In turn, <code class="language-plaintext highlighter-rouge">Ariel</code> will sign a contract with <code class="language-plaintext highlighter-rouge">Velia</code> to send <code class="language-plaintext highlighter-rouge">2300 sats to Fadi</code>, and if she is able to prove she successfully made this transfer with <code class="language-plaintext highlighter-rouge">20s left</code>, she can spend the <code class="language-plaintext highlighter-rouge">2700 sats</code> they both signed in a 2-of-2 multisig address, otherwise Ariel will get back his funds.</p>

<p>Then <code class="language-plaintext highlighter-rouge">Velia</code> will sign a contract with <code class="language-plaintext highlighter-rouge">Fadi</code> that says:</p>

<p>You can spend the <code class="language-plaintext highlighter-rouge">2300 sats</code> we both signed in a 2-of-2 multisig address if you give me the secret which hashes to <code class="language-plaintext highlighter-rouge">hash</code> with <code class="language-plaintext highlighter-rouge">10s left</code>, otherwise I will get back my funds.</p>

<p><img src="/assets/images/lpd/topic-001-img2.png" alt="HTLCs" /></p>

<h2 id="htlc-successful-case">HTLC successful case</h2>

<p>Once we have established an HTLC between Fadi and an intermediate node, Velia in our case, if Fadi gives her secret (unique) for this payment hash to Velia before the expiration time, she will be able to spend the <code class="language-plaintext highlighter-rouge">2300 sats</code>. She successfully received our satoshis.</p>

<p>In turn, Velia will give the secret to Ariel before the expiration time, he will be able to spend, and so on… <code class="language-plaintext highlighter-rouge">We move backward with the secret from Fadi to me</code>.</p>

<p><img src="/assets/images/lpd/topic-001-htlc-img2.png" alt="success" /></p>

<h2 id="htlc-failure-case">HTLC failure case</h2>

<p>For any reason, if some node is unable to fulfill its HTLC contract, primarily:</p>

<ul>
  <li>Every node will get back its own funds</li>
  <li>And all failed HTLCs make the payment fail too.</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>This is the atomicity of the HTLC. If one node fails to complete the HTLC, the entire payment fails.
</code></pre></div></div>

<p><img src="/assets/images/lpd/topic-001-htlc-img3.png" alt="FAILURES" /></p>

<h2 id="do-i-need-to-trust-the-following-nodes">Do I need to trust the following nodes?</h2>

<p>No, you don’t need to trust the nodes in the path. The HTLC is a trust mechanism: thanks to the 2-of-2 multisig address you lock the funds in, your partner cannot spend your funds without your validation.</p>

<p>As Lightning is a punishment-based system, cheaters risk losing their entire funds in the payment channel used.</p>

<p>HTLCs ensure trustlessness in that way.</p>

<h2 id="what-do-participants-gain">What do participants gain?</h2>

<p>Remember that the HTLC is a mechanism to ensure the payment is atomic. The participants gain the following:</p>

<ul>
  <li><strong>Security</strong>: the payment is secure, even if one node fails to complete the HTLC,</li>
  <li><strong>Atomicity</strong>: the payment is atomic, even if one node fails to complete the HTLC,</li>
  <li><strong>Trustlessness</strong>: the payment is trustless, you don’t need to trust the nodes.</li>
</ul>

<p>And if you remember well, <code class="language-plaintext highlighter-rouge">the Y amount in the HTLC definition is greater than or equal to the amount they have to send. So they do not lose money.</code></p>

<p>They can be rewarded with some extra sats we will call here — some routing fees.</p>]]></content><author><name></name></author><category term="lightning" /><category term="seminar" /><category term="htlc" /><summary type="html"><![CDATA[What is a Hash Timelocked Contract? I explain how Lightning routes a payment across channels with hashes and timeouts — no need to trust middlemen.]]></summary></entry></feed>