bolt7

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

Main.hs (12585B)


      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 -- Criterion timing benchmarks for BOLT #7 gossip codecs.
     11 
     12 module Main where
     13 
     14 import Criterion.Main
     15 import qualified Data.ByteString as BS
     16 import Lightning.Protocol.BOLT1 (TlvStream, unsafeTlvStream)
     17 import Lightning.Protocol.BOLT7
     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 TLV stream.
    102 emptyTlvs :: TlvStream
    103 emptyTlvs = unsafeTlvStream []
    104 {-# NOINLINE emptyTlvs #-}
    105 
    106 -- | Empty feature bits.
    107 emptyFeatures :: FeatureBits
    108 emptyFeatures = featureBits BS.empty
    109 {-# NOINLINE emptyFeatures #-}
    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 -- Test messages ---------------------------------------------------------------
    126 
    127 -- | Test ChannelAnnouncement message.
    128 testChannelAnnouncement :: ChannelAnnouncement
    129 testChannelAnnouncement = ChannelAnnouncement
    130   { channelAnnNodeSig1     = testSignature
    131   , channelAnnNodeSig2     = testSignature
    132   , channelAnnBitcoinSig1  = testSignature
    133   , channelAnnBitcoinSig2  = testSignature
    134   , channelAnnFeatures     = emptyFeatures
    135   , channelAnnChainHash    = testChainHash
    136   , channelAnnShortChanId  = testShortChannelId
    137   , channelAnnNodeId1      = testNodeId2  -- 02... (smaller)
    138   , channelAnnNodeId2      = testNodeId   -- 03... (larger)
    139   , channelAnnBitcoinKey1  = testPoint
    140   , channelAnnBitcoinKey2  = testPoint
    141   }
    142 {-# NOINLINE testChannelAnnouncement #-}
    143 
    144 -- | Encoded ChannelAnnouncement for decode benchmarks.
    145 encodedChannelAnnouncement :: BS.ByteString
    146 encodedChannelAnnouncement = encodeChannelAnnouncement testChannelAnnouncement
    147 {-# NOINLINE encodedChannelAnnouncement #-}
    148 
    149 -- | Test NodeAnnouncement message.
    150 testNodeAnnouncement :: NodeAnnouncement
    151 testNodeAnnouncement = NodeAnnouncement
    152   { nodeAnnSignature = testSignature
    153   , nodeAnnFeatures  = emptyFeatures
    154   , nodeAnnTimestamp = 1234567890
    155   , nodeAnnNodeId    = testNodeId
    156   , nodeAnnRgbColor  = testRgbColor
    157   , nodeAnnAlias     = testAlias
    158   , nodeAnnAddresses = [AddrIPv4 testIPv4 9735]
    159   }
    160 {-# NOINLINE testNodeAnnouncement #-}
    161 
    162 -- | Encoded NodeAnnouncement for decode benchmarks.
    163 encodedNodeAnnouncement :: BS.ByteString
    164 encodedNodeAnnouncement = case encodeNodeAnnouncement testNodeAnnouncement of
    165   Right bs -> bs
    166   Left _   -> error "encodedNodeAnnouncement: encode failed"
    167 {-# NOINLINE encodedNodeAnnouncement #-}
    168 
    169 -- | Test ChannelUpdate message.
    170 testChannelUpdate :: ChannelUpdate
    171 testChannelUpdate = ChannelUpdate
    172   { chanUpdateSignature       = testSignature
    173   , chanUpdateChainHash       = testChainHash
    174   , chanUpdateShortChanId     = testShortChannelId
    175   , chanUpdateTimestamp       = 1234567890
    176   , chanUpdateMsgFlags        = 0x01
    177   , chanUpdateChanFlags       = 0x00
    178   , chanUpdateCltvExpDelta    = 144
    179   , chanUpdateHtlcMinMsat     = 1000
    180   , chanUpdateFeeBaseMsat     = 1000
    181   , chanUpdateFeeProportional = 100
    182   , chanUpdateHtlcMaxMsat     = Just 1000000000
    183   }
    184 {-# NOINLINE testChannelUpdate #-}
    185 
    186 -- | Encoded ChannelUpdate for decode benchmarks.
    187 encodedChannelUpdate :: BS.ByteString
    188 encodedChannelUpdate = encodeChannelUpdate testChannelUpdate
    189 {-# NOINLINE encodedChannelUpdate #-}
    190 
    191 -- | Test AnnouncementSignatures message.
    192 testAnnouncementSignatures :: AnnouncementSignatures
    193 testAnnouncementSignatures = AnnouncementSignatures
    194   { annSigChannelId   = testChannelId
    195   , annSigShortChanId = testShortChannelId
    196   , annSigNodeSig     = testSignature
    197   , annSigBitcoinSig  = testSignature
    198   }
    199 {-# NOINLINE testAnnouncementSignatures #-}
    200 
    201 -- | Encoded AnnouncementSignatures for decode benchmarks.
    202 encodedAnnouncementSignatures :: BS.ByteString
    203 encodedAnnouncementSignatures =
    204   encodeAnnouncementSignatures testAnnouncementSignatures
    205 {-# NOINLINE encodedAnnouncementSignatures #-}
    206 
    207 -- | Test QueryShortChannelIds message.
    208 testQueryShortChannelIds :: QueryShortChannelIds
    209 testQueryShortChannelIds = QueryShortChannelIds
    210   { queryScidsChainHash = testChainHash
    211   , queryScidsData      = encodeShortChannelIdList [testShortChannelId]
    212   , queryScidsTlvs      = emptyTlvs
    213   }
    214 {-# NOINLINE testQueryShortChannelIds #-}
    215 
    216 -- | Encoded QueryShortChannelIds for decode benchmarks.
    217 encodedQueryShortChannelIds :: BS.ByteString
    218 encodedQueryShortChannelIds =
    219   case encodeQueryShortChannelIds testQueryShortChannelIds of
    220     Right bs -> bs
    221     Left _   -> error "encodedQueryShortChannelIds: encode failed"
    222 {-# NOINLINE encodedQueryShortChannelIds #-}
    223 
    224 -- | Test ReplyShortChannelIdsEnd message.
    225 testReplyShortChannelIdsEnd :: ReplyShortChannelIdsEnd
    226 testReplyShortChannelIdsEnd = ReplyShortChannelIdsEnd
    227   { replyScidsChainHash = testChainHash
    228   , replyScidsFullInfo  = 1
    229   }
    230 {-# NOINLINE testReplyShortChannelIdsEnd #-}
    231 
    232 -- | Encoded ReplyShortChannelIdsEnd for decode benchmarks.
    233 encodedReplyShortChannelIdsEnd :: BS.ByteString
    234 encodedReplyShortChannelIdsEnd =
    235   encodeReplyShortChannelIdsEnd testReplyShortChannelIdsEnd
    236 {-# NOINLINE encodedReplyShortChannelIdsEnd #-}
    237 
    238 -- | Test QueryChannelRange message.
    239 testQueryChannelRange :: QueryChannelRange
    240 testQueryChannelRange = QueryChannelRange
    241   { queryRangeChainHash  = testChainHash
    242   , queryRangeFirstBlock = 700000
    243   , queryRangeNumBlocks  = 10000
    244   , queryRangeTlvs       = emptyTlvs
    245   }
    246 {-# NOINLINE testQueryChannelRange #-}
    247 
    248 -- | Encoded QueryChannelRange for decode benchmarks.
    249 encodedQueryChannelRange :: BS.ByteString
    250 encodedQueryChannelRange = encodeQueryChannelRange testQueryChannelRange
    251 {-# NOINLINE encodedQueryChannelRange #-}
    252 
    253 -- | Test ReplyChannelRange message.
    254 testReplyChannelRange :: ReplyChannelRange
    255 testReplyChannelRange = ReplyChannelRange
    256   { replyRangeChainHash    = testChainHash
    257   , replyRangeFirstBlock   = 700000
    258   , replyRangeNumBlocks    = 10000
    259   , replyRangeSyncComplete = 1
    260   , replyRangeData         = encodeShortChannelIdList [testShortChannelId]
    261   , replyRangeTlvs         = emptyTlvs
    262   }
    263 {-# NOINLINE testReplyChannelRange #-}
    264 
    265 -- | Encoded ReplyChannelRange for decode benchmarks.
    266 encodedReplyChannelRange :: BS.ByteString
    267 encodedReplyChannelRange = case encodeReplyChannelRange testReplyChannelRange of
    268   Right bs -> bs
    269   Left _   -> error "encodedReplyChannelRange: encode failed"
    270 {-# NOINLINE encodedReplyChannelRange #-}
    271 
    272 -- | Test GossipTimestampFilter message.
    273 testGossipTimestampFilter :: GossipTimestampFilter
    274 testGossipTimestampFilter = GossipTimestampFilter
    275   { gossipFilterChainHash      = testChainHash
    276   , gossipFilterFirstTimestamp = 1609459200
    277   , gossipFilterTimestampRange = 86400
    278   }
    279 {-# NOINLINE testGossipTimestampFilter #-}
    280 
    281 -- | Encoded GossipTimestampFilter for decode benchmarks.
    282 encodedGossipTimestampFilter :: BS.ByteString
    283 encodedGossipTimestampFilter =
    284   encodeGossipTimestampFilter testGossipTimestampFilter
    285 {-# NOINLINE encodedGossipTimestampFilter #-}
    286 
    287 -- Benchmark groups ------------------------------------------------------------
    288 
    289 main :: IO ()
    290 main = defaultMain
    291   [ bgroup "channel_announcement"
    292       [ bench "encode" $ nf encodeChannelAnnouncement testChannelAnnouncement
    293       , bench "decode" $ nf decodeChannelAnnouncement encodedChannelAnnouncement
    294       ]
    295   , bgroup "node_announcement"
    296       [ bench "encode" $ nf encodeNodeAnnouncement testNodeAnnouncement
    297       , bench "decode" $ nf decodeNodeAnnouncement encodedNodeAnnouncement
    298       ]
    299   , bgroup "channel_update"
    300       [ bench "encode" $ nf encodeChannelUpdate testChannelUpdate
    301       , bench "decode" $ nf decodeChannelUpdate encodedChannelUpdate
    302       ]
    303   , bgroup "announcement_signatures"
    304       [ bench "encode" $
    305           nf encodeAnnouncementSignatures testAnnouncementSignatures
    306       , bench "decode" $
    307           nf decodeAnnouncementSignatures encodedAnnouncementSignatures
    308       ]
    309   , bgroup "query_short_channel_ids"
    310       [ bench "encode" $
    311           nf encodeQueryShortChannelIds testQueryShortChannelIds
    312       , bench "decode" $
    313           nf decodeQueryShortChannelIds encodedQueryShortChannelIds
    314       ]
    315   , bgroup "reply_short_channel_ids_end"
    316       [ bench "encode" $
    317           nf encodeReplyShortChannelIdsEnd testReplyShortChannelIdsEnd
    318       , bench "decode" $
    319           nf decodeReplyShortChannelIdsEnd encodedReplyShortChannelIdsEnd
    320       ]
    321   , bgroup "query_channel_range"
    322       [ bench "encode" $ nf encodeQueryChannelRange testQueryChannelRange
    323       , bench "decode" $ nf decodeQueryChannelRange encodedQueryChannelRange
    324       ]
    325   , bgroup "reply_channel_range"
    326       [ bench "encode" $ nf encodeReplyChannelRange testReplyChannelRange
    327       , bench "decode" $ nf decodeReplyChannelRange encodedReplyChannelRange
    328       ]
    329   , bgroup "gossip_timestamp_filter"
    330       [ bench "encode" $
    331           nf encodeGossipTimestampFilter testGossipTimestampFilter
    332       , bench "decode" $
    333           nf decodeGossipTimestampFilter encodedGossipTimestampFilter
    334       ]
    335   , bgroup "scid_list"
    336       [ bench "encode (100)" $ nf encodeShortChannelIdList testScidList
    337       , bench "decode (100)" $ nf decodeShortChannelIdList encodedScidList
    338       ]
    339   , bgroup "hash"
    340       [ bench "channelAnnouncementHash" $
    341           nf channelAnnouncementHash encodedChannelAnnouncement
    342       , bench "nodeAnnouncementHash" $
    343           nf nodeAnnouncementHash encodedNodeAnnouncement
    344       , bench "channelUpdateHash" $
    345           nf channelUpdateHash encodedChannelUpdate
    346       , bench "channelUpdateChecksum" $
    347           nf channelUpdateChecksum encodedChannelUpdate
    348       ]
    349   , bgroup "validate"
    350       [ bench "channelAnnouncement" $
    351           nf validateChannelAnnouncement testChannelAnnouncement
    352       , bench "nodeAnnouncement" $
    353           nf validateNodeAnnouncement testNodeAnnouncement
    354       , bench "channelUpdate" $
    355           nf validateChannelUpdate testChannelUpdate
    356       , bench "queryChannelRange" $
    357           nf validateQueryChannelRange testQueryChannelRange
    358       , bench "replyChannelRange" $
    359           nf validateReplyChannelRange testReplyChannelRange
    360       ]
    361   ]