bolt7

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

Weight.hs (12762B)


      1 {-# LANGUAGE BangPatterns #-}
      2 {-# LANGUAGE OverloadedStrings #-}
      3 
      4 -- |
      5 -- Module: Main
      6 -- Copyright: (c) 2025 Jared Tobin
      7 -- License: MIT
      8 -- Maintainer: Jared Tobin <jared@ppad.tech>
      9 --
     10 -- Weigh allocation benchmarks for BOLT #7 gossip codecs.
     11 
     12 module Main where
     13 
     14 import qualified Data.ByteString as BS
     15 import Lightning.Protocol.BOLT1 (TlvStream, unsafeTlvStream)
     16 import Lightning.Protocol.BOLT7
     17 import Weigh
     18 
     19 -- Test data construction ------------------------------------------------------
     20 
     21 -- | 32 zero bytes for chain hashes, etc.
     22 zeroBytes32 :: BS.ByteString
     23 zeroBytes32 = BS.replicate 32 0x00
     24 {-# NOINLINE zeroBytes32 #-}
     25 
     26 -- | 8 zero bytes for short channel IDs.
     27 zeroBytes8 :: BS.ByteString
     28 zeroBytes8 = BS.replicate 8 0x00
     29 {-# NOINLINE zeroBytes8 #-}
     30 
     31 -- | 64-byte signature.
     32 testSignature :: Signature
     33 testSignature = case signature (BS.replicate 64 0x01) of
     34   Just s  -> s
     35   Nothing -> error "testSignature: invalid"
     36 {-# NOINLINE testSignature #-}
     37 
     38 -- | 33-byte compressed public key (02 prefix + 32 zero bytes).
     39 testPoint :: Point
     40 testPoint = case point (BS.cons 0x02 zeroBytes32) of
     41   Just p  -> p
     42   Nothing -> error "testPoint: invalid"
     43 {-# NOINLINE testPoint #-}
     44 
     45 -- | 32-byte chain hash.
     46 testChainHash :: ChainHash
     47 testChainHash = case chainHash zeroBytes32 of
     48   Just h  -> h
     49   Nothing -> error "testChainHash: invalid"
     50 {-# NOINLINE testChainHash #-}
     51 
     52 -- | 8-byte short channel ID.
     53 testShortChannelId :: ShortChannelId
     54 testShortChannelId = case shortChannelId zeroBytes8 of
     55   Just s  -> s
     56   Nothing -> error "testShortChannelId: invalid"
     57 {-# NOINLINE testShortChannelId #-}
     58 
     59 -- | 32-byte channel ID.
     60 testChannelId :: ChannelId
     61 testChannelId = case channelId zeroBytes32 of
     62   Just c  -> c
     63   Nothing -> error "testChannelId: invalid"
     64 {-# NOINLINE testChannelId #-}
     65 
     66 -- | 33-byte node ID (03 prefix).
     67 testNodeId :: NodeId
     68 testNodeId = case nodeId (BS.cons 0x03 zeroBytes32) of
     69   Just n  -> n
     70   Nothing -> error "testNodeId: invalid"
     71 {-# NOINLINE testNodeId #-}
     72 
     73 -- | Second node ID (02 prefix, lexicographically smaller).
     74 testNodeId2 :: NodeId
     75 testNodeId2 = case nodeId (BS.cons 0x02 zeroBytes32) of
     76   Just n  -> n
     77   Nothing -> error "testNodeId2: invalid"
     78 {-# NOINLINE testNodeId2 #-}
     79 
     80 -- | RGB color.
     81 testRgbColor :: RgbColor
     82 testRgbColor = case rgbColor (BS.pack [0xff, 0x00, 0x00]) of
     83   Just c  -> c
     84   Nothing -> error "testRgbColor: invalid"
     85 {-# NOINLINE testRgbColor #-}
     86 
     87 -- | 32-byte alias.
     88 testAlias :: Alias
     89 testAlias = case alias zeroBytes32 of
     90   Just a  -> a
     91   Nothing -> error "testAlias: invalid"
     92 {-# NOINLINE testAlias #-}
     93 
     94 -- | IPv4 address.
     95 testIPv4 :: IPv4Addr
     96 testIPv4 = case ipv4Addr (BS.pack [127, 0, 0, 1]) of
     97   Just a  -> a
     98   Nothing -> error "testIPv4: invalid"
     99 {-# NOINLINE testIPv4 #-}
    100 
    101 -- | Empty feature bits.
    102 emptyFeatures :: FeatureBits
    103 emptyFeatures = featureBits BS.empty
    104 {-# NOINLINE emptyFeatures #-}
    105 
    106 -- | Empty TLV stream.
    107 emptyTlvs :: TlvStream
    108 emptyTlvs = unsafeTlvStream []
    109 {-# NOINLINE emptyTlvs #-}
    110 
    111 -- | List of test SCIDs for list encoding benchmarks.
    112 testScidList :: [ShortChannelId]
    113 testScidList = map mkScid [1..100]
    114   where
    115     mkScid n = case shortChannelId (BS.pack [0, 0, 0, n, 0, 0, 0, n]) of
    116       Just s  -> s
    117       Nothing -> error "mkScid: invalid"
    118 {-# NOINLINE testScidList #-}
    119 
    120 -- | Encoded SCID list for decode benchmarks.
    121 encodedScidList :: BS.ByteString
    122 encodedScidList = encodeShortChannelIdList testScidList
    123 {-# NOINLINE encodedScidList #-}
    124 
    125 -- Message constructors --------------------------------------------------------
    126 
    127 -- | Construct ChannelAnnouncement message.
    128 mkChannelAnnouncement
    129   :: Signature -> Signature -> ChainHash -> ShortChannelId
    130   -> NodeId -> NodeId -> Point -> Point -> FeatureBits
    131   -> ChannelAnnouncement
    132 mkChannelAnnouncement !ns1 !ns2 !ch !scid !nid1 !nid2 !bk1 !bk2 !feat =
    133   ChannelAnnouncement
    134     { channelAnnNodeSig1     = ns1
    135     , channelAnnNodeSig2     = ns2
    136     , channelAnnBitcoinSig1  = ns1
    137     , channelAnnBitcoinSig2  = ns2
    138     , channelAnnFeatures     = feat
    139     , channelAnnChainHash    = ch
    140     , channelAnnShortChanId  = scid
    141     , channelAnnNodeId1      = nid1
    142     , channelAnnNodeId2      = nid2
    143     , channelAnnBitcoinKey1  = bk1
    144     , channelAnnBitcoinKey2  = bk2
    145     }
    146 
    147 -- | Construct NodeAnnouncement message.
    148 mkNodeAnnouncement
    149   :: Signature -> FeatureBits -> NodeId -> RgbColor -> Alias
    150   -> [Address] -> NodeAnnouncement
    151 mkNodeAnnouncement !sig !feat !nid !col !al !addrs = NodeAnnouncement
    152   { nodeAnnSignature = sig
    153   , nodeAnnFeatures  = feat
    154   , nodeAnnTimestamp = 1234567890
    155   , nodeAnnNodeId    = nid
    156   , nodeAnnRgbColor  = col
    157   , nodeAnnAlias     = al
    158   , nodeAnnAddresses = addrs
    159   }
    160 
    161 -- | Construct ChannelUpdate message.
    162 mkChannelUpdate :: Signature -> ChainHash -> ShortChannelId -> ChannelUpdate
    163 mkChannelUpdate !sig !ch !scid = ChannelUpdate
    164   { chanUpdateSignature       = sig
    165   , chanUpdateChainHash       = ch
    166   , chanUpdateShortChanId     = scid
    167   , chanUpdateTimestamp       = 1234567890
    168   , chanUpdateMsgFlags        = 0x01
    169   , chanUpdateChanFlags       = 0x00
    170   , chanUpdateCltvExpDelta    = 144
    171   , chanUpdateHtlcMinMsat     = 1000
    172   , chanUpdateFeeBaseMsat     = 1000
    173   , chanUpdateFeeProportional = 100
    174   , chanUpdateHtlcMaxMsat     = Just 1000000000
    175   }
    176 
    177 -- | Construct AnnouncementSignatures message.
    178 mkAnnouncementSignatures
    179   :: ChannelId -> ShortChannelId -> Signature -> AnnouncementSignatures
    180 mkAnnouncementSignatures !cid !scid !sig = AnnouncementSignatures
    181   { annSigChannelId   = cid
    182   , annSigShortChanId = scid
    183   , annSigNodeSig     = sig
    184   , annSigBitcoinSig  = sig
    185   }
    186 
    187 -- | Construct GossipTimestampFilter message.
    188 mkGossipTimestampFilter :: ChainHash -> GossipTimestampFilter
    189 mkGossipTimestampFilter !ch = GossipTimestampFilter
    190   { gossipFilterChainHash      = ch
    191   , gossipFilterFirstTimestamp = 1609459200
    192   , gossipFilterTimestampRange = 86400
    193   }
    194 
    195 -- | Construct QueryChannelRange message.
    196 mkQueryChannelRange :: ChainHash -> TlvStream -> QueryChannelRange
    197 mkQueryChannelRange !ch !tlvs = QueryChannelRange
    198   { queryRangeChainHash  = ch
    199   , queryRangeFirstBlock = 700000
    200   , queryRangeNumBlocks  = 10000
    201   , queryRangeTlvs       = tlvs
    202   }
    203 
    204 -- | Construct ReplyChannelRange message.
    205 mkReplyChannelRange :: ChainHash -> TlvStream -> ReplyChannelRange
    206 mkReplyChannelRange !ch !tlvs = ReplyChannelRange
    207   { replyRangeChainHash    = ch
    208   , replyRangeFirstBlock   = 700000
    209   , replyRangeNumBlocks    = 10000
    210   , replyRangeSyncComplete = 1
    211   , replyRangeData         = encodeShortChannelIdList [testShortChannelId]
    212   , replyRangeTlvs         = tlvs
    213   }
    214 
    215 -- Pre-constructed messages ----------------------------------------------------
    216 
    217 -- | Test ChannelAnnouncement message.
    218 testChannelAnnouncement :: ChannelAnnouncement
    219 testChannelAnnouncement = mkChannelAnnouncement
    220   testSignature testSignature testChainHash testShortChannelId
    221   testNodeId2 testNodeId testPoint testPoint emptyFeatures
    222 {-# NOINLINE testChannelAnnouncement #-}
    223 
    224 -- | Encoded ChannelAnnouncement for decode benchmarks.
    225 encodedChannelAnnouncement :: BS.ByteString
    226 encodedChannelAnnouncement = encodeChannelAnnouncement testChannelAnnouncement
    227 {-# NOINLINE encodedChannelAnnouncement #-}
    228 
    229 -- | Test NodeAnnouncement message.
    230 testNodeAnnouncement :: NodeAnnouncement
    231 testNodeAnnouncement = mkNodeAnnouncement
    232   testSignature emptyFeatures testNodeId testRgbColor testAlias
    233   [AddrIPv4 testIPv4 9735]
    234 {-# NOINLINE testNodeAnnouncement #-}
    235 
    236 -- | Encoded NodeAnnouncement for decode benchmarks.
    237 encodedNodeAnnouncement :: BS.ByteString
    238 encodedNodeAnnouncement = case encodeNodeAnnouncement testNodeAnnouncement of
    239   Right bs -> bs
    240   Left _   -> error "encodedNodeAnnouncement: encode failed"
    241 {-# NOINLINE encodedNodeAnnouncement #-}
    242 
    243 -- | Test ChannelUpdate message.
    244 testChannelUpdate :: ChannelUpdate
    245 testChannelUpdate = mkChannelUpdate testSignature testChainHash testShortChannelId
    246 {-# NOINLINE testChannelUpdate #-}
    247 
    248 -- | Encoded ChannelUpdate for decode benchmarks.
    249 encodedChannelUpdate :: BS.ByteString
    250 encodedChannelUpdate = encodeChannelUpdate testChannelUpdate
    251 {-# NOINLINE encodedChannelUpdate #-}
    252 
    253 -- | Test AnnouncementSignatures message.
    254 testAnnouncementSignatures :: AnnouncementSignatures
    255 testAnnouncementSignatures =
    256   mkAnnouncementSignatures testChannelId testShortChannelId testSignature
    257 {-# NOINLINE testAnnouncementSignatures #-}
    258 
    259 -- | Encoded AnnouncementSignatures for decode benchmarks.
    260 encodedAnnouncementSignatures :: BS.ByteString
    261 encodedAnnouncementSignatures =
    262   encodeAnnouncementSignatures testAnnouncementSignatures
    263 {-# NOINLINE encodedAnnouncementSignatures #-}
    264 
    265 -- | Test GossipTimestampFilter message.
    266 testGossipTimestampFilter :: GossipTimestampFilter
    267 testGossipTimestampFilter = mkGossipTimestampFilter testChainHash
    268 {-# NOINLINE testGossipTimestampFilter #-}
    269 
    270 -- | Encoded GossipTimestampFilter for decode benchmarks.
    271 encodedGossipTimestampFilter :: BS.ByteString
    272 encodedGossipTimestampFilter =
    273   encodeGossipTimestampFilter testGossipTimestampFilter
    274 {-# NOINLINE encodedGossipTimestampFilter #-}
    275 
    276 -- | Test QueryChannelRange message.
    277 testQueryChannelRange :: QueryChannelRange
    278 testQueryChannelRange = mkQueryChannelRange testChainHash emptyTlvs
    279 {-# NOINLINE testQueryChannelRange #-}
    280 
    281 -- | Encoded QueryChannelRange for decode benchmarks.
    282 encodedQueryChannelRange :: BS.ByteString
    283 encodedQueryChannelRange = encodeQueryChannelRange testQueryChannelRange
    284 {-# NOINLINE encodedQueryChannelRange #-}
    285 
    286 -- | Test ReplyChannelRange message.
    287 testReplyChannelRange :: ReplyChannelRange
    288 testReplyChannelRange = mkReplyChannelRange testChainHash emptyTlvs
    289 {-# NOINLINE testReplyChannelRange #-}
    290 
    291 -- | Encoded ReplyChannelRange for decode benchmarks.
    292 encodedReplyChannelRange :: BS.ByteString
    293 encodedReplyChannelRange = case encodeReplyChannelRange testReplyChannelRange of
    294   Right bs -> bs
    295   Left _   -> error "encodedReplyChannelRange: encode failed"
    296 {-# NOINLINE encodedReplyChannelRange #-}
    297 
    298 -- Weigh benchmarks ------------------------------------------------------------
    299 
    300 main :: IO ()
    301 main = mainWith $ do
    302   wgroup "channel_announcement" $ do
    303     func "construct" (mkChannelAnnouncement
    304       testSignature testSignature testChainHash testShortChannelId
    305       testNodeId2 testNodeId testPoint testPoint) emptyFeatures
    306     func "encode" encodeChannelAnnouncement testChannelAnnouncement
    307     func "decode" decodeChannelAnnouncement encodedChannelAnnouncement
    308 
    309   wgroup "node_announcement" $ do
    310     func "construct" (mkNodeAnnouncement
    311       testSignature emptyFeatures testNodeId testRgbColor testAlias)
    312       [AddrIPv4 testIPv4 9735]
    313     func "encode" encodeNodeAnnouncement testNodeAnnouncement
    314     func "decode" decodeNodeAnnouncement encodedNodeAnnouncement
    315 
    316   wgroup "channel_update" $ do
    317     func "construct" (mkChannelUpdate testSignature testChainHash)
    318       testShortChannelId
    319     func "encode" encodeChannelUpdate testChannelUpdate
    320     func "decode" decodeChannelUpdate encodedChannelUpdate
    321 
    322   wgroup "announcement_signatures" $ do
    323     func "construct" (mkAnnouncementSignatures testChannelId testShortChannelId)
    324       testSignature
    325     func "encode" encodeAnnouncementSignatures testAnnouncementSignatures
    326     func "decode" decodeAnnouncementSignatures encodedAnnouncementSignatures
    327 
    328   wgroup "query_channel_range" $ do
    329     func "construct" (mkQueryChannelRange testChainHash) emptyTlvs
    330     func "encode" encodeQueryChannelRange testQueryChannelRange
    331     func "decode" decodeQueryChannelRange encodedQueryChannelRange
    332 
    333   wgroup "reply_channel_range" $ do
    334     func "construct" (mkReplyChannelRange testChainHash) emptyTlvs
    335     func "encode" encodeReplyChannelRange testReplyChannelRange
    336     func "decode" decodeReplyChannelRange encodedReplyChannelRange
    337 
    338   wgroup "gossip_timestamp_filter" $ do
    339     func "construct" mkGossipTimestampFilter testChainHash
    340     func "encode" encodeGossipTimestampFilter testGossipTimestampFilter
    341     func "decode" decodeGossipTimestampFilter encodedGossipTimestampFilter
    342 
    343   wgroup "scid_list" $ do
    344     func "encode (100)" encodeShortChannelIdList testScidList
    345     func "decode (100)" decodeShortChannelIdList encodedScidList
    346 
    347   wgroup "hash" $ do
    348     func "channelAnnouncementHash" channelAnnouncementHash
    349       encodedChannelAnnouncement
    350     func "nodeAnnouncementHash" nodeAnnouncementHash encodedNodeAnnouncement
    351     func "channelUpdateHash" channelUpdateHash encodedChannelUpdate
    352     func "channelUpdateChecksum" channelUpdateChecksum encodedChannelUpdate
    353 
    354   wgroup "validate" $ do
    355     func "channelAnnouncement" validateChannelAnnouncement testChannelAnnouncement
    356     func "nodeAnnouncement" validateNodeAnnouncement testNodeAnnouncement
    357     func "channelUpdate" validateChannelUpdate testChannelUpdate
    358     func "queryChannelRange" validateQueryChannelRange testQueryChannelRange
    359     func "replyChannelRange" validateReplyChannelRange testReplyChannelRange