# BOLT12 Offer Parsing Bug Report: SCID in Blinded Paths ## Summary CLN version 24.02 fails to decode certain BOLT12 offers that use short channel IDs (SCIDs) instead of pubkeys in blinded path definitions. This is due to a wire format incompatibility with the newer BOLT12 specification. ## Affected Versions | Version | Status | |---------|--------| | v24.02 (Feb 2024) | **Affected** | | v24.05 (May 2024) | Fixed | | v24.08+ | Fixed | ## Symptom When attempting to decode certain BOLT12 offers in v24.02, users receive the error: ```json { "code": -32602, "message": "string: invalid offer data: invalid token '\"lno1pg7y7s69...\"'" } ``` The same offer decodes successfully in v24.05 and later versions. ## Root Cause Analysis ### The Problem BOLT12 blinded paths contain a `first_node_id` field that identifies the entry point to the blinded route. The BOLT12 specification was updated to allow this field to be encoded as either: 1. **Pubkey format**: 33-byte compressed public key (starts with `0x02` or `0x03`) 2. **SCID+DIR format**: 9-byte short channel ID with direction (starts with `0x00` or `0x01`) ### Wire Format Change **v24.02 wire definition** (`wire/onion_wire.csv`): ``` subtypedata,blinded_path,first_node_id,point, ``` **Current wire definition** (after May 2024): ``` subtypedata,blinded_path,first_node_id,sciddir_or_pubkey, ``` In v24.02, the parser expected a 33-byte `point` (pubkey). When it encountered an offer using the SCID format, the TLV deserialization failed because the data structure didn't match the expected format. ### Evidence from Offer Analysis **Failing Offer** (cannot be decoded in v24.02): ``` offer_paths first byte: 0x01 (SCID+DIR format) Direction: 1 SCID: 851467x1143x0 ``` **Working Offer** (can be decoded in v24.02): ``` offer_paths first byte: 0x03 (PUBKEY format) first_node_id: 038a9e56512ec98da2b5789761f7af8f280baf98a09282360cd6ff1381b5e889bf ``` ### TLV Structure Comparison | Field | Failing Offer | Working Offer | |-------|--------------|---------------| | `offer_description` | OCEAN Payouts for bc1q4wat... | OCEAN Payouts for bc1qdf3j... | | `offer_paths` format | **SCID+DIR** | **PUBKEY** | | `offer_paths` first byte | `0x01` | `0x03` | | `offer_issuer_id` | Not present (allowed with blinded paths) | Present | ## The Fix ### Commit Details **Commit**: `cb2c4963f23275bf1446370be12d0ad1f051f9e2` **Date**: May 9, 2024 **Author**: Rusty Russell **Message**: "bolt12: allow first_node_id in blinded path to be a scid." This commit: 1. Changed the wire type from `point` to `sciddir_or_pubkey` 2. Updated JSON parsing to handle both formats 3. Added `first_scid` and `first_scid_dir` fields to the decode output ### Related Commits | Commit | Date | Description | |--------|------|-------------| | `cb2c4963f` | May 2024 | Allow SCID in blinded path first_node_id | | `d74079513` | Aug 2024 | Allow missing offer_issuer_id with blinded paths | | `2ecf5e6bd` | 2024 | Reject zero-length blinded paths | ## Impact ### Affected Offers Offers created by implementations that use the newer BOLT12 SCID format for blinded paths cannot be decoded or paid by CLN v24.02. This includes offers from: - LDK-based wallets (e.g., AlbyHub) that implement the updated spec - Any implementation using SCIDs for compact blinded path encoding ### User Experience Users on v24.02 attempting to pay these offers will see cryptic "invalid token" errors, with no indication that the issue is a version incompatibility. ## Recommendation Users experiencing this issue should upgrade to CLN v24.05 or later. ## Test Cases ### Failing Offer (SCID format) ``` lno1pg7y7s69g98zq5rp09hh2arnypnx7u3qvf3nzuf5washgcmvxf6xgv3kwa4njaekxpmxz6nrxcmhzvm5v4enjcmvxekrvan4dgcpplgptyqselstqqz8wqqqqdn0w5mmyp3w8u tg0lr84qxn2eg6fe583pv0eg0dqs05t59c5yctwqszdne6syjug0rkmzdq3pukg2ngw0aca37pz8n886g73mfxp2uldrrsqaz4xvkz5p352vm39rertccwr9yk4k7zz0fasyhwsmwu 8dtr3cpn4d757rlcy29lyfjn30mfjgtcz870ykzkha99qq3d2r8aq73hahjr58twu4stlq459czerqfkkj98qw7ajq5azwy4hhchpk6f8uzhx5h9g8srmthaq4m44cmkcgkrheurx9 kp5xzlqt3p88jd6kvz0df8r6h87y537ahs50jnenhs32cuy84j87lr4aq96qr5q28v0v2hrnhwwlwevkc0wnyd9jeq26zcyz0d4m3pzx3zl7qnkhf6vmwtxejt8ly973rkaztpzf6f dyntfr7cxlwy7cr6ypjy6qhedgn4jfcej0wmlneuzkf2td68qwpygdnkk48m9d278phhxhzpu2w2kmh8szspdmldq54ecn5strqwfy8tuaez7stzzq73nqa4nd85qqvngy09zk8ymf laclthd0969pw332eepeq9qwqac5 ``` ### Working Offer (Pubkey format) ``` lno1pg7y7s69g98zq5rp09hh2arnypnx7u3qvf3nzutyvcek5dt60fuxv7ndxp6nvwrdvy6xgee4vem8vansxuex5ums0gux2mpswpn3p6qr3209v5fwexx69dtcjasl0tu09q96lx 9qj2prvrxklufcrd0g3xls804j25ns7wugmevv4s8yr5lnwu0dzy2hx4tunxyqjx68wu3sznx4qgp7q20g92z50ajt04xprfvvnr08xc4e2c4w0xv06x7jyeux6gc2xgsqxddd04f9 eqc34jgzhhzcauqp2dftpcsqehv24xwngps4utfg24p9sd2aftxxfng58r7xpk5l45k0nl5uhkfs8r6amjk9ae8q63pnhj9u8j7lkpywhdhqqzkj0an5q8cz7tww7xfsqqk877gc9a jgtcdunnz0e5ahaquqchp46ag5mlrdu5ry0w8z80g99dtwsg3khwqfy8jcfdrvwstzzqktvhhg7flqcnjg0g88wd0h5ldkpkxjafr272s5swqpx6p33wh78u ``` ## References - Commit cb2c4963f: https://github.com/ElementsProject/lightning/commit/cb2c4963f - Commit d74079513: https://github.com/ElementsProject/lightning/commit/d74079513 - BOLT12 Specification: https://github.com/lightning/bolts/blob/master/12-offer-encoding.md ``` ➜ ~ lightning-cli decode lno1pg7y7s69g98zq5rp09hh2arnypnx7u3qvf3nzutyvcek5dt60fuxv7ndxp6nvwrdvy6xgee4vem8vansxuex5ums0gux2mpswpn3p6qr3209v5fwexx69dtcjasl0tu09q96lx9qj2prvrxklufcrd0g3xls804j25ns7wugmevv4s8yr5lnwu0dzy2hx4tunxyqjx68wu3sznx4qgp7q20g92z50ajt04xprfvvnr08xc4e2c4w0xv06x7jyeux6gc2xgsqxddd04f9eqc34jgzhhzcauqp2dftpcsqehv24xwngps4utfg24p9sd2aftxxfng58r7xpk5l45k0nl5uhkfs8r6amjk9ae8q63pnhj9u8j7lkpywhdhqqzkj0an5q8cz7tww7xfsqqk877gc9ajgtcdunnz0e5ahaquqchp46ag5mlrdu5ry0w8z80g99dtwsg3khwqfy8jcfdrvwstzzqktvhhg7flqcnjg0g88wd0h5ldkpkxjafr272s5swqpx6p33wh78u { "type": "bolt12 offer", "offer_id": "99f4e1eb167a5bf337d010ed3c73aaec779e90327126330247cf1ac25eecb3c9", "offer_description": "OCEAN Payouts for bc1qdf3j5zzxfzm0u68ma4dg5fvvvp72jspz8el0pg", "offer_paths": [ { "first_node_id": "038a9e56512ec98da2b5789761f7af8f280baf98a09282360cd6ff1381b5e889bf", "blinding": "03beb255270f3b88de58cac0e41d3f3771ed111573557c9988091b477723014cd5", "first_path_key": "03beb255270f3b88de58cac0e41d3f3771ed111573557c9988091b477723014cd5", "path": [ { "blinded_node_id": "03e029e82a8547f64b7d4c11a58c98de7362b9562ae7998fd1bd226786d230a322", "encrypted_recipient_data": "5ad7d525c8311ac902bdc58ef0015352b0e200cdd8aa99d340615e2d28554258355d4acc64cd1438fc60da9fad2cf9fe9cbd93" }, { "blinded_node_id": "038f5ddcac5ee4e0d4433bc8bc3cbdfb048ebb6e000ad27f67401f02f2dcef1930", "encrypted_recipient_data": "7f79182f6485e1bc9cc4fcd3b7e8380c5c35d7514dfc6de50647b8e23bd052b56e82236bb80921e584b46c74" } ] } ], "offer_issuer_id": "02cb65ee8f27e0c4e487a0e7735f7a7db60d8d2ea46af2a1483801368318bafe3f", "valid": true } ➜ ~ lightning-cli decode lno1pg7y7s69g98zq5rp09hh2arnypnx7u3qvf3nzuf5washgcmvxf6xgv3kwa4njaekxpmxz6nrxcmhzvm5v4enjcmvxekrvan4dgcpplgptyqselstqqz8wqqqqdn0w5mmyp3w8utg0lr84qxn2eg6fe583pv0eg0dqs05t59c5yctwqszdne6syjug0rkmzdq3pukg2ngw0aca37pz8n886g73mfxp2uldrrsqaz4xvkz5p352vm39rertccwr9yk4k7zz0fasyhwsmwu8dtr3cpn4d757rlcy29lyfjn30mfjgtcz870ykzkha99qq3d2r8aq73hahjr58twu4stlq459czerqfkkj98qw7ajq5azwy4hhchpk6f8uzhx5h9g8srmthaq4m44cmkcgkrheurx9kp5xzlqt3p88jd6kvz0df8r6h87y537ahs50jnenhs32cuy84j87lr4aq96qr5q28v0v2hrnhwwlwevkc0wnyd9jeq26zcyz0d4m3pzx3zl7qnkhf6vmwtxejt8ly973rkaztpzf6fdyntfr7cxlwy7cr6ypjy6qhedgn4jfcej0wmlneuzkf2td68qwpygdnkk48m9d278phhxhzpu2w2kmh8szspdmldq54ecn5strqwfy8tuaez7stzzq73nqa4nd85qqvngy09zk8ymflaclthd0969pw332eepeq9qwqac5 { "type": "bolt12 offer", "offer_id": "306d60ed6977f257f692ee3f7a546a0521d82ef12752121a57a0e02d636d4fb5", "offer_description": "OCEAN Payouts for bc1q4watcl2td26wk9w60vajc67q3tes9cl6l6vuj0", "offer_paths": [ { "first_scid": "851467x1143x0", "first_scid_dir": 1, "blinding": "0366f7537b2062e3f1687fc67a80d35651a4e6878858fca1ed041f45d0b8a130b7", "first_path_key": "0366f7537b2062e3f1687fc67a80d35651a4e6878858fca1ed041f45d0b8a130b7", "path": [ { "blinded_node_id": "026cf3a8125c43c76d89a08879642a6873fb8ec7c111e673e91e8ed260ab9f68c7", "encrypted_recipient_data": "55332c2a06345337128f235e30e19496adbc213d3d812ee86ddc3b5638e033ab7d4f0ff8228bf226538bf699217811fcf25856bf4a50022d50cfd07a37ede43a1d6ee560bf82b42e05918136b48a703bdd9029d13895bdf170db493f057352e541e03daefd05775ae376c22c3be783316c1a185f" }, { "blinded_node_id": "02e2139e4dd59827b5271eae7f1291f76f0a3e53ccef08ab1c21eb23fbe3af405d", "encrypted_recipient_data": "028ec7b1571ceee77dd965b0f74c8d2cb2056858209edaee2111a22ff813b5d3a66dcb3664b3fc85f4476e8961127496926b48fd837dc4f607a20644d02f96a2759271993ddbfcf3c1592a5b7470382443676b54fb2b55e386f735c41e29cab6ee780a016efed052b9c4e9058c0e490ebe7722f4" } ] } ], "offer_issuer_id": "03d1983b59b4f400193411e5158e4da7fdc7d776bcba285d18ab390e4050381dc5", "valid": true } ``` --- Suggested Workaround (To Be Confirmed) For Users on CLN v24.02 Who Cannot Upgrade If you're receiving payments via BOLT12 offers from LDK-based wallets (e.g., AlbyHub) and cannot upgrade to v24.05+: Option 1: Use Private Channels (Recipient Side) The recipient (AlbyHub/LDK wallet) should ensure their Lightning channel is private/unannounced: - When LDK creates a blinded path using a private channel, it encodes the introduction point as a pubkey (33 bytes) - When LDK creates a blinded path using a public channel, it encodes the introduction point as an SCID (9 bytes) In AlbyHub, this typically means: - Opening channels with announce=false (private) - Or using LSP channels which are often private by default Option 2: Upgrade (Recommended) The proper fix is to upgrade to CLN v24.05 or later, which correctly handles both SCID and pubkey formats in blinded paths. --- Confirmation Needed To confirm this workaround: 1. Have an AlbyHub user with a private channel generate an offer 2. Verify the offer uses first_node_id (pubkey) instead of first_scid 3. Test that CLN v24.02 can decode and pay this offer This would validate that the channel visibility (public vs private) is indeed what determines LDK's choice of encoding format.