bolt7

Routing gossip protocol, per BOLT #7 (docs.ppad.tech/bolt7).
git clone git://git.ppad.tech/bolt7.git
Log | Files | Refs | README | LICENSE

Codec.hs (25538B)


      1 {-# OPTIONS_HADDOCK hide #-}
      2 {-# LANGUAGE BangPatterns #-}
      3 {-# LANGUAGE DeriveGeneric #-}
      4 
      5 -- |
      6 -- Module: Lightning.Protocol.BOLT7.Codec
      7 -- Copyright: (c) 2025 Jared Tobin
      8 -- License: MIT
      9 -- Maintainer: Jared Tobin <jared@ppad.tech>
     10 --
     11 -- Encoding and decoding of BOLT #7 messages.
     12 
     13 module Lightning.Protocol.BOLT7.Codec (
     14     EncodeError(..)
     15   , DecodeError(..)
     16   , encode_message
     17   , decode_message
     18   , encode_channel_announcement
     19   , decode_channel_announcement
     20   , encode_node_announcement
     21   , decode_node_announcement
     22   , encode_channel_update
     23   , decode_channel_update
     24   , encode_announcement_signatures
     25   , decode_announcement_signatures
     26   , encode_query_short_channel_ids
     27   , decode_query_short_channel_ids
     28   , encode_reply_short_channel_ids_end
     29   , decode_reply_short_channel_ids_end
     30   , encode_query_channel_range
     31   , decode_query_channel_range
     32   , encode_reply_channel_range
     33   , decode_reply_channel_range
     34   , encode_gossip_timestamp_filter
     35   , decode_gossip_timestamp_filter
     36   ) where
     37 
     38 import Control.DeepSeq (NFData)
     39 import qualified Data.ByteString as BS
     40 import Data.Word (Word8, Word16, Word32, Word64)
     41 import GHC.Generics (Generic)
     42 import Lightning.Protocol.BOLT1
     43   ( ChainHash, MilliSatoshi, Point, ShortChannelId, Signature
     44   , TlvError, TlvRecord(..), TlvStream )
     45 import qualified Lightning.Protocol.BOLT1 as BOLT1
     46 import qualified Lightning.Protocol.BOLT9 as BOLT9
     47 import Lightning.Protocol.BOLT7.Messages
     48 import Lightning.Protocol.BOLT7.Types
     49 
     50 -- errors ---------------------------------------------------------------------
     51 
     52 -- | Why a message failed to encode.
     53 data EncodeError
     54   = EncodeLengthOverflow
     55     -- ^ a length-prefixed field exceeds 65535 bytes
     56   | EncodeInvalidTlvs
     57     -- ^ a @_tlvs@ field holds a record of a type the message defines
     58   | EncodeCountMismatch
     59     -- ^ query flags, timestamps or checksums don't number one per
     60     --   short channel id
     61   | EncodeInvalidAddresses
     62     -- ^ 'na_unknown_addresses' begins with a descriptor of a known type
     63   deriving (Eq, Show, Generic)
     64 
     65 instance NFData EncodeError
     66 
     67 -- | Why a message failed to decode.
     68 data DecodeError
     69   = DecodeInsufficientBytes
     70     -- ^ the input ended before a field did
     71   | DecodeInvalidPoint
     72     -- ^ a point lacks a compressed-encoding prefix (0x02 or 0x03)
     73   | DecodeInvalidAmount
     74     -- ^ an amount exceeds 21 million BTC
     75   | DecodeInvalidBool
     76     -- ^ a boolean byte is neither 0 nor 1
     77   | DecodeInvalidShortChannelIds
     78     -- ^ @encoded_short_ids@ lacks an encoding type, or isn't a whole
     79     --   number of short channel ids
     80   | DecodeUnknownEncoding !Word8
     81     -- ^ an encoded array uses an unknown encoding type (type 1, zlib,
     82     --   is no longer allowed)
     83   | DecodeCountMismatch
     84     -- ^ query flags, timestamps or checksums don't number one per
     85     --   short channel id
     86   | DecodeTlvError !TlvError
     87     -- ^ the message's TLV stream is malformed
     88   | DecodeInvalidTlvValue !Word64
     89     -- ^ a known TLV record (of the given type) has a malformed value
     90   | DecodeUnknownType !Word16
     91     -- ^ the message type is not one of BOLT #7's
     92   deriving (Eq, Show, Generic)
     93 
     94 instance NFData DecodeError
     95 
     96 -- messages -------------------------------------------------------------------
     97 
     98 -- | Encode a 'Message' payload (excluding the 2-byte message type; see
     99 --   'message_type'). Frame the result with
    100 --   'Lightning.Protocol.BOLT1.encode_envelope', which enforces the
    101 --   65535-byte message limit.
    102 encode_message :: Message -> Either EncodeError BS.ByteString
    103 encode_message m = case m of
    104   MsgChannelAnnouncement a     -> encode_channel_announcement a
    105   MsgNodeAnnouncement a        -> encode_node_announcement a
    106   MsgChannelUpdate a           -> Right (encode_channel_update a)
    107   MsgAnnouncementSignatures a  -> Right (encode_announcement_signatures a)
    108   MsgQueryShortChannelIds a    -> encode_query_short_channel_ids a
    109   MsgReplyShortChannelIdsEnd a -> Right (encode_reply_short_channel_ids_end a)
    110   MsgQueryChannelRange a       -> encode_query_channel_range a
    111   MsgReplyChannelRange a       -> encode_reply_channel_range a
    112   MsgGossipTimestampFilter a   -> Right (encode_gossip_timestamp_filter a)
    113 
    114 -- | Decode a message payload, given its message type (as split off by
    115 --   'Lightning.Protocol.BOLT1.decode_envelope').
    116 --
    117 --   >>> decode_message 260 "\NUL"
    118 --   Left (DecodeUnknownType 260)
    119 decode_message :: Word16 -> BS.ByteString -> Either DecodeError Message
    120 decode_message t bs = case t of
    121   256 -> MsgChannelAnnouncement <$> decode_channel_announcement bs
    122   257 -> MsgNodeAnnouncement <$> decode_node_announcement bs
    123   258 -> MsgChannelUpdate <$> decode_channel_update bs
    124   259 -> MsgAnnouncementSignatures <$> decode_announcement_signatures bs
    125   261 -> MsgQueryShortChannelIds <$> decode_query_short_channel_ids bs
    126   262 -> MsgReplyShortChannelIdsEnd <$> decode_reply_short_channel_ids_end bs
    127   263 -> MsgQueryChannelRange <$> decode_query_channel_range bs
    128   264 -> MsgReplyChannelRange <$> decode_reply_channel_range bs
    129   265 -> MsgGossipTimestampFilter <$> decode_gossip_timestamp_filter bs
    130   _   -> Left (DecodeUnknownType t)
    131 
    132 -- channel_announcement -------------------------------------------------------
    133 
    134 -- | Encode a t'ChannelAnnouncement' payload. Fails if the features exceed
    135 --   65535 bytes.
    136 encode_channel_announcement
    137   :: ChannelAnnouncement -> Either EncodeError BS.ByteString
    138 encode_channel_announcement m = do
    139   f <- prefixed (BOLT9.render (ca_features m))
    140   pure $ mconcat
    141     [ BOLT1.un_signature (ca_node_signature_1 m)
    142     , BOLT1.un_signature (ca_node_signature_2 m)
    143     , BOLT1.un_signature (ca_bitcoin_signature_1 m)
    144     , BOLT1.un_signature (ca_bitcoin_signature_2 m)
    145     , f
    146     , BOLT1.un_chain_hash (ca_chain_hash m)
    147     , BOLT1.encode_short_channel_id (ca_short_channel_id m)
    148     , BOLT1.un_point (ca_node_id_1 m)
    149     , BOLT1.un_point (ca_node_id_2 m)
    150     , BOLT1.un_point (ca_bitcoin_key_1 m)
    151     , BOLT1.un_point (ca_bitcoin_key_2 m)
    152     , BOLT1.encode_tlv_stream (ca_tlvs m)
    153     ]
    154 
    155 -- | Decode a t'ChannelAnnouncement' payload.
    156 decode_channel_announcement
    157   :: BS.ByteString -> Either DecodeError ChannelAnnouncement
    158 decode_channel_announcement b0 = do
    159   (ns1, b1)  <- signature b0
    160   (ns2, b2)  <- signature b1
    161   (bs1, b3)  <- signature b2
    162   (bs2, b4)  <- signature b3
    163   (f, b5)    <- u16_prefixed b4
    164   (ch, b6)   <- chain_hash b5
    165   (s, b7)    <- short_channel_id b6
    166   (n1, b8)   <- point b7
    167   (n2, b9)   <- point b8
    168   (bk1, b10) <- point b9
    169   (bk2, b11) <- point b10
    170   ext        <- extension b11
    171   pure ChannelAnnouncement
    172     { ca_node_signature_1    = ns1
    173     , ca_node_signature_2    = ns2
    174     , ca_bitcoin_signature_1 = bs1
    175     , ca_bitcoin_signature_2 = bs2
    176     , ca_features            = BOLT9.parse f
    177     , ca_chain_hash          = ch
    178     , ca_short_channel_id    = s
    179     , ca_node_id_1           = n1
    180     , ca_node_id_2           = n2
    181     , ca_bitcoin_key_1       = bk1
    182     , ca_bitcoin_key_2       = bk2
    183     , ca_tlvs                = ext
    184     }
    185 
    186 -- node_announcement ----------------------------------------------------------
    187 
    188 -- | Encode a t'NodeAnnouncement' payload. Fails if the features or the
    189 --   addresses exceed 65535 bytes, or if 'na_unknown_addresses' begins
    190 --   with a descriptor of a known type.
    191 encode_node_announcement
    192   :: NodeAnnouncement -> Either EncodeError BS.ByteString
    193 encode_node_announcement m = do
    194   f <- prefixed (BOLT9.render (na_features m))
    195   let unknown = na_unknown_addresses m
    196   case BS.uncons unknown of
    197     Just (t, _) | t >= 1 && t <= 5 -> Left EncodeInvalidAddresses
    198     _ -> pure ()
    199   as <- prefixed (foldMap encode_address (na_addresses m) <> unknown)
    200   let RgbColor r g b = na_rgb_color m
    201       Alias al = na_alias m
    202   pure $ mconcat
    203     [ BOLT1.un_signature (na_signature m)
    204     , f
    205     , BOLT1.encode_u32 (na_timestamp m)
    206     , BOLT1.un_point (na_node_id m)
    207     , BS.pack [r, g, b]
    208     , al
    209     , as
    210     , BOLT1.encode_tlv_stream (na_tlvs m)
    211     ]
    212 
    213 encode_address :: Address -> BS.ByteString
    214 encode_address a = case a of
    215   AddrIPv4 (IPv4Addr b) p   -> BS.cons 1 (b <> BOLT1.encode_u16 p)
    216   AddrIPv6 (IPv6Addr b) p   -> BS.cons 2 (b <> BOLT1.encode_u16 p)
    217   AddrTorV2 (TorV2Addr b)   -> BS.cons 3 b
    218   AddrTorV3 (TorV3Addr b) p -> BS.cons 4 (b <> BOLT1.encode_u16 p)
    219   AddrDNS (Hostname h) p    ->
    220     BS.cons 5 (BS.cons (fromIntegral (BS.length h)) (h <> BOLT1.encode_u16 p))
    221 
    222 -- | Decode a t'NodeAnnouncement' payload.
    223 --
    224 --   Address descriptors are parsed up to the first one of an unknown
    225 --   type; it and the bytes after it are kept in 'na_unknown_addresses'.
    226 --   A truncated descriptor of a known type is an error.
    227 decode_node_announcement
    228   :: BS.ByteString -> Either DecodeError NodeAnnouncement
    229 decode_node_announcement b0 = do
    230   (sig, b1) <- signature b0
    231   (f, b2)   <- u16_prefixed b1
    232   (ts, b3)  <- u32 b2
    233   (nid, b4) <- point b3
    234   (r, b5)   <- u8 b4
    235   (g, b6)   <- u8 b5
    236   (b, b7)   <- u8 b6
    237   (al, b8)  <- bytes 32 b7
    238   (as, b9)  <- u16_prefixed b8
    239   (known, unknown) <- addresses as
    240   ext <- extension b9
    241   pure NodeAnnouncement
    242     { na_signature         = sig
    243     , na_features          = BOLT9.parse f
    244     , na_timestamp         = ts
    245     , na_node_id           = nid
    246     , na_rgb_color         = RgbColor r g b
    247     , na_alias             = Alias al
    248     , na_addresses         = known
    249     , na_unknown_addresses = unknown
    250     , na_tlvs              = ext
    251     }
    252 
    253 -- parse address descriptors, stopping at the first of an unknown type
    254 addresses
    255   :: BS.ByteString -> Either DecodeError ([Address], BS.ByteString)
    256 addresses = go []
    257   where
    258     go !acc !bs = case BS.uncons bs of
    259       Nothing -> Right (reverse acc, BS.empty)
    260       Just (t, r) -> case t of
    261         1 -> with_port acc 4 (AddrIPv4 . IPv4Addr) r
    262         2 -> with_port acc 16 (AddrIPv6 . IPv6Addr) r
    263         3 -> do
    264           (a, r1) <- bytes 12 r
    265           go (AddrTorV2 (TorV2Addr a) : acc) r1
    266         4 -> with_port acc 35 (AddrTorV3 . TorV3Addr) r
    267         5 -> do
    268           (n, r1) <- u8 r
    269           (h, r2) <- bytes (fromIntegral n) r1
    270           (p, r3) <- u16 r2
    271           go (AddrDNS (Hostname h) p : acc) r3
    272         _ -> Right (reverse acc, bs)
    273 
    274     with_port acc n mk r = do
    275       (a, r1) <- bytes n r
    276       (p, r2) <- u16 r1
    277       go (mk a p : acc) r2
    278 
    279 -- channel_update -------------------------------------------------------------
    280 
    281 -- | Encode a t'ChannelUpdate' payload.
    282 encode_channel_update :: ChannelUpdate -> BS.ByteString
    283 encode_channel_update m =
    284   let MessageFlags mf = cu_message_flags m
    285       ChannelFlags cf = cu_channel_flags m
    286   in  mconcat
    287         [ BOLT1.un_signature (cu_signature m)
    288         , BOLT1.un_chain_hash (cu_chain_hash m)
    289         , BOLT1.encode_short_channel_id (cu_short_channel_id m)
    290         , BOLT1.encode_u32 (cu_timestamp m)
    291         , BS.pack [mf, cf]
    292         , BOLT1.encode_u16 (cu_cltv_expiry_delta m)
    293         , BOLT1.encode_milli_satoshi (cu_htlc_minimum_msat m)
    294         , BOLT1.encode_u32 (cu_fee_base_msat m)
    295         , BOLT1.encode_u32 (cu_fee_proportional_millionths m)
    296         , BOLT1.encode_milli_satoshi (cu_htlc_maximum_msat m)
    297         , BOLT1.encode_tlv_stream (cu_tlvs m)
    298         ]
    299 
    300 -- | Decode a t'ChannelUpdate' payload.
    301 --
    302 --   @htlc_maximum_msat@ is always present; the @must_be_one@ bit of
    303 --   @message_flags@ is kept but not interpreted.
    304 decode_channel_update :: BS.ByteString -> Either DecodeError ChannelUpdate
    305 decode_channel_update b0 = do
    306   (sig, b1)   <- signature b0
    307   (ch, b2)    <- chain_hash b1
    308   (s, b3)     <- short_channel_id b2
    309   (ts, b4)    <- u32 b3
    310   (mf, b5)    <- u8 b4
    311   (cf, b6)    <- u8 b5
    312   (cltv, b7)  <- u16 b6
    313   (hmin, b8)  <- milli_satoshi b7
    314   (fb, b9)    <- u32 b8
    315   (fp, b10)   <- u32 b9
    316   (hmax, b11) <- milli_satoshi b10
    317   ext         <- extension b11
    318   pure ChannelUpdate
    319     { cu_signature                   = sig
    320     , cu_chain_hash                  = ch
    321     , cu_short_channel_id            = s
    322     , cu_timestamp                   = ts
    323     , cu_message_flags               = MessageFlags mf
    324     , cu_channel_flags               = ChannelFlags cf
    325     , cu_cltv_expiry_delta           = cltv
    326     , cu_htlc_minimum_msat           = hmin
    327     , cu_fee_base_msat               = fb
    328     , cu_fee_proportional_millionths = fp
    329     , cu_htlc_maximum_msat           = hmax
    330     , cu_tlvs                        = ext
    331     }
    332 
    333 -- announcement_signatures ----------------------------------------------------
    334 
    335 -- | Encode an t'AnnouncementSignatures' payload.
    336 encode_announcement_signatures :: AnnouncementSignatures -> BS.ByteString
    337 encode_announcement_signatures m = mconcat
    338   [ BOLT1.un_channel_id (as_channel_id m)
    339   , BOLT1.encode_short_channel_id (as_short_channel_id m)
    340   , BOLT1.un_signature (as_node_signature m)
    341   , BOLT1.un_signature (as_bitcoin_signature m)
    342   , BOLT1.encode_tlv_stream (as_tlvs m)
    343   ]
    344 
    345 -- | Decode an t'AnnouncementSignatures' payload.
    346 decode_announcement_signatures
    347   :: BS.ByteString -> Either DecodeError AnnouncementSignatures
    348 decode_announcement_signatures b0 = do
    349   (cid, b1) <- need (BOLT1.decode_channel_id b0)
    350   (s, b2)   <- short_channel_id b1
    351   (ns, b3)  <- signature b2
    352   (bs, b4)  <- signature b3
    353   ext       <- extension b4
    354   pure (AnnouncementSignatures cid s ns bs ext)
    355 
    356 -- query_short_channel_ids ----------------------------------------------------
    357 
    358 -- | Encode a t'QueryShortChannelIds' payload. Fails if the short channel
    359 --   ids exceed the u16 length limit (8191 of them), if the query flags
    360 --   don't number one per short channel id, or if 'qsci_tlvs' holds a
    361 --   record of type 1.
    362 encode_query_short_channel_ids
    363   :: QueryShortChannelIds -> Either EncodeError BS.ByteString
    364 encode_query_short_channel_ids m = do
    365   let scids = qsci_short_channel_ids m
    366   ids <- prefixed (encode_short_ids scids)
    367   flags <- case qsci_query_flags m of
    368     Nothing -> pure []
    369     Just fs
    370       | length fs /= length scids -> Left EncodeCountMismatch
    371       | otherwise -> pure
    372           [TlvRecord 1 (BS.cons 0 (foldMap (\(QueryFlags w) ->
    373                                        BOLT1.encode_bigsize w) fs))]
    374   t <- merge [1] flags (qsci_tlvs m)
    375   pure (BOLT1.un_chain_hash (qsci_chain_hash m) <> ids <> t)
    376 
    377 -- | Decode a t'QueryShortChannelIds' payload.
    378 --
    379 --   Fails on an unknown encoding type (including the deprecated zlib
    380 --   encoding), on @encoded_short_ids@ that isn't a whole number of short
    381 --   channel ids, and on query flags that don't number one per short
    382 --   channel id.
    383 --
    384 --   >>> let zlib = BS.replicate 32 0 <> "\NUL\STX\SOHx"
    385 --   >>> decode_query_short_channel_ids zlib
    386 --   Left (DecodeUnknownEncoding 1)
    387 decode_query_short_channel_ids
    388   :: BS.ByteString -> Either DecodeError QueryShortChannelIds
    389 decode_query_short_channel_ids b0 = do
    390   (ch, b1)  <- chain_hash b0
    391   (ids, b2) <- u16_prefixed b1
    392   scids     <- short_ids ids
    393   s         <- tlvs [1] b2
    394   flags     <- traverse (query_flags_value (length scids))
    395                  (BOLT1.lookup_tlv 1 s)
    396   pure QueryShortChannelIds
    397     { qsci_chain_hash        = ch
    398     , qsci_short_channel_ids = scids
    399     , qsci_query_flags       = flags
    400     , qsci_tlvs              = BOLT1.filter_tlv_stream (/= 1) s
    401     }
    402 
    403 query_flags_value :: Int -> BS.ByteString -> Either DecodeError [QueryFlags]
    404 query_flags_value n v = case BS.uncons v of
    405   Nothing -> Left (DecodeInvalidTlvValue 1)
    406   Just (0, r) -> do
    407     fs <- bigsizes r
    408     if length fs /= n
    409       then Left DecodeCountMismatch
    410       else Right (map QueryFlags fs)
    411   Just (e, _) -> Left (DecodeUnknownEncoding e)
    412   where
    413     bigsizes !r
    414       | BS.null r = Right []
    415       | otherwise = case BOLT1.decode_bigsize r of
    416           Nothing      -> Left (DecodeInvalidTlvValue 1)
    417           Just (w, r1) -> (w :) <$> bigsizes r1
    418 
    419 -- reply_short_channel_ids_end ------------------------------------------------
    420 
    421 -- | Encode a t'ReplyShortChannelIdsEnd' payload.
    422 encode_reply_short_channel_ids_end
    423   :: ReplyShortChannelIdsEnd -> BS.ByteString
    424 encode_reply_short_channel_ids_end m = mconcat
    425   [ BOLT1.un_chain_hash (rsce_chain_hash m)
    426   , encode_bool (rsce_full_information m)
    427   , BOLT1.encode_tlv_stream (rsce_tlvs m)
    428   ]
    429 
    430 -- | Decode a t'ReplyShortChannelIdsEnd' payload.
    431 --
    432 --   >>> decode_reply_short_channel_ids_end (BS.replicate 32 0 <> "\STX")
    433 --   Left DecodeInvalidBool
    434 decode_reply_short_channel_ids_end
    435   :: BS.ByteString -> Either DecodeError ReplyShortChannelIdsEnd
    436 decode_reply_short_channel_ids_end b0 = do
    437   (ch, b1)   <- chain_hash b0
    438   (full, b2) <- bool b1
    439   ext        <- extension b2
    440   pure (ReplyShortChannelIdsEnd ch full ext)
    441 
    442 -- query_channel_range --------------------------------------------------------
    443 
    444 -- | Encode a t'QueryChannelRange' payload. Fails if 'qcr_tlvs' holds a
    445 --   record of type 1.
    446 encode_query_channel_range
    447   :: QueryChannelRange -> Either EncodeError BS.ByteString
    448 encode_query_channel_range m = do
    449   let opt = case qcr_query_option m of
    450         Nothing              -> []
    451         Just (QueryOption w) -> [TlvRecord 1 (BOLT1.encode_bigsize w)]
    452   t <- merge [1] opt (qcr_tlvs m)
    453   pure $ mconcat
    454     [ BOLT1.un_chain_hash (qcr_chain_hash m)
    455     , BOLT1.encode_u32 (qcr_first_blocknum m)
    456     , BOLT1.encode_u32 (qcr_number_of_blocks m)
    457     , t
    458     ]
    459 
    460 -- | Decode a t'QueryChannelRange' payload.
    461 decode_query_channel_range
    462   :: BS.ByteString -> Either DecodeError QueryChannelRange
    463 decode_query_channel_range b0 = do
    464   (ch, b1)    <- chain_hash b0
    465   (first, b2) <- u32 b1
    466   (num, b3)   <- u32 b2
    467   s           <- tlvs [1] b3
    468   opt         <- traverse option (BOLT1.lookup_tlv 1 s)
    469   pure QueryChannelRange
    470     { qcr_chain_hash       = ch
    471     , qcr_first_blocknum   = first
    472     , qcr_number_of_blocks = num
    473     , qcr_query_option     = opt
    474     , qcr_tlvs             = BOLT1.filter_tlv_stream (/= 1) s
    475     }
    476   where
    477     option v = case BOLT1.decode_bigsize v of
    478       Just (w, r) | BS.null r -> Right (QueryOption w)
    479       _ -> Left (DecodeInvalidTlvValue 1)
    480 
    481 -- reply_channel_range --------------------------------------------------------
    482 
    483 -- | Encode a t'ReplyChannelRange' payload. Fails if the short channel ids
    484 --   exceed the u16 length limit (8191 of them), if the timestamps or
    485 --   checksums don't number one per short channel id, or if 'rcr_tlvs'
    486 --   holds a record of type 1 or 3.
    487 encode_reply_channel_range
    488   :: ReplyChannelRange -> Either EncodeError BS.ByteString
    489 encode_reply_channel_range m = do
    490   let scids = rcr_short_channel_ids m
    491       n = length scids
    492       count xs
    493         | length xs /= n = Left EncodeCountMismatch
    494         | otherwise      = Right ()
    495   ids <- prefixed (encode_short_ids scids)
    496   ts <- case rcr_timestamps m of
    497     Nothing -> pure []
    498     Just xs -> do
    499       count xs
    500       pure [TlvRecord 1 (BS.cons 0 (foldMap
    501         (\(ChannelUpdateTimestamps a b) -> pair a b) xs))]
    502   cs <- case rcr_checksums m of
    503     Nothing -> pure []
    504     Just xs -> do
    505       count xs
    506       pure [TlvRecord 3 (foldMap
    507         (\(ChannelUpdateChecksums a b) -> pair a b) xs)]
    508   t <- merge [1, 3] (ts <> cs) (rcr_tlvs m)
    509   pure $ mconcat
    510     [ BOLT1.un_chain_hash (rcr_chain_hash m)
    511     , BOLT1.encode_u32 (rcr_first_blocknum m)
    512     , BOLT1.encode_u32 (rcr_number_of_blocks m)
    513     , encode_bool (rcr_sync_complete m)
    514     , ids
    515     , t
    516     ]
    517   where
    518     pair a b = BOLT1.encode_u32 a <> BOLT1.encode_u32 b
    519 
    520 -- | Decode a t'ReplyChannelRange' payload.
    521 --
    522 --   Fails on an unknown encoding type (including the deprecated zlib
    523 --   encoding), on @encoded_short_ids@ that isn't a whole number of short
    524 --   channel ids, and on timestamps or checksums that don't number one
    525 --   per short channel id.
    526 decode_reply_channel_range
    527   :: BS.ByteString -> Either DecodeError ReplyChannelRange
    528 decode_reply_channel_range b0 = do
    529   (ch, b1)    <- chain_hash b0
    530   (first, b2) <- u32 b1
    531   (num, b3)   <- u32 b2
    532   (sync, b4)  <- bool b3
    533   (ids, b5)   <- u16_prefixed b4
    534   scids       <- short_ids ids
    535   s           <- tlvs [1, 3] b5
    536   let n = length scids
    537   ts <- traverse (timestamps n) (BOLT1.lookup_tlv 1 s)
    538   cs <- traverse (pairs 3 ChannelUpdateChecksums n) (BOLT1.lookup_tlv 3 s)
    539   pure ReplyChannelRange
    540     { rcr_chain_hash        = ch
    541     , rcr_first_blocknum    = first
    542     , rcr_number_of_blocks  = num
    543     , rcr_sync_complete     = sync
    544     , rcr_short_channel_ids = scids
    545     , rcr_timestamps        = ts
    546     , rcr_checksums         = cs
    547     , rcr_tlvs              =
    548         BOLT1.filter_tlv_stream (\t -> t /= 1 && t /= 3) s
    549     }
    550   where
    551     timestamps n v = case BS.uncons v of
    552       Nothing     -> Left (DecodeInvalidTlvValue 1)
    553       Just (0, r) -> pairs 1 ChannelUpdateTimestamps n r
    554       Just (e, _) -> Left (DecodeUnknownEncoding e)
    555 
    556 -- decode an array of u32 pairs holding n elements
    557 pairs
    558   :: Word64 -> (Word32 -> Word32 -> a) -> Int -> BS.ByteString
    559   -> Either DecodeError [a]
    560 pairs t mk n r
    561   | BS.length r `rem` 8 /= 0  = Left (DecodeInvalidTlvValue t)
    562   | BS.length r `quot` 8 /= n = Left DecodeCountMismatch
    563   | otherwise                 = Right (go r)
    564   where
    565     go !bs = case BOLT1.decode_u32 bs of
    566       Nothing -> []
    567       Just (a, r1) -> case BOLT1.decode_u32 r1 of
    568         Nothing      -> []
    569         Just (b, r2) -> mk a b : go r2
    570 
    571 -- gossip_timestamp_filter ----------------------------------------------------
    572 
    573 -- | Encode a t'GossipTimestampFilter' payload.
    574 encode_gossip_timestamp_filter :: GossipTimestampFilter -> BS.ByteString
    575 encode_gossip_timestamp_filter m = mconcat
    576   [ BOLT1.un_chain_hash (gtf_chain_hash m)
    577   , BOLT1.encode_u32 (gtf_first_timestamp m)
    578   , BOLT1.encode_u32 (gtf_timestamp_range m)
    579   , BOLT1.encode_tlv_stream (gtf_tlvs m)
    580   ]
    581 
    582 -- | Decode a t'GossipTimestampFilter' payload.
    583 decode_gossip_timestamp_filter
    584   :: BS.ByteString -> Either DecodeError GossipTimestampFilter
    585 decode_gossip_timestamp_filter b0 = do
    586   (ch, b1)    <- chain_hash b0
    587   (first, b2) <- u32 b1
    588   (range, b3) <- u32 b2
    589   ext         <- extension b3
    590   pure (GossipTimestampFilter ch first range ext)
    591 
    592 -- encoded short channel ids --------------------------------------------------
    593 
    594 -- encoding type 0 (uncompressed), the only one allowed
    595 encode_short_ids :: [ShortChannelId] -> BS.ByteString
    596 encode_short_ids = BS.cons 0 . foldMap BOLT1.encode_short_channel_id
    597 
    598 short_ids :: BS.ByteString -> Either DecodeError [ShortChannelId]
    599 short_ids bs = case BS.uncons bs of
    600   Nothing -> Left DecodeInvalidShortChannelIds
    601   Just (0, r)
    602     | BS.length r `rem` 8 == 0 -> Right (go r)
    603     | otherwise                -> Left DecodeInvalidShortChannelIds
    604   Just (e, _) -> Left (DecodeUnknownEncoding e)
    605   where
    606     go !r = case BOLT1.decode_short_channel_id r of
    607       Nothing      -> []
    608       Just (s, r1) -> s : go r1
    609 
    610 -- helpers --------------------------------------------------------------------
    611 
    612 need :: Maybe a -> Either DecodeError a
    613 need = maybe (Left DecodeInsufficientBytes) Right
    614 {-# INLINE need #-}
    615 
    616 u8 :: BS.ByteString -> Either DecodeError (Word8, BS.ByteString)
    617 u8 = need . BS.uncons
    618 {-# INLINE u8 #-}
    619 
    620 u16 :: BS.ByteString -> Either DecodeError (Word16, BS.ByteString)
    621 u16 = need . BOLT1.decode_u16
    622 {-# INLINE u16 #-}
    623 
    624 u32 :: BS.ByteString -> Either DecodeError (Word32, BS.ByteString)
    625 u32 = need . BOLT1.decode_u32
    626 {-# INLINE u32 #-}
    627 
    628 bytes
    629   :: Int -> BS.ByteString
    630   -> Either DecodeError (BS.ByteString, BS.ByteString)
    631 bytes n bs
    632   | BS.length bs < n = Left DecodeInsufficientBytes
    633   | otherwise        = Right (BS.splitAt n bs)
    634 {-# INLINE bytes #-}
    635 
    636 u16_prefixed
    637   :: BS.ByteString -> Either DecodeError (BS.ByteString, BS.ByteString)
    638 u16_prefixed = need . BOLT1.decode_u16_prefixed
    639 {-# INLINE u16_prefixed #-}
    640 
    641 bool :: BS.ByteString -> Either DecodeError (Bool, BS.ByteString)
    642 bool bs = do
    643   (b, r) <- u8 bs
    644   case b of
    645     0 -> Right (False, r)
    646     1 -> Right (True, r)
    647     _ -> Left DecodeInvalidBool
    648 
    649 signature :: BS.ByteString -> Either DecodeError (Signature, BS.ByteString)
    650 signature = need . BOLT1.decode_signature
    651 {-# INLINE signature #-}
    652 
    653 chain_hash :: BS.ByteString -> Either DecodeError (ChainHash, BS.ByteString)
    654 chain_hash = need . BOLT1.decode_chain_hash
    655 {-# INLINE chain_hash #-}
    656 
    657 short_channel_id
    658   :: BS.ByteString -> Either DecodeError (ShortChannelId, BS.ByteString)
    659 short_channel_id = need . BOLT1.decode_short_channel_id
    660 {-# INLINE short_channel_id #-}
    661 
    662 point :: BS.ByteString -> Either DecodeError (Point, BS.ByteString)
    663 point bs = do
    664   (b, r) <- bytes 33 bs
    665   case BOLT1.point b of
    666     Nothing -> Left DecodeInvalidPoint
    667     Just p  -> Right (p, r)
    668 
    669 milli_satoshi
    670   :: BS.ByteString -> Either DecodeError (MilliSatoshi, BS.ByteString)
    671 milli_satoshi bs = do
    672   (w, r) <- need (BOLT1.decode_u64 bs)
    673   case BOLT1.milli_satoshi w of
    674     Nothing -> Left DecodeInvalidAmount
    675     Just a  -> Right (a, r)
    676 
    677 -- a TLV stream with the given known types
    678 tlvs :: [Word64] -> BS.ByteString -> Either DecodeError TlvStream
    679 tlvs known bs = either (Left . DecodeTlvError) Right
    680   (BOLT1.decode_tlv_stream (`elem` known) bs)
    681 
    682 -- an extension stream, in which no types are known
    683 extension :: BS.ByteString -> Either DecodeError TlvStream
    684 extension = tlvs []
    685 {-# INLINE extension #-}
    686 
    687 prefixed :: BS.ByteString -> Either EncodeError BS.ByteString
    688 prefixed bs =
    689   maybe (Left EncodeLengthOverflow) Right (BOLT1.encode_u16_prefixed bs)
    690 {-# INLINE prefixed #-}
    691 
    692 encode_bool :: Bool -> BS.ByteString
    693 encode_bool b = BS.singleton (if b then 1 else 0)
    694 {-# INLINE encode_bool #-}
    695 
    696 -- encode typed records together with the extra records of a @_tlvs@
    697 -- field, which mustn't use any of the message's known types
    698 merge
    699   :: [Word64] -> [TlvRecord] -> TlvStream -> Either EncodeError BS.ByteString
    700 merge known typed extra
    701   | any ((`elem` known) . tlv_type) rs = Left EncodeInvalidTlvs
    702   | otherwise =
    703       maybe (Left EncodeInvalidTlvs) (Right . BOLT1.encode_tlv_stream)
    704       (BOLT1.tlv_stream (typed <> rs))
    705   where
    706     rs = BOLT1.un_tlv_stream extra