{-# OPTIONS_HADDOCK prune #-}

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveGeneric #-}

-- |
-- Module: Lightning.Protocol.BOLT7.Codec
-- Copyright: (c) 2025 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
-- Encoding and decoding for BOLT #7 gossip messages.

module Lightning.Protocol.BOLT7.Codec (
  -- * Error types
    EncodeError(..)
  , DecodeError(..)

  -- * Channel announcement
  , encodeChannelAnnouncement
  , decodeChannelAnnouncement

  -- * Node announcement
  , encodeNodeAnnouncement
  , decodeNodeAnnouncement

  -- * Channel update
  , encodeChannelUpdate
  , decodeChannelUpdate

  -- * Announcement signatures
  , encodeAnnouncementSignatures
  , decodeAnnouncementSignatures

  -- * Query messages
  , encodeQueryShortChannelIds
  , decodeQueryShortChannelIds
  , encodeReplyShortChannelIdsEnd
  , decodeReplyShortChannelIdsEnd
  , encodeQueryChannelRange
  , decodeQueryChannelRange
  , encodeReplyChannelRange
  , decodeReplyChannelRange
  , encodeGossipTimestampFilter
  , decodeGossipTimestampFilter

  -- * Short channel ID encoding
  , encodeShortChannelIdList
  , decodeShortChannelIdList
  ) where

import Control.DeepSeq (NFData)
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.Word (Word8, Word16, Word32, Word64)
import GHC.Generics (Generic)
import Lightning.Protocol.BOLT1 (unsafeTlvStream)
import qualified Lightning.Protocol.BOLT1.Prim as Prim
import qualified Lightning.Protocol.BOLT1.TLV as TLV
import Lightning.Protocol.BOLT7.Messages
import Lightning.Protocol.BOLT7.Types

-- Error types -----------------------------------------------------------------

-- | Encoding errors.
data EncodeError
  = EncodeLengthOverflow  -- ^ Field too large for u16 length prefix
  deriving (EncodeError -> EncodeError -> Bool
(EncodeError -> EncodeError -> Bool)
-> (EncodeError -> EncodeError -> Bool) -> Eq EncodeError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: EncodeError -> EncodeError -> Bool
== :: EncodeError -> EncodeError -> Bool
$c/= :: EncodeError -> EncodeError -> Bool
/= :: EncodeError -> EncodeError -> Bool
Eq, Int -> EncodeError -> ShowS
[EncodeError] -> ShowS
EncodeError -> String
(Int -> EncodeError -> ShowS)
-> (EncodeError -> String)
-> ([EncodeError] -> ShowS)
-> Show EncodeError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> EncodeError -> ShowS
showsPrec :: Int -> EncodeError -> ShowS
$cshow :: EncodeError -> String
show :: EncodeError -> String
$cshowList :: [EncodeError] -> ShowS
showList :: [EncodeError] -> ShowS
Show, (forall x. EncodeError -> Rep EncodeError x)
-> (forall x. Rep EncodeError x -> EncodeError)
-> Generic EncodeError
forall x. Rep EncodeError x -> EncodeError
forall x. EncodeError -> Rep EncodeError x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. EncodeError -> Rep EncodeError x
from :: forall x. EncodeError -> Rep EncodeError x
$cto :: forall x. Rep EncodeError x -> EncodeError
to :: forall x. Rep EncodeError x -> EncodeError
Generic)

instance NFData EncodeError

-- | Decoding errors.
data DecodeError
  = DecodeInsufficientBytes          -- ^ Not enough bytes
  | DecodeInvalidSignature           -- ^ Invalid signature field
  | DecodeInvalidChainHash           -- ^ Invalid chain hash field
  | DecodeInvalidShortChannelId      -- ^ Invalid short channel ID field
  | DecodeInvalidChannelId           -- ^ Invalid channel ID field
  | DecodeInvalidNodeId              -- ^ Invalid node ID field
  | DecodeInvalidPoint               -- ^ Invalid point field
  | DecodeInvalidRgbColor            -- ^ Invalid RGB color field
  | DecodeInvalidAlias               -- ^ Invalid alias field
  | DecodeInvalidAddress             -- ^ Invalid address encoding
  | DecodeTlvError                   -- ^ TLV decoding error
  deriving (DecodeError -> DecodeError -> Bool
(DecodeError -> DecodeError -> Bool)
-> (DecodeError -> DecodeError -> Bool) -> Eq DecodeError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DecodeError -> DecodeError -> Bool
== :: DecodeError -> DecodeError -> Bool
$c/= :: DecodeError -> DecodeError -> Bool
/= :: DecodeError -> DecodeError -> Bool
Eq, Int -> DecodeError -> ShowS
[DecodeError] -> ShowS
DecodeError -> String
(Int -> DecodeError -> ShowS)
-> (DecodeError -> String)
-> ([DecodeError] -> ShowS)
-> Show DecodeError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DecodeError -> ShowS
showsPrec :: Int -> DecodeError -> ShowS
$cshow :: DecodeError -> String
show :: DecodeError -> String
$cshowList :: [DecodeError] -> ShowS
showList :: [DecodeError] -> ShowS
Show, (forall x. DecodeError -> Rep DecodeError x)
-> (forall x. Rep DecodeError x -> DecodeError)
-> Generic DecodeError
forall x. Rep DecodeError x -> DecodeError
forall x. DecodeError -> Rep DecodeError x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. DecodeError -> Rep DecodeError x
from :: forall x. DecodeError -> Rep DecodeError x
$cto :: forall x. Rep DecodeError x -> DecodeError
to :: forall x. Rep DecodeError x -> DecodeError
Generic)

instance NFData DecodeError

-- Primitive helpers -----------------------------------------------------------

-- | Decode u8.
decodeU8 :: ByteString -> Either DecodeError (Word8, ByteString)
decodeU8 :: ByteString -> Either DecodeError (Word8, ByteString)
decodeU8 ByteString
bs
  | ByteString -> Bool
BS.null ByteString
bs = DecodeError -> Either DecodeError (Word8, ByteString)
forall a b. a -> Either a b
Left DecodeError
DecodeInsufficientBytes
  | Bool
otherwise = (Word8, ByteString) -> Either DecodeError (Word8, ByteString)
forall a b. b -> Either a b
Right (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs Int
0, Int -> ByteString -> ByteString
BS.drop Int
1 ByteString
bs)
{-# INLINE decodeU8 #-}

-- | Decode u16 (big-endian).
decodeU16 :: ByteString -> Either DecodeError (Word16, ByteString)
decodeU16 :: ByteString -> Either DecodeError (Word16, ByteString)
decodeU16 ByteString
bs = case ByteString -> Maybe (Word16, ByteString)
Prim.decodeU16 ByteString
bs of
  Maybe (Word16, ByteString)
Nothing -> DecodeError -> Either DecodeError (Word16, ByteString)
forall a b. a -> Either a b
Left DecodeError
DecodeInsufficientBytes
  Just (Word16, ByteString)
r  -> (Word16, ByteString) -> Either DecodeError (Word16, ByteString)
forall a b. b -> Either a b
Right (Word16, ByteString)
r
{-# INLINE decodeU16 #-}

-- | Decode u32 (big-endian).
decodeU32 :: ByteString -> Either DecodeError (Word32, ByteString)
decodeU32 :: ByteString -> Either DecodeError (Word32, ByteString)
decodeU32 ByteString
bs = case ByteString -> Maybe (Word32, ByteString)
Prim.decodeU32 ByteString
bs of
  Maybe (Word32, ByteString)
Nothing -> DecodeError -> Either DecodeError (Word32, ByteString)
forall a b. a -> Either a b
Left DecodeError
DecodeInsufficientBytes
  Just (Word32, ByteString)
r  -> (Word32, ByteString) -> Either DecodeError (Word32, ByteString)
forall a b. b -> Either a b
Right (Word32, ByteString)
r
{-# INLINE decodeU32 #-}

-- | Decode u64 (big-endian).
decodeU64 :: ByteString -> Either DecodeError (Word64, ByteString)
decodeU64 :: ByteString -> Either DecodeError (Word64, ByteString)
decodeU64 ByteString
bs = case ByteString -> Maybe (Word64, ByteString)
Prim.decodeU64 ByteString
bs of
  Maybe (Word64, ByteString)
Nothing -> DecodeError -> Either DecodeError (Word64, ByteString)
forall a b. a -> Either a b
Left DecodeError
DecodeInsufficientBytes
  Just (Word64, ByteString)
r  -> (Word64, ByteString) -> Either DecodeError (Word64, ByteString)
forall a b. b -> Either a b
Right (Word64, ByteString)
r
{-# INLINE decodeU64 #-}

-- | Decode fixed-length bytes.
decodeBytes :: Int -> ByteString -> Either DecodeError (ByteString, ByteString)
decodeBytes :: Int -> ByteString -> Either DecodeError (ByteString, ByteString)
decodeBytes Int
n ByteString
bs
  | ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
n = DecodeError -> Either DecodeError (ByteString, ByteString)
forall a b. a -> Either a b
Left DecodeError
DecodeInsufficientBytes
  | Bool
otherwise = (ByteString, ByteString)
-> Either DecodeError (ByteString, ByteString)
forall a b. b -> Either a b
Right (Int -> ByteString -> (ByteString, ByteString)
BS.splitAt Int
n ByteString
bs)
{-# INLINE decodeBytes #-}

-- | Decode length-prefixed bytes (u16 prefix).
decodeLenPrefixed :: ByteString
                  -> Either DecodeError (ByteString, ByteString)
decodeLenPrefixed :: ByteString -> Either DecodeError (ByteString, ByteString)
decodeLenPrefixed ByteString
bs = do
  (len, rest) <- ByteString -> Either DecodeError (Word16, ByteString)
decodeU16 ByteString
bs
  let n = Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
len
  if BS.length rest < n
    then Left DecodeInsufficientBytes
    else Right (BS.splitAt n rest)
{-# INLINE decodeLenPrefixed #-}

-- | Encode with u16 length prefix.
encodeLenPrefixed :: ByteString -> ByteString
encodeLenPrefixed :: ByteString -> ByteString
encodeLenPrefixed ByteString
bs = Word16 -> ByteString
Prim.encodeU16 (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word16) -> Int -> Word16
forall a b. (a -> b) -> a -> b
$ ByteString -> Int
BS.length ByteString
bs) ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
bs
{-# INLINE encodeLenPrefixed #-}

-- | Decode fixed-length validated type.
decodeFixed :: Int -> DecodeError -> (ByteString -> Maybe a)
            -> ByteString -> Either DecodeError (a, ByteString)
decodeFixed :: forall a.
Int
-> DecodeError
-> (ByteString -> Maybe a)
-> ByteString
-> Either DecodeError (a, ByteString)
decodeFixed Int
len DecodeError
err ByteString -> Maybe a
mkVal ByteString
bs = do
  (bytes, rest) <- Int -> ByteString -> Either DecodeError (ByteString, ByteString)
decodeBytes Int
len ByteString
bs
  case mkVal bytes of
    Maybe a
Nothing -> DecodeError -> Either DecodeError (a, ByteString)
forall a b. a -> Either a b
Left DecodeError
err
    Just a
v  -> (a, ByteString) -> Either DecodeError (a, ByteString)
forall a b. b -> Either a b
Right (a
v, ByteString
rest)
{-# INLINE decodeFixed #-}

-- Type-specific decoders ------------------------------------------------------

-- | Decode Signature (64 bytes).
decodeSignature :: ByteString -> Either DecodeError (Signature, ByteString)
decodeSignature :: ByteString -> Either DecodeError (Signature, ByteString)
decodeSignature = Int
-> DecodeError
-> (ByteString -> Maybe Signature)
-> ByteString
-> Either DecodeError (Signature, ByteString)
forall a.
Int
-> DecodeError
-> (ByteString -> Maybe a)
-> ByteString
-> Either DecodeError (a, ByteString)
decodeFixed Int
signatureLen DecodeError
DecodeInvalidSignature ByteString -> Maybe Signature
signature
{-# INLINE decodeSignature #-}

-- | Decode ChainHash (32 bytes).
decodeChainHash :: ByteString -> Either DecodeError (ChainHash, ByteString)
decodeChainHash :: ByteString -> Either DecodeError (ChainHash, ByteString)
decodeChainHash = Int
-> DecodeError
-> (ByteString -> Maybe ChainHash)
-> ByteString
-> Either DecodeError (ChainHash, ByteString)
forall a.
Int
-> DecodeError
-> (ByteString -> Maybe a)
-> ByteString
-> Either DecodeError (a, ByteString)
decodeFixed Int
chainHashLen DecodeError
DecodeInvalidChainHash ByteString -> Maybe ChainHash
chainHash
{-# INLINE decodeChainHash #-}

-- | Decode ShortChannelId (8 bytes).
decodeShortChannelId :: ByteString
                     -> Either DecodeError (ShortChannelId, ByteString)
decodeShortChannelId :: ByteString -> Either DecodeError (ShortChannelId, ByteString)
decodeShortChannelId =
  Int
-> DecodeError
-> (ByteString -> Maybe ShortChannelId)
-> ByteString
-> Either DecodeError (ShortChannelId, ByteString)
forall a.
Int
-> DecodeError
-> (ByteString -> Maybe a)
-> ByteString
-> Either DecodeError (a, ByteString)
decodeFixed Int
shortChannelIdLen DecodeError
DecodeInvalidShortChannelId ByteString -> Maybe ShortChannelId
shortChannelId
{-# INLINE decodeShortChannelId #-}

-- | Decode ChannelId (32 bytes).
decodeChannelId :: ByteString -> Either DecodeError (ChannelId, ByteString)
decodeChannelId :: ByteString -> Either DecodeError (ChannelId, ByteString)
decodeChannelId = Int
-> DecodeError
-> (ByteString -> Maybe ChannelId)
-> ByteString
-> Either DecodeError (ChannelId, ByteString)
forall a.
Int
-> DecodeError
-> (ByteString -> Maybe a)
-> ByteString
-> Either DecodeError (a, ByteString)
decodeFixed Int
channelIdLen DecodeError
DecodeInvalidChannelId ByteString -> Maybe ChannelId
channelId
{-# INLINE decodeChannelId #-}

-- | Decode NodeId (33 bytes).
decodeNodeId :: ByteString -> Either DecodeError (NodeId, ByteString)
decodeNodeId :: ByteString -> Either DecodeError (NodeId, ByteString)
decodeNodeId = Int
-> DecodeError
-> (ByteString -> Maybe NodeId)
-> ByteString
-> Either DecodeError (NodeId, ByteString)
forall a.
Int
-> DecodeError
-> (ByteString -> Maybe a)
-> ByteString
-> Either DecodeError (a, ByteString)
decodeFixed Int
nodeIdLen DecodeError
DecodeInvalidNodeId ByteString -> Maybe NodeId
nodeId
{-# INLINE decodeNodeId #-}

-- | Decode Point (33 bytes).
decodePoint :: ByteString -> Either DecodeError (Point, ByteString)
decodePoint :: ByteString -> Either DecodeError (Point, ByteString)
decodePoint = Int
-> DecodeError
-> (ByteString -> Maybe Point)
-> ByteString
-> Either DecodeError (Point, ByteString)
forall a.
Int
-> DecodeError
-> (ByteString -> Maybe a)
-> ByteString
-> Either DecodeError (a, ByteString)
decodeFixed Int
pointLen DecodeError
DecodeInvalidPoint ByteString -> Maybe Point
point
{-# INLINE decodePoint #-}

-- | Decode RgbColor (3 bytes).
decodeRgbColor :: ByteString -> Either DecodeError (RgbColor, ByteString)
decodeRgbColor :: ByteString -> Either DecodeError (RgbColor, ByteString)
decodeRgbColor = Int
-> DecodeError
-> (ByteString -> Maybe RgbColor)
-> ByteString
-> Either DecodeError (RgbColor, ByteString)
forall a.
Int
-> DecodeError
-> (ByteString -> Maybe a)
-> ByteString
-> Either DecodeError (a, ByteString)
decodeFixed Int
rgbColorLen DecodeError
DecodeInvalidRgbColor ByteString -> Maybe RgbColor
rgbColor
{-# INLINE decodeRgbColor #-}

-- | Decode Alias (32 bytes).
decodeAlias :: ByteString -> Either DecodeError (Alias, ByteString)
decodeAlias :: ByteString -> Either DecodeError (Alias, ByteString)
decodeAlias = Int
-> DecodeError
-> (ByteString -> Maybe Alias)
-> ByteString
-> Either DecodeError (Alias, ByteString)
forall a.
Int
-> DecodeError
-> (ByteString -> Maybe a)
-> ByteString
-> Either DecodeError (a, ByteString)
decodeFixed Int
aliasLen DecodeError
DecodeInvalidAlias ByteString -> Maybe Alias
alias
{-# INLINE decodeAlias #-}

-- | Decode FeatureBits (length-prefixed).
decodeFeatureBits :: ByteString -> Either DecodeError (FeatureBits, ByteString)
decodeFeatureBits :: ByteString -> Either DecodeError (FeatureBits, ByteString)
decodeFeatureBits ByteString
bs = do
  (bytes, rest) <- ByteString -> Either DecodeError (ByteString, ByteString)
decodeLenPrefixed ByteString
bs
  Right (featureBits bytes, rest)
{-# INLINE decodeFeatureBits #-}

-- | Decode addresses list (length-prefixed).
decodeAddresses :: ByteString -> Either DecodeError ([Address], ByteString)
decodeAddresses :: ByteString -> Either DecodeError ([Address], ByteString)
decodeAddresses ByteString
bs = do
  (addrData, rest) <- ByteString -> Either DecodeError (ByteString, ByteString)
decodeLenPrefixed ByteString
bs
  addrs <- parseAddrs addrData
  Right (addrs, rest)
  where
    parseAddrs :: ByteString -> Either DecodeError [Address]
    parseAddrs :: ByteString -> Either DecodeError [Address]
parseAddrs !ByteString
d
      | ByteString -> Bool
BS.null ByteString
d = [Address] -> Either DecodeError [Address]
forall a b. b -> Either a b
Right []
      | Bool
otherwise = do
          (addr, d') <- ByteString -> Either DecodeError (Address, ByteString)
parseOneAddr ByteString
d
          addrs <- parseAddrs d'
          Right (addr : addrs)

    parseOneAddr :: ByteString -> Either DecodeError (Address, ByteString)
    parseOneAddr :: ByteString -> Either DecodeError (Address, ByteString)
parseOneAddr ByteString
d = do
      (typ, d1) <- ByteString -> Either DecodeError (Word8, ByteString)
decodeU8 ByteString
d
      case typ of
        Word8
1 -> do  -- IPv4
          (addrBytes, d2) <- Int -> ByteString -> Either DecodeError (ByteString, ByteString)
decodeBytes Int
ipv4AddrLen ByteString
d1
          (port, d3) <- decodeU16 d2
          case ipv4Addr addrBytes of
            Maybe IPv4Addr
Nothing -> DecodeError -> Either DecodeError (Address, ByteString)
forall a b. a -> Either a b
Left DecodeError
DecodeInvalidAddress
            Just IPv4Addr
a  -> (Address, ByteString) -> Either DecodeError (Address, ByteString)
forall a b. b -> Either a b
Right (IPv4Addr -> Word16 -> Address
AddrIPv4 IPv4Addr
a Word16
port, ByteString
d3)
        Word8
2 -> do  -- IPv6
          (addrBytes, d2) <- Int -> ByteString -> Either DecodeError (ByteString, ByteString)
decodeBytes Int
ipv6AddrLen ByteString
d1
          (port, d3) <- decodeU16 d2
          case ipv6Addr addrBytes of
            Maybe IPv6Addr
Nothing -> DecodeError -> Either DecodeError (Address, ByteString)
forall a b. a -> Either a b
Left DecodeError
DecodeInvalidAddress
            Just IPv6Addr
a  -> (Address, ByteString) -> Either DecodeError (Address, ByteString)
forall a b. b -> Either a b
Right (IPv6Addr -> Word16 -> Address
AddrIPv6 IPv6Addr
a Word16
port, ByteString
d3)
        Word8
4 -> do  -- Tor v3
          (addrBytes, d2) <- Int -> ByteString -> Either DecodeError (ByteString, ByteString)
decodeBytes Int
torV3AddrLen ByteString
d1
          (port, d3) <- decodeU16 d2
          case torV3Addr addrBytes of
            Maybe TorV3Addr
Nothing -> DecodeError -> Either DecodeError (Address, ByteString)
forall a b. a -> Either a b
Left DecodeError
DecodeInvalidAddress
            Just TorV3Addr
a  -> (Address, ByteString) -> Either DecodeError (Address, ByteString)
forall a b. b -> Either a b
Right (TorV3Addr -> Word16 -> Address
AddrTorV3 TorV3Addr
a Word16
port, ByteString
d3)
        Word8
5 -> do  -- DNS hostname
          (hostLen, d2) <- ByteString -> Either DecodeError (Word8, ByteString)
decodeU8 ByteString
d1
          (hostBytes, d3) <- decodeBytes (fromIntegral hostLen) d2
          (port, d4) <- decodeU16 d3
          Right (AddrDNS hostBytes port, d4)
        Word8
_ -> DecodeError -> Either DecodeError (Address, ByteString)
forall a b. a -> Either a b
Left DecodeError
DecodeInvalidAddress  -- Unknown address type

-- Channel announcement --------------------------------------------------------

-- | Encode channel_announcement message.
encodeChannelAnnouncement :: ChannelAnnouncement -> ByteString
encodeChannelAnnouncement :: ChannelAnnouncement -> ByteString
encodeChannelAnnouncement ChannelAnnouncement
msg = [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
  [ Signature -> ByteString
getSignature (ChannelAnnouncement -> Signature
channelAnnNodeSig1 ChannelAnnouncement
msg)
  , Signature -> ByteString
getSignature (ChannelAnnouncement -> Signature
channelAnnNodeSig2 ChannelAnnouncement
msg)
  , Signature -> ByteString
getSignature (ChannelAnnouncement -> Signature
channelAnnBitcoinSig1 ChannelAnnouncement
msg)
  , Signature -> ByteString
getSignature (ChannelAnnouncement -> Signature
channelAnnBitcoinSig2 ChannelAnnouncement
msg)
  , ByteString -> ByteString
encodeLenPrefixed (FeatureBits -> ByteString
getFeatureBits (ChannelAnnouncement -> FeatureBits
channelAnnFeatures ChannelAnnouncement
msg))
  , ChainHash -> ByteString
getChainHash (ChannelAnnouncement -> ChainHash
channelAnnChainHash ChannelAnnouncement
msg)
  , ShortChannelId -> ByteString
getShortChannelId (ChannelAnnouncement -> ShortChannelId
channelAnnShortChanId ChannelAnnouncement
msg)
  , NodeId -> ByteString
getNodeId (ChannelAnnouncement -> NodeId
channelAnnNodeId1 ChannelAnnouncement
msg)
  , NodeId -> ByteString
getNodeId (ChannelAnnouncement -> NodeId
channelAnnNodeId2 ChannelAnnouncement
msg)
  , Point -> ByteString
getPoint (ChannelAnnouncement -> Point
channelAnnBitcoinKey1 ChannelAnnouncement
msg)
  , Point -> ByteString
getPoint (ChannelAnnouncement -> Point
channelAnnBitcoinKey2 ChannelAnnouncement
msg)
  ]

-- | Decode channel_announcement message.
decodeChannelAnnouncement :: ByteString
                          -> Either DecodeError (ChannelAnnouncement, ByteString)
decodeChannelAnnouncement :: ByteString -> Either DecodeError (ChannelAnnouncement, ByteString)
decodeChannelAnnouncement ByteString
bs = do
  (nodeSig1, bs1)    <- ByteString -> Either DecodeError (Signature, ByteString)
decodeSignature ByteString
bs
  (nodeSig2, bs2)    <- decodeSignature bs1
  (btcSig1, bs3)     <- decodeSignature bs2
  (btcSig2, bs4)     <- decodeSignature bs3
  (features, bs5)    <- decodeFeatureBits bs4
  (chainH, bs6)      <- decodeChainHash bs5
  (scid, bs7)        <- decodeShortChannelId bs6
  (nid1, bs8)        <- decodeNodeId bs7
  (nid2, bs9)        <- decodeNodeId bs8
  (btcKey1, bs10)    <- decodePoint bs9
  (btcKey2, rest)    <- decodePoint bs10
  let msg = ChannelAnnouncement
        { channelAnnNodeSig1 :: Signature
channelAnnNodeSig1    = Signature
nodeSig1
        , channelAnnNodeSig2 :: Signature
channelAnnNodeSig2    = Signature
nodeSig2
        , channelAnnBitcoinSig1 :: Signature
channelAnnBitcoinSig1 = Signature
btcSig1
        , channelAnnBitcoinSig2 :: Signature
channelAnnBitcoinSig2 = Signature
btcSig2
        , channelAnnFeatures :: FeatureBits
channelAnnFeatures    = FeatureBits
features
        , channelAnnChainHash :: ChainHash
channelAnnChainHash   = ChainHash
chainH
        , channelAnnShortChanId :: ShortChannelId
channelAnnShortChanId = ShortChannelId
scid
        , channelAnnNodeId1 :: NodeId
channelAnnNodeId1     = NodeId
nid1
        , channelAnnNodeId2 :: NodeId
channelAnnNodeId2     = NodeId
nid2
        , channelAnnBitcoinKey1 :: Point
channelAnnBitcoinKey1 = Point
btcKey1
        , channelAnnBitcoinKey2 :: Point
channelAnnBitcoinKey2 = Point
btcKey2
        }
  Right (msg, rest)

-- Node announcement -----------------------------------------------------------

-- | Encode node_announcement message.
encodeNodeAnnouncement :: NodeAnnouncement -> Either EncodeError ByteString
encodeNodeAnnouncement :: NodeAnnouncement -> Either EncodeError ByteString
encodeNodeAnnouncement NodeAnnouncement
msg = do
  addrData <- [Address] -> Either EncodeError ByteString
encodeAddresses (NodeAnnouncement -> [Address]
nodeAnnAddresses NodeAnnouncement
msg)
  let features = FeatureBits -> ByteString
getFeatureBits (NodeAnnouncement -> FeatureBits
nodeAnnFeatures NodeAnnouncement
msg)
  if BS.length features > 65535
    then Left EncodeLengthOverflow
    else Right $ mconcat
      [ getSignature (nodeAnnSignature msg)
      , encodeLenPrefixed features
      , Prim.encodeU32 (nodeAnnTimestamp msg)
      , getNodeId (nodeAnnNodeId msg)
      , getRgbColor (nodeAnnRgbColor msg)
      , getAlias (nodeAnnAlias msg)
      , encodeLenPrefixed addrData
      ]

-- | Encode address list.
encodeAddresses :: [Address] -> Either EncodeError ByteString
encodeAddresses :: [Address] -> Either EncodeError ByteString
encodeAddresses [Address]
addrs = ByteString -> Either EncodeError ByteString
forall a b. b -> Either a b
Right (ByteString -> Either EncodeError ByteString)
-> ByteString -> Either EncodeError ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat ((Address -> ByteString) -> [Address] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map Address -> ByteString
encodeAddress [Address]
addrs)
  where
    encodeAddress :: Address -> ByteString
    encodeAddress :: Address -> ByteString
encodeAddress (AddrIPv4 IPv4Addr
a Word16
port) = [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
      [ Word8 -> ByteString
BS.singleton Word8
1
      , IPv4Addr -> ByteString
getIPv4Addr IPv4Addr
a
      , Word16 -> ByteString
Prim.encodeU16 Word16
port
      ]
    encodeAddress (AddrIPv6 IPv6Addr
a Word16
port) = [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
      [ Word8 -> ByteString
BS.singleton Word8
2
      , IPv6Addr -> ByteString
getIPv6Addr IPv6Addr
a
      , Word16 -> ByteString
Prim.encodeU16 Word16
port
      ]
    encodeAddress (AddrTorV3 TorV3Addr
a Word16
port) = [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
      [ Word8 -> ByteString
BS.singleton Word8
4
      , TorV3Addr -> ByteString
getTorV3Addr TorV3Addr
a
      , Word16 -> ByteString
Prim.encodeU16 Word16
port
      ]
    encodeAddress (AddrDNS ByteString
host Word16
port) = [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
      [ Word8 -> ByteString
BS.singleton Word8
5
      , Word8 -> ByteString
BS.singleton (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8) -> Int -> Word8
forall a b. (a -> b) -> a -> b
$ ByteString -> Int
BS.length ByteString
host)
      , ByteString
host
      , Word16 -> ByteString
Prim.encodeU16 Word16
port
      ]

-- | Decode node_announcement message.
decodeNodeAnnouncement :: ByteString
                       -> Either DecodeError (NodeAnnouncement, ByteString)
decodeNodeAnnouncement :: ByteString -> Either DecodeError (NodeAnnouncement, ByteString)
decodeNodeAnnouncement ByteString
bs = do
  (sig, bs1)       <- ByteString -> Either DecodeError (Signature, ByteString)
decodeSignature ByteString
bs
  (features, bs2)  <- decodeFeatureBits bs1
  (timestamp, bs3) <- decodeU32 bs2
  (nid, bs4)       <- decodeNodeId bs3
  (color, bs5)     <- decodeRgbColor bs4
  (al, bs6)        <- decodeAlias bs5
  (addrs, rest)    <- decodeAddresses bs6
  let msg = NodeAnnouncement
        { nodeAnnSignature :: Signature
nodeAnnSignature = Signature
sig
        , nodeAnnFeatures :: FeatureBits
nodeAnnFeatures  = FeatureBits
features
        , nodeAnnTimestamp :: Word32
nodeAnnTimestamp = Word32
timestamp
        , nodeAnnNodeId :: NodeId
nodeAnnNodeId    = NodeId
nid
        , nodeAnnRgbColor :: RgbColor
nodeAnnRgbColor  = RgbColor
color
        , nodeAnnAlias :: Alias
nodeAnnAlias     = Alias
al
        , nodeAnnAddresses :: [Address]
nodeAnnAddresses = [Address]
addrs
        }
  Right (msg, rest)

-- Channel update --------------------------------------------------------------

-- | Encode channel_update message.
encodeChannelUpdate :: ChannelUpdate -> ByteString
encodeChannelUpdate :: ChannelUpdate -> ByteString
encodeChannelUpdate ChannelUpdate
msg = [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
  [ Signature -> ByteString
getSignature (ChannelUpdate -> Signature
chanUpdateSignature ChannelUpdate
msg)
  , ChainHash -> ByteString
getChainHash (ChannelUpdate -> ChainHash
chanUpdateChainHash ChannelUpdate
msg)
  , ShortChannelId -> ByteString
getShortChannelId (ChannelUpdate -> ShortChannelId
chanUpdateShortChanId ChannelUpdate
msg)
  , Word32 -> ByteString
Prim.encodeU32 (ChannelUpdate -> Word32
chanUpdateTimestamp ChannelUpdate
msg)
  , Word8 -> ByteString
BS.singleton (MessageFlags -> Word8
encodeMessageFlags (ChannelUpdate -> MessageFlags
chanUpdateMsgFlags ChannelUpdate
msg))
  , Word8 -> ByteString
BS.singleton (ChannelFlags -> Word8
encodeChannelFlags (ChannelUpdate -> ChannelFlags
chanUpdateChanFlags ChannelUpdate
msg))
  , Word16 -> ByteString
Prim.encodeU16 (CltvExpiryDelta -> Word16
getCltvExpiryDelta (ChannelUpdate -> CltvExpiryDelta
chanUpdateCltvExpDelta ChannelUpdate
msg))
  , Word64 -> ByteString
Prim.encodeU64 (HtlcMinimumMsat -> Word64
getHtlcMinimumMsat (ChannelUpdate -> HtlcMinimumMsat
chanUpdateHtlcMinMsat ChannelUpdate
msg))
  , Word32 -> ByteString
Prim.encodeU32 (FeeBaseMsat -> Word32
getFeeBaseMsat (ChannelUpdate -> FeeBaseMsat
chanUpdateFeeBaseMsat ChannelUpdate
msg))
  , Word32 -> ByteString
Prim.encodeU32 (FeeProportionalMillionths -> Word32
getFeeProportionalMillionths (ChannelUpdate -> FeeProportionalMillionths
chanUpdateFeeProportional ChannelUpdate
msg))
  , case ChannelUpdate -> Maybe HtlcMaximumMsat
chanUpdateHtlcMaxMsat ChannelUpdate
msg of
      Maybe HtlcMaximumMsat
Nothing -> ByteString
BS.empty
      Just HtlcMaximumMsat
m  -> Word64 -> ByteString
Prim.encodeU64 (HtlcMaximumMsat -> Word64
getHtlcMaximumMsat HtlcMaximumMsat
m)
  ]

-- | Decode channel_update message.
decodeChannelUpdate :: ByteString
                    -> Either DecodeError (ChannelUpdate, ByteString)
decodeChannelUpdate :: ByteString -> Either DecodeError (ChannelUpdate, ByteString)
decodeChannelUpdate ByteString
bs = do
  (sig, bs1)         <- ByteString -> Either DecodeError (Signature, ByteString)
decodeSignature ByteString
bs
  (chainH, bs2)      <- decodeChainHash bs1
  (scid, bs3)        <- decodeShortChannelId bs2
  (timestamp, bs4)   <- decodeU32 bs3
  (msgFlagsRaw, bs5) <- decodeU8 bs4
  (chanFlagsRaw, bs6) <- decodeU8 bs5
  (cltvDelta, bs7)   <- decodeU16 bs6
  (htlcMin, bs8)     <- decodeU64 bs7
  (feeBase, bs9)     <- decodeU32 bs8
  (feeProp, bs10)    <- decodeU32 bs9
  let msgFlags' = Word8 -> MessageFlags
decodeMessageFlags Word8
msgFlagsRaw
      chanFlags' = Word8 -> ChannelFlags
decodeChannelFlags Word8
chanFlagsRaw
  -- htlc_maximum_msat is present if message_flags bit 0 is set
  (htlcMax, rest) <- if mfHtlcMaxPresent msgFlags'
    then do
      (m, r) <- decodeU64 bs10
      Right (Just (HtlcMaximumMsat m), r)
    else Right (Nothing, bs10)
  let msg = ChannelUpdate
        { chanUpdateSignature :: Signature
chanUpdateSignature       = Signature
sig
        , chanUpdateChainHash :: ChainHash
chanUpdateChainHash       = ChainHash
chainH
        , chanUpdateShortChanId :: ShortChannelId
chanUpdateShortChanId     = ShortChannelId
scid
        , chanUpdateTimestamp :: Word32
chanUpdateTimestamp       = Word32
timestamp
        , chanUpdateMsgFlags :: MessageFlags
chanUpdateMsgFlags        = MessageFlags
msgFlags'
        , chanUpdateChanFlags :: ChannelFlags
chanUpdateChanFlags       = ChannelFlags
chanFlags'
        , chanUpdateCltvExpDelta :: CltvExpiryDelta
chanUpdateCltvExpDelta    = Word16 -> CltvExpiryDelta
CltvExpiryDelta Word16
cltvDelta
        , chanUpdateHtlcMinMsat :: HtlcMinimumMsat
chanUpdateHtlcMinMsat     = Word64 -> HtlcMinimumMsat
HtlcMinimumMsat Word64
htlcMin
        , chanUpdateFeeBaseMsat :: FeeBaseMsat
chanUpdateFeeBaseMsat     = Word32 -> FeeBaseMsat
FeeBaseMsat Word32
feeBase
        , chanUpdateFeeProportional :: FeeProportionalMillionths
chanUpdateFeeProportional = Word32 -> FeeProportionalMillionths
FeeProportionalMillionths Word32
feeProp
        , chanUpdateHtlcMaxMsat :: Maybe HtlcMaximumMsat
chanUpdateHtlcMaxMsat     = Maybe HtlcMaximumMsat
htlcMax
        }
  Right (msg, rest)

-- Announcement signatures -----------------------------------------------------

-- | Encode announcement_signatures message.
encodeAnnouncementSignatures :: AnnouncementSignatures -> ByteString
encodeAnnouncementSignatures :: AnnouncementSignatures -> ByteString
encodeAnnouncementSignatures AnnouncementSignatures
msg = [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
  [ ChannelId -> ByteString
getChannelId (AnnouncementSignatures -> ChannelId
annSigChannelId AnnouncementSignatures
msg)
  , ShortChannelId -> ByteString
getShortChannelId (AnnouncementSignatures -> ShortChannelId
annSigShortChanId AnnouncementSignatures
msg)
  , Signature -> ByteString
getSignature (AnnouncementSignatures -> Signature
annSigNodeSig AnnouncementSignatures
msg)
  , Signature -> ByteString
getSignature (AnnouncementSignatures -> Signature
annSigBitcoinSig AnnouncementSignatures
msg)
  ]

-- | Decode announcement_signatures message.
decodeAnnouncementSignatures :: ByteString
                             -> Either DecodeError
                                  (AnnouncementSignatures, ByteString)
decodeAnnouncementSignatures :: ByteString
-> Either DecodeError (AnnouncementSignatures, ByteString)
decodeAnnouncementSignatures ByteString
bs = do
  (cid, bs1)     <- ByteString -> Either DecodeError (ChannelId, ByteString)
decodeChannelId ByteString
bs
  (scid, bs2)    <- decodeShortChannelId bs1
  (nodeSig, bs3) <- decodeSignature bs2
  (btcSig, rest) <- decodeSignature bs3
  let msg = AnnouncementSignatures
        { annSigChannelId :: ChannelId
annSigChannelId   = ChannelId
cid
        , annSigShortChanId :: ShortChannelId
annSigShortChanId = ShortChannelId
scid
        , annSigNodeSig :: Signature
annSigNodeSig     = Signature
nodeSig
        , annSigBitcoinSig :: Signature
annSigBitcoinSig  = Signature
btcSig
        }
  Right (msg, rest)

-- Query messages --------------------------------------------------------------

-- | Encode query_short_channel_ids message.
encodeQueryShortChannelIds :: QueryShortChannelIds
                           -> Either EncodeError ByteString
encodeQueryShortChannelIds :: QueryShortChannelIds -> Either EncodeError ByteString
encodeQueryShortChannelIds QueryShortChannelIds
msg = do
  let scidData :: ByteString
scidData = QueryShortChannelIds -> ByteString
queryScidsData QueryShortChannelIds
msg
  if ByteString -> Int
BS.length ByteString
scidData Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
65535
    then EncodeError -> Either EncodeError ByteString
forall a b. a -> Either a b
Left EncodeError
EncodeLengthOverflow
    else ByteString -> Either EncodeError ByteString
forall a b. b -> Either a b
Right (ByteString -> Either EncodeError ByteString)
-> ByteString -> Either EncodeError ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
      [ ChainHash -> ByteString
getChainHash (QueryShortChannelIds -> ChainHash
queryScidsChainHash QueryShortChannelIds
msg)
      , ByteString -> ByteString
encodeLenPrefixed ByteString
scidData
      , TlvStream -> ByteString
TLV.encodeTlvStream (QueryShortChannelIds -> TlvStream
queryScidsTlvs QueryShortChannelIds
msg)
      ]

-- | Decode query_short_channel_ids message.
decodeQueryShortChannelIds :: ByteString
                           -> Either DecodeError
                                (QueryShortChannelIds, ByteString)
decodeQueryShortChannelIds :: ByteString -> Either DecodeError (QueryShortChannelIds, ByteString)
decodeQueryShortChannelIds ByteString
bs = do
  (chainH, bs1)   <- ByteString -> Either DecodeError (ChainHash, ByteString)
decodeChainHash ByteString
bs
  (scidData, bs2) <- decodeLenPrefixed bs1
  let tlvs = case ByteString -> Either TlvError TlvStream
TLV.decodeTlvStreamRaw ByteString
bs2 of
        Left TlvError
_  -> [TlvRecord] -> TlvStream
unsafeTlvStream []
        Right TlvStream
t -> TlvStream
t
  let msg = QueryShortChannelIds
        { queryScidsChainHash :: ChainHash
queryScidsChainHash = ChainHash
chainH
        , queryScidsData :: ByteString
queryScidsData      = ByteString
scidData
        , queryScidsTlvs :: TlvStream
queryScidsTlvs      = TlvStream
tlvs
        }
  Right (msg, BS.empty)

-- | Encode reply_short_channel_ids_end message.
encodeReplyShortChannelIdsEnd :: ReplyShortChannelIdsEnd -> ByteString
encodeReplyShortChannelIdsEnd :: ReplyShortChannelIdsEnd -> ByteString
encodeReplyShortChannelIdsEnd ReplyShortChannelIdsEnd
msg = [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
  [ ChainHash -> ByteString
getChainHash (ReplyShortChannelIdsEnd -> ChainHash
replyScidsChainHash ReplyShortChannelIdsEnd
msg)
  , Word8 -> ByteString
BS.singleton (ReplyShortChannelIdsEnd -> Word8
replyScidsFullInfo ReplyShortChannelIdsEnd
msg)
  ]

-- | Decode reply_short_channel_ids_end message.
decodeReplyShortChannelIdsEnd :: ByteString
                              -> Either DecodeError
                                   (ReplyShortChannelIdsEnd, ByteString)
decodeReplyShortChannelIdsEnd :: ByteString
-> Either DecodeError (ReplyShortChannelIdsEnd, ByteString)
decodeReplyShortChannelIdsEnd ByteString
bs = do
  (chainH, bs1)    <- ByteString -> Either DecodeError (ChainHash, ByteString)
decodeChainHash ByteString
bs
  (fullInfo, rest) <- decodeU8 bs1
  let msg = ReplyShortChannelIdsEnd
        { replyScidsChainHash :: ChainHash
replyScidsChainHash = ChainHash
chainH
        , replyScidsFullInfo :: Word8
replyScidsFullInfo  = Word8
fullInfo
        }
  Right (msg, rest)

-- | Encode query_channel_range message.
encodeQueryChannelRange :: QueryChannelRange -> ByteString
encodeQueryChannelRange :: QueryChannelRange -> ByteString
encodeQueryChannelRange QueryChannelRange
msg = [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
  [ ChainHash -> ByteString
getChainHash (QueryChannelRange -> ChainHash
queryRangeChainHash QueryChannelRange
msg)
  , Word32 -> ByteString
Prim.encodeU32 (QueryChannelRange -> Word32
queryRangeFirstBlock QueryChannelRange
msg)
  , Word32 -> ByteString
Prim.encodeU32 (QueryChannelRange -> Word32
queryRangeNumBlocks QueryChannelRange
msg)
  , TlvStream -> ByteString
TLV.encodeTlvStream (QueryChannelRange -> TlvStream
queryRangeTlvs QueryChannelRange
msg)
  ]

-- | Decode query_channel_range message.
decodeQueryChannelRange :: ByteString
                        -> Either DecodeError (QueryChannelRange, ByteString)
decodeQueryChannelRange :: ByteString -> Either DecodeError (QueryChannelRange, ByteString)
decodeQueryChannelRange ByteString
bs = do
  (chainH, bs1)     <- ByteString -> Either DecodeError (ChainHash, ByteString)
decodeChainHash ByteString
bs
  (firstBlock, bs2) <- decodeU32 bs1
  (numBlocks, bs3)  <- decodeU32 bs2
  let tlvs = case ByteString -> Either TlvError TlvStream
TLV.decodeTlvStreamRaw ByteString
bs3 of
        Left TlvError
_  -> [TlvRecord] -> TlvStream
unsafeTlvStream []
        Right TlvStream
t -> TlvStream
t
  let msg = QueryChannelRange
        { queryRangeChainHash :: ChainHash
queryRangeChainHash  = ChainHash
chainH
        , queryRangeFirstBlock :: Word32
queryRangeFirstBlock = Word32
firstBlock
        , queryRangeNumBlocks :: Word32
queryRangeNumBlocks  = Word32
numBlocks
        , queryRangeTlvs :: TlvStream
queryRangeTlvs       = TlvStream
tlvs
        }
  Right (msg, BS.empty)

-- | Encode reply_channel_range message.
encodeReplyChannelRange :: ReplyChannelRange -> Either EncodeError ByteString
encodeReplyChannelRange :: ReplyChannelRange -> Either EncodeError ByteString
encodeReplyChannelRange ReplyChannelRange
msg = do
  let rangeData :: ByteString
rangeData = ReplyChannelRange -> ByteString
replyRangeData ReplyChannelRange
msg
  if ByteString -> Int
BS.length ByteString
rangeData Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
65535
    then EncodeError -> Either EncodeError ByteString
forall a b. a -> Either a b
Left EncodeError
EncodeLengthOverflow
    else ByteString -> Either EncodeError ByteString
forall a b. b -> Either a b
Right (ByteString -> Either EncodeError ByteString)
-> ByteString -> Either EncodeError ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
      [ ChainHash -> ByteString
getChainHash (ReplyChannelRange -> ChainHash
replyRangeChainHash ReplyChannelRange
msg)
      , Word32 -> ByteString
Prim.encodeU32 (ReplyChannelRange -> Word32
replyRangeFirstBlock ReplyChannelRange
msg)
      , Word32 -> ByteString
Prim.encodeU32 (ReplyChannelRange -> Word32
replyRangeNumBlocks ReplyChannelRange
msg)
      , Word8 -> ByteString
BS.singleton (ReplyChannelRange -> Word8
replyRangeSyncComplete ReplyChannelRange
msg)
      , ByteString -> ByteString
encodeLenPrefixed ByteString
rangeData
      , TlvStream -> ByteString
TLV.encodeTlvStream (ReplyChannelRange -> TlvStream
replyRangeTlvs ReplyChannelRange
msg)
      ]

-- | Decode reply_channel_range message.
decodeReplyChannelRange :: ByteString
                        -> Either DecodeError (ReplyChannelRange, ByteString)
decodeReplyChannelRange :: ByteString -> Either DecodeError (ReplyChannelRange, ByteString)
decodeReplyChannelRange ByteString
bs = do
  (chainH, bs1)       <- ByteString -> Either DecodeError (ChainHash, ByteString)
decodeChainHash ByteString
bs
  (firstBlock, bs2)   <- decodeU32 bs1
  (numBlocks, bs3)    <- decodeU32 bs2
  (syncComplete, bs4) <- decodeU8 bs3
  (rangeData, bs5)    <- decodeLenPrefixed bs4
  let tlvs = case ByteString -> Either TlvError TlvStream
TLV.decodeTlvStreamRaw ByteString
bs5 of
        Left TlvError
_  -> [TlvRecord] -> TlvStream
unsafeTlvStream []
        Right TlvStream
t -> TlvStream
t
  let msg = ReplyChannelRange
        { replyRangeChainHash :: ChainHash
replyRangeChainHash    = ChainHash
chainH
        , replyRangeFirstBlock :: Word32
replyRangeFirstBlock   = Word32
firstBlock
        , replyRangeNumBlocks :: Word32
replyRangeNumBlocks    = Word32
numBlocks
        , replyRangeSyncComplete :: Word8
replyRangeSyncComplete = Word8
syncComplete
        , replyRangeData :: ByteString
replyRangeData         = ByteString
rangeData
        , replyRangeTlvs :: TlvStream
replyRangeTlvs         = TlvStream
tlvs
        }
  Right (msg, BS.empty)

-- | Encode gossip_timestamp_filter message.
encodeGossipTimestampFilter :: GossipTimestampFilter -> ByteString
encodeGossipTimestampFilter :: GossipTimestampFilter -> ByteString
encodeGossipTimestampFilter GossipTimestampFilter
msg = [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
  [ ChainHash -> ByteString
getChainHash (GossipTimestampFilter -> ChainHash
gossipFilterChainHash GossipTimestampFilter
msg)
  , Word32 -> ByteString
Prim.encodeU32 (GossipTimestampFilter -> Word32
gossipFilterFirstTimestamp GossipTimestampFilter
msg)
  , Word32 -> ByteString
Prim.encodeU32 (GossipTimestampFilter -> Word32
gossipFilterTimestampRange GossipTimestampFilter
msg)
  ]

-- | Decode gossip_timestamp_filter message.
decodeGossipTimestampFilter :: ByteString
                            -> Either DecodeError
                                 (GossipTimestampFilter, ByteString)
decodeGossipTimestampFilter :: ByteString
-> Either DecodeError (GossipTimestampFilter, ByteString)
decodeGossipTimestampFilter ByteString
bs = do
  (chainH, bs1)   <- ByteString -> Either DecodeError (ChainHash, ByteString)
decodeChainHash ByteString
bs
  (firstTs, bs2)  <- decodeU32 bs1
  (tsRange, rest) <- decodeU32 bs2
  let msg = GossipTimestampFilter
        { gossipFilterChainHash :: ChainHash
gossipFilterChainHash      = ChainHash
chainH
        , gossipFilterFirstTimestamp :: Word32
gossipFilterFirstTimestamp = Word32
firstTs
        , gossipFilterTimestampRange :: Word32
gossipFilterTimestampRange = Word32
tsRange
        }
  Right (msg, rest)

-- Short channel ID list encoding -----------------------------------------------

-- | Encode a list of short channel IDs as concatenated 8-byte values.
--
-- This produces encoded_short_ids data with encoding type 0 (uncompressed).
-- The first byte is the encoding type (0), followed by the concatenated SCIDs.
--
-- Note: This does NOT sort the SCIDs. The caller should ensure they are in
-- ascending order if that's required by the protocol context.
encodeShortChannelIdList :: [ShortChannelId] -> ByteString
encodeShortChannelIdList :: [ShortChannelId] -> ByteString
encodeShortChannelIdList [ShortChannelId]
scids = Word8 -> ByteString -> ByteString
BS.cons Word8
0 (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$
  [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat ((ShortChannelId -> ByteString) -> [ShortChannelId] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map ShortChannelId -> ByteString
getShortChannelId [ShortChannelId]
scids)
{-# INLINE encodeShortChannelIdList #-}

-- | Decode a list of short channel IDs from encoded_short_ids data.
--
-- Supports encoding type 0 (uncompressed). Other encoding types will fail.
decodeShortChannelIdList :: ByteString
                         -> Either DecodeError [ShortChannelId]
decodeShortChannelIdList :: ByteString -> Either DecodeError [ShortChannelId]
decodeShortChannelIdList ByteString
bs
  | ByteString -> Bool
BS.null ByteString
bs = DecodeError -> Either DecodeError [ShortChannelId]
forall a b. a -> Either a b
Left DecodeError
DecodeInsufficientBytes
  | Bool
otherwise = do
      let encType :: Word8
encType = HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs Int
0
          payload :: ByteString
payload = Int -> ByteString -> ByteString
BS.drop Int
1 ByteString
bs
      case Word8
encType of
        Word8
0 -> ByteString -> Either DecodeError [ShortChannelId]
decodeUncompressedScids ByteString
payload
        Word8
_ -> DecodeError -> Either DecodeError [ShortChannelId]
forall a b. a -> Either a b
Left DecodeError
DecodeInvalidShortChannelId  -- Unsupported encoding type
  where
    decodeUncompressedScids :: ByteString -> Either DecodeError [ShortChannelId]
    decodeUncompressedScids :: ByteString -> Either DecodeError [ShortChannelId]
decodeUncompressedScids !ByteString
d
      | ByteString -> Bool
BS.null ByteString
d = [ShortChannelId] -> Either DecodeError [ShortChannelId]
forall a b. b -> Either a b
Right []
      | ByteString -> Int
BS.length ByteString
d Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
shortChannelIdLen = DecodeError -> Either DecodeError [ShortChannelId]
forall a b. a -> Either a b
Left DecodeError
DecodeInsufficientBytes
      | Bool
otherwise = do
          let (ByteString
scidBytes, ByteString
rest) = Int -> ByteString -> (ByteString, ByteString)
BS.splitAt Int
shortChannelIdLen ByteString
d
          case ByteString -> Maybe ShortChannelId
shortChannelId ByteString
scidBytes of
            Maybe ShortChannelId
Nothing -> DecodeError -> Either DecodeError [ShortChannelId]
forall a b. a -> Either a b
Left DecodeError
DecodeInvalidShortChannelId
            Just ShortChannelId
scid -> do
              scids <- ByteString -> Either DecodeError [ShortChannelId]
decodeUncompressedScids ByteString
rest
              Right (scid : scids)
{-# INLINE decodeShortChannelIdList #-}