Skip to content

Add the routing quest, and explain fees where they belong - #11

Merged
hotpixelgroup merged 1 commit into
mainfrom
routing-and-fees
Aug 26, 2026
Merged

hotpixelgroup merged 1 commit into
mainfrom
routing-and-fees

Conversation

@hotpixelgroup

Copy link
Copy Markdown
Owner

Quest #4 showed a payment crossing hops without ever saying where the route came from or who decided what it cost. Routing read as magic; fees were a passing clause.

Quest #6 — "How does your wallet find a route?"

Four stops, deliberately separating the two questions people conflate:

  • There is no map — gossip, and why a channel announcement can't lie (it names the on-chain output backing it)
  • How a fee is SET — each node picks two numbers per direction and advertises them. No schedule, no floor, no approval
  • How a fee is ASSESSED — one formula, integer truncation, charged on the amount forwarded, paid entirely by the sender in advance so the payee always receives the invoice amount
  • Choosing a path — cheapest ≠ shortest, and why liquidity is never gossiped (which is why payments fail and retry rather than being quoted)

BOLT #7 works its own example through a four-node network and prints the answer, so the finale reproduces the spec's own sum and won't claim anything unless it matches to the millisatoshi.

A real bug, caught by the spec

My first implementation charged each hop using the channel the payment arrived on. The spec settles it in the worked example — A pays B the fee it specified in the B->C channel_update, the channel it forwards out of — and my arithmetic came out at 5,099 instead of 10,199.

Testing against a primary source caught what testing against myself never would have. A consequence worth stating in its own right: the first channel of any route is free, because the node forwarding out of it is the sender, and a sender doesn't charge itself.

Also

  • Six glossary entries for the fee/gossip vocabulary (Routing fee, fee_base_msat, fee_proportional_millionths, channel_update, Gossip, short_channel_id)
  • Two figures: a fee calculator that demonstrates the truncation, and a route race showing two-hop paths differing 2× on price alone
  • Quest Bump js-yaml from 4.3.0 to 4.3.1 #4 now points forward instead of leaving its fee clause hanging
  • whose-lightning renumbers to Signpost each site from the other, clearly and in both directions #7 so routing sits inside the Routing track

Verification

147 tests green (39 in lightning-logic); lint, build, typecheck clean. Exercised in-browser: spec check returns 10,199, routes rank A→B→C (2.2 sats) over A→D→C (4.4 sats), first hop shows no fee.

🤖 Generated with Claude Code

Quest #4 showed a payment crossing hops without ever saying where the
route came from or who decided what it cost. Routing read as magic and
fees were a passing clause.

Quest #6 fills it, in four stops that separate the two questions people
actually conflate. How a fee is SET: each node picks two numbers per
direction — fee_base_msat and fee_proportional_millionths — and gossips
them. Nobody approves them, there is no schedule and no floor. How a fee
is ASSESSED: one formula fixed by the specification, applied to those
numbers, charged on the amount forwarded, paid entirely by the sender in
advance so the payee always receives the invoice amount.

BOLT #7 is unusually generous here: it works its own example through a
four-node network and prints the answer, so the finale reproduces the
specification's own sum and refuses to claim anything unless it matches
to the millisatoshi.

Writing that turned up a real bug. My first implementation charged each
hop using the channel the payment ARRIVED on. The spec settles it in the
worked example — A pays B the fee B specified on B->C, the channel it
forwards OUT of — and the arithmetic came out at 5,099 instead of 10,199.
Testing against a primary source caught what testing against myself never
would have. A consequence worth stating: the first channel of any route
is free, because the node forwarding out of it is the sender.

Also: six glossary entries for the fee and gossip vocabulary, a fee
calculator and a route race figure, and Quest #4 now points forward
rather than leaving the clause hanging. whose-lightning renumbers to #7
so routing sits inside the Routing track.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@hotpixelgroup
hotpixelgroup merged commit e51d16b into main Aug 26, 2026
1 check passed
@hotpixelgroup
hotpixelgroup deleted the routing-and-fees branch August 26, 2026 20:55
hotpixelgroup added a commit that referenced this pull request Aug 26, 2026
The previous pass applied the punctuation rules to every source file,
which pulled in eleven pre-existing bitcoin-logic files that had nothing
to do with the Lightning work. Those comments are restored exactly as
they were.

The single exception is the Bech32Options block, which I wrote this
session when BOLT #11 invoices needed the 90-character address ceiling
lifted. That one is mine, so the rules apply to it, and it now uses
brackets instead of a pair of dashes.

The rules govern what I write. They are not a reason to churn code that
was already here.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant