README.md (4804B)
1 # ppad-bolt7 2 3 [](https://hackage.haskell.org/package/ppad-bolt7) 4  5 [](https://docs.ppad.tech/bolt7) 6 7 A pure Haskell implementation of Lightning Network routing gossip, 8 [BOLT #7][bolt7]: the `channel_announcement`, `node_announcement`, 9 `channel_update` and `announcement_signatures` messages, the gossip 10 queries, signature digests and verification, and `channel_update` 11 checksums. 12 13 Decoding keeps every byte of a message (unassigned flag bits, unknown 14 address descriptors, extension TLV records), so a decoded message 15 re-encodes exactly and its signatures still verify. 16 17 ## Usage 18 19 A sample GHCi session: 20 21 ``` 22 > :set -XOverloadedStrings 23 > import qualified Data.ByteString as BS 24 > import qualified Data.ByteString.Base16 as B16 25 > import qualified Lightning.Protocol.BOLT1 as BOLT1 26 > import Lightning.Protocol.BOLT7 27 > 28 > -- a channel_update payload from mainnet gossip 29 > :{ 30 | let Just wire = B16.decode $ mconcat 31 | [ "1c3f0859cb3f4494919c3dcc80d22bbf1e25e378bd95f071530833c2371c33d7" 32 | , "0766012ebef1cd79b299a54d0d29bea2ef6feca1d6cfa188864c95d7eea7e9a4" 33 | , "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000" 34 | , "0cf884000bb000016a0a1c760100006400000000000003e80000000000001388" 35 | , "00000000b1069a80fdd9030800000000ffffffed" ] 36 | :} 37 > let Right upd = decode_channel_update wire 38 > format_short_channel_id (cu_short_channel_id upd) 39 "850052x2992x1" 40 > channel_flags_direction (cu_channel_flags upd) 41 NodeOne 42 > cu_fee_proportional_millionths upd 43 5000 44 > 45 > -- extension records (here LND's inbound fees) are kept, so the 46 > -- update re-encodes exactly and its signature verifies 47 > BOLT1.un_tlv_stream (cu_tlvs upd) 48 [TlvRecord {tlv_type = 55555, tlv_value = "\NUL\NUL\NUL\NUL\255\255\255\237"}] 49 > encode_channel_update upd == wire 50 True 51 > :{ 52 | let Just node_1 = BOLT1.point =<< B16.decode 53 | "02bb5e47ee26aca1654ce092d9d06eac15d953210c737f2220e2d7e54c4f108677" 54 | :} 55 > verify_channel_update node_1 upd 56 True 57 > verify_channel_update node_1 upd { cu_fee_base_msat = 1 } 58 False 59 > 60 > -- dispatch on a message type, as split off by BOLT1.decode_envelope 61 > fmap message_type (decode_message 258 wire) 62 Right 258 63 > 64 > -- gossip queries have typed fields 65 > let Just chain = BOLT1.chain_hash (BS.replicate 32 0) 66 > let opt = Just (query_option [WantTimestamps]) 67 > let q = QueryChannelRange chain 800000 1000 opt BOLT1.empty_tlv_stream 68 > let Right payload = encode_query_channel_range q 69 > decode_query_channel_range payload == Right q 70 True 71 > 72 > -- the deprecated zlib encoding is rejected 73 > decode_reply_channel_range (BS.replicate 41 0 <> "\NUL\STX\SOHx") 74 Left (DecodeUnknownEncoding 1) 75 ``` 76 77 ## Documentation 78 79 Haddocks (API documentation, etc.) are hosted at 80 [docs.ppad.tech/bolt7](https://docs.ppad.tech/bolt7). 81 82 ## Specification 83 84 This library implements BOLT #7 as of lightning/bolts commit 85 [1aadb719][spec] (2026-09-21); a copy lives in `etc/`. Fundamental 86 types come from [ppad-bolt1][bolt1] and feature vectors from 87 [ppad-bolt9][bolt9]. 88 89 Not implemented: 90 91 * The zlib encoding (type 1) of `encoded_short_ids` and its kin, which 92 the specification forbids; messages using it fail to decode. 93 * Signing. The digest functions give what a node signs, with e.g. 94 [ppad-secp256k1][secp], to create announcements and updates. 95 * Rules that need state or chain access: timestamp ordering, 96 blacklisting, funding output checks, chain hash filtering, rebroadcast 97 and pruning policy. Feature-bit rules are left to ppad-bolt9. 98 99 Checksums cover a `channel_update`'s extension records, per the 100 specification's wording. 101 102 ## Performance 103 104 The aim is best-in-class performance for pure Haskell code. Run the 105 benchmarks with: 106 107 ``` 108 $ cabal bench 109 ``` 110 111 ## Security 112 113 This library has received no security audit. Decoding validates every 114 field the specification constrains, and rejects unknown even TLV types. 115 Signature verification uses ppad-secp256k1 and, like libsecp256k1, 116 accepts only low-s signatures. 117 118 ## Development 119 120 You'll require [Nix][nixos] with [flake][flake] support enabled. Enter a 121 development shell with: 122 123 ``` 124 $ nix develop 125 ``` 126 127 Then do e.g.: 128 129 ``` 130 $ cabal repl ppad-bolt7 131 ``` 132 133 to get a REPL for the main library. 134 135 [bolt7]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md 136 [bolt1]: https://git.ppad.tech/bolt1 137 [bolt9]: https://git.ppad.tech/bolt9 138 [secp]: https://git.ppad.tech/secp256k1 139 [spec]: https://github.com/lightning/bolts/tree/1aadb719b4007c4cea0ba6e36b08c4fb53788dee 140 [nixos]: https://nixos.org/ 141 [flake]: https://nixos.org/manual/nix/unstable/command-ref/new-cli/nix3-flake.html