Repository navigation
Add the routing quest, and explain fees where they belong - #11
Merged
Merged
Conversation
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
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>
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
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
Routing fee,fee_base_msat,fee_proportional_millionths,channel_update,Gossip,short_channel_id)whose-lightningrenumbers to Signpost each site from the other, clearly and in both directions #7 so routing sits inside the Routing trackVerification
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