commit c6633cfbe6a81ac5fab87dbbbe10879ee04e5a37
parent cc26a14c9df241afa7f2775e2b38a0935f9af18a
Author: Jared Tobin <jared@jtobin.io>
Date: Sat, 10 Oct 2026 14:31:08 +0400
bench: rewrite for the new API
Criterion and weigh suites share fixtures built from real gossip, a
signed node_announcement and 1000-id query replies, and cover decoding,
encoding, digests, checksums, signature verification and validation.
Fixtures are built totally; the suites exit if they fail.
Diffstat:
| A | bench/Fixtures.hs | | | 116 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | bench/Main.hs | | | 399 | ++++++++++--------------------------------------------------------------------- |
| M | bench/Weight.hs | | | 379 | +++++++------------------------------------------------------------------------ |
| M | ppad-bolt7.cabal | | | 6 | ++++-- |
4 files changed, 200 insertions(+), 700 deletions(-)
diff --git a/bench/Fixtures.hs b/bench/Fixtures.hs
@@ -0,0 +1,116 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- |
+-- Module: Fixtures
+-- Copyright: (c) 2025 Jared Tobin
+-- License: MIT
+-- Maintainer: Jared Tobin <jared@ppad.tech>
+--
+-- Benchmark inputs: real mainnet gossip, a signed node_announcement, and
+-- large gossip query replies.
+
+module Fixtures (
+ Fixtures(..)
+ , fixtures
+ ) where
+
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Base16 as B16
+import qualified Lightning.Protocol.BOLT1 as BOLT1
+import Lightning.Protocol.BOLT7
+
+data Fixtures = Fixtures
+ { f_ann_bytes :: !BS.ByteString
+ , f_ann :: !ChannelAnnouncement
+ , f_upd_bytes :: !BS.ByteString
+ , f_upd :: !ChannelUpdate
+ , f_upd_key :: !BOLT1.Point
+ , f_node_bytes :: !BS.ByteString
+ , f_node :: !NodeAnnouncement
+ , f_qsci_bytes :: !BS.ByteString
+ , f_qsci :: !QueryShortChannelIds
+ , f_rcr_bytes :: !BS.ByteString
+ , f_rcr :: !ReplyChannelRange
+ }
+
+-- | The fixtures, or 'Nothing' if one fails to build.
+fixtures :: Maybe Fixtures
+fixtures = do
+ ann_bytes <- B16.decode ann_hex
+ ann <- right (decode_channel_announcement ann_bytes)
+ upd_bytes <- B16.decode upd_hex
+ upd <- right (decode_channel_update upd_bytes)
+ node_bytes <- B16.decode node_hex
+ node <- right (decode_node_announcement node_bytes)
+ ch <- BOLT1.chain_hash (BS.replicate 32 0x6f)
+ let ids = [ BOLT1.ShortChannelId (0x0cf88400000000 + 0x10000 * i)
+ | i <- [1 .. 1000] ]
+ qsci = QueryShortChannelIds ch ids
+ (Just (map (\i -> QueryFlags (i `mod` 32)) [1 .. 1000]))
+ BOLT1.empty_tlv_stream
+ rcr = ReplyChannelRange ch 850000 10000 True ids
+ (Just [ ChannelUpdateTimestamps (1776493010 + i) (1776493020 + i)
+ | i <- [1 .. 1000] ])
+ (Just [ ChannelUpdateChecksums (0x1da953bd + i) (0xf0a89fda + i)
+ | i <- [1 .. 1000] ])
+ BOLT1.empty_tlv_stream
+ qsci_bytes <- right (encode_query_short_channel_ids qsci)
+ rcr_bytes <- right (encode_reply_channel_range rcr)
+ pure Fixtures
+ { f_ann_bytes = ann_bytes
+ , f_ann = ann
+ , f_upd_bytes = upd_bytes
+ , f_upd = upd
+ , f_upd_key = ca_node_id_1 ann
+ , f_node_bytes = node_bytes
+ , f_node = node
+ , f_qsci_bytes = qsci_bytes
+ , f_qsci = qsci
+ , f_rcr_bytes = rcr_bytes
+ , f_rcr = rcr
+ }
+ where
+ right :: Either e a -> Maybe a
+ right = either (const Nothing) Just
+
+-- channel_announcement for 850052x2992x1
+ann_hex :: BS.ByteString
+ann_hex = mconcat
+ [ "3c256c270126d2c52ab5464fa959d627e9baec8c76bd2b81d34b47c4efb03290"
+ , "40126ea7a0f8d31420976dc28ff684dc63f62620fa10dbac4fe3d417ca5690c1"
+ , "b7fe1de61f5dd2b8368886d6c98f625c9110198e57c14fac93d4eff34e19ce5f"
+ , "5dc6fef4501e8105c8f9b82d6d0b348f5840864445b071ae7a741b5eb92d2ec0"
+ , "ab85681e4e1e85144bbbd8757c14cee92468d2c5ac84345cb28931b6fed5e339"
+ , "00ed9dd363db630f31248cfa933a3667cbf87bb78a48a442e81c652686355365"
+ , "ff33164c7588f0a753d50c4d52dd4a81c611fa47b4e950dfc9e3379a12ef7834"
+ , "781c0900b90f56a5a49893446d03c8d283c3c093e3c8c682ff6cb40d70d9eebc"
+ , "00006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000"
+ , "00000cf884000bb0000102bb5e47ee26aca1654ce092d9d06eac15d953210c73"
+ , "7f2220e2d7e54c4f108677030b828fd1e42549fbc2f1d0960ec3663362c41777"
+ , "d3d87fe1b8e1d4bf063abcaa02bc3f260955062a4f427704edef1864c76d6777"
+ , "fe81bed43a5f6297dda1c7ca9203523e164f4f9fbdea978c6570d56b13ca8338"
+ , "430e6794ff74cf6aa0dbda71dd2d"
+ ]
+
+-- a channel_update for it from node_id_1, with an inbound-fee extension
+upd_hex :: BS.ByteString
+upd_hex = mconcat
+ [ "1c3f0859cb3f4494919c3dcc80d22bbf1e25e378bd95f071530833c2371c33d7"
+ , "0766012ebef1cd79b299a54d0d29bea2ef6feca1d6cfa188864c95d7eea7e9a4"
+ , "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000"
+ , "0cf884000bb000016a0a1c760100006400000000000003e80000000000001388"
+ , "00000000b1069a80fdd9030800000000ffffffed"
+ ]
+
+-- a node_announcement with one address descriptor of each type
+node_hex :: BS.ByteString
+node_hex = mconcat
+ [ "edbd2df19aee2f072d9665e2d9a2807fbcd4be6876f6863955ea11870e411e66"
+ , "063a31dcef14f1983524f87e108ee556b3a6646c873cd4bbcc07512c8f5e8f6a"
+ , "000908000000000002aaa26553f1000324653eac434488002cc06bbfb7f10fe1"
+ , "8991e35f9fe4302dbea6d2353dc0ab1c314159707061642d626f6c7437000000"
+ , "000000000000000000000000000000000000000063017f000001260702000000"
+ , "00000000000000000000000001260703aaaaaaaaaaaaaaaaaaaaaaaa04bbbbbb"
+ , "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+ , "2607050e6c6e2e6578616d706c652e636f6d2607060102036503657874"
+ ]
diff --git a/bench/Main.hs b/bench/Main.hs
@@ -1,363 +1,62 @@
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE OverloadedStrings #-}
-
-- |
-- Module: Main
-- Copyright: (c) 2025 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
--- Criterion timing benchmarks for BOLT #7 gossip codecs.
+-- Criterion timing benchmarks for ppad-bolt7.
module Main where
import Criterion.Main
-import qualified Data.ByteString as BS
-import Lightning.Protocol.BOLT1 (TlvStream, unsafeTlvStream)
+import Fixtures
import Lightning.Protocol.BOLT7
-
--- Test data construction ------------------------------------------------------
-
--- | 32 zero bytes for chain hashes, etc.
-zeroBytes32 :: BS.ByteString
-zeroBytes32 = BS.replicate 32 0x00
-{-# NOINLINE zeroBytes32 #-}
-
--- | 8 zero bytes for short channel IDs.
-zeroBytes8 :: BS.ByteString
-zeroBytes8 = BS.replicate 8 0x00
-{-# NOINLINE zeroBytes8 #-}
-
--- | 64-byte signature.
-testSignature :: Signature
-testSignature = case signature (BS.replicate 64 0x01) of
- Just s -> s
- Nothing -> error "testSignature: invalid"
-{-# NOINLINE testSignature #-}
-
--- | 33-byte compressed public key (02 prefix + 32 zero bytes).
-testPoint :: Point
-testPoint = case point (BS.cons 0x02 zeroBytes32) of
- Just p -> p
- Nothing -> error "testPoint: invalid"
-{-# NOINLINE testPoint #-}
-
--- | 32-byte chain hash.
-testChainHash :: ChainHash
-testChainHash = case chainHash zeroBytes32 of
- Just h -> h
- Nothing -> error "testChainHash: invalid"
-{-# NOINLINE testChainHash #-}
-
--- | 8-byte short channel ID.
-testShortChannelId :: ShortChannelId
-testShortChannelId = case scidFromBytes zeroBytes8 of
- Just s -> s
- Nothing -> error "testShortChannelId: invalid"
-{-# NOINLINE testShortChannelId #-}
-
--- | 32-byte channel ID.
-testChannelId :: ChannelId
-testChannelId = case channelId zeroBytes32 of
- Just c -> c
- Nothing -> error "testChannelId: invalid"
-{-# NOINLINE testChannelId #-}
-
--- | 33-byte node ID (03 prefix).
-testNodeId :: NodeId
-testNodeId = case nodeId (BS.cons 0x03 zeroBytes32) of
- Just n -> n
- Nothing -> error "testNodeId: invalid"
-{-# NOINLINE testNodeId #-}
-
--- | Second node ID (02 prefix, lexicographically smaller).
-testNodeId2 :: NodeId
-testNodeId2 = case nodeId (BS.cons 0x02 zeroBytes32) of
- Just n -> n
- Nothing -> error "testNodeId2: invalid"
-{-# NOINLINE testNodeId2 #-}
-
--- | RGB color.
-testRgbColor :: RgbColor
-testRgbColor = case rgbColor (BS.pack [0xff, 0x00, 0x00]) of
- Just c -> c
- Nothing -> error "testRgbColor: invalid"
-{-# NOINLINE testRgbColor #-}
-
--- | 32-byte alias.
-testAlias :: Alias
-testAlias = case alias zeroBytes32 of
- Just a -> a
- Nothing -> error "testAlias: invalid"
-{-# NOINLINE testAlias #-}
-
--- | IPv4 address.
-testIPv4 :: IPv4Addr
-testIPv4 = case ipv4Addr (BS.pack [127, 0, 0, 1]) of
- Just a -> a
- Nothing -> error "testIPv4: invalid"
-{-# NOINLINE testIPv4 #-}
-
--- | Empty TLV stream.
-emptyTlvs :: TlvStream
-emptyTlvs = unsafeTlvStream []
-{-# NOINLINE emptyTlvs #-}
-
--- | Empty feature bits.
-emptyFeatures :: FeatureBits
-emptyFeatures = featureBits BS.empty
-{-# NOINLINE emptyFeatures #-}
-
--- | List of test SCIDs for list encoding benchmarks.
-testScidList :: [ShortChannelId]
-testScidList = map mkScid [1..100]
- where
- mkScid n = case scidFromBytes (BS.pack [0, 0, 0, n, 0, 0, 0, n]) of
- Just s -> s
- Nothing -> error "mkScid: invalid"
-{-# NOINLINE testScidList #-}
-
--- | Encoded SCID list for decode benchmarks.
-encodedScidList :: BS.ByteString
-encodedScidList = encodeShortChannelIdList testScidList
-{-# NOINLINE encodedScidList #-}
-
--- Test messages ---------------------------------------------------------------
-
--- | Test ChannelAnnouncement message.
-testChannelAnnouncement :: ChannelAnnouncement
-testChannelAnnouncement = ChannelAnnouncement
- { channelAnnNodeSig1 = testSignature
- , channelAnnNodeSig2 = testSignature
- , channelAnnBitcoinSig1 = testSignature
- , channelAnnBitcoinSig2 = testSignature
- , channelAnnFeatures = emptyFeatures
- , channelAnnChainHash = testChainHash
- , channelAnnShortChanId = testShortChannelId
- , channelAnnNodeId1 = testNodeId2 -- 02... (smaller)
- , channelAnnNodeId2 = testNodeId -- 03... (larger)
- , channelAnnBitcoinKey1 = testPoint
- , channelAnnBitcoinKey2 = testPoint
- }
-{-# NOINLINE testChannelAnnouncement #-}
-
--- | Encoded ChannelAnnouncement for decode benchmarks.
-encodedChannelAnnouncement :: BS.ByteString
-encodedChannelAnnouncement =
- case encodeChannelAnnouncement testChannelAnnouncement of
- Right bs -> bs
- Left _ -> error "encodedChannelAnnouncement: encode failed"
-{-# NOINLINE encodedChannelAnnouncement #-}
-
--- | Test NodeAnnouncement message.
-testNodeAnnouncement :: NodeAnnouncement
-testNodeAnnouncement = NodeAnnouncement
- { nodeAnnSignature = testSignature
- , nodeAnnFeatures = emptyFeatures
- , nodeAnnTimestamp = 1234567890
- , nodeAnnNodeId = testNodeId
- , nodeAnnRgbColor = testRgbColor
- , nodeAnnAlias = testAlias
- , nodeAnnAddresses = [AddrIPv4 testIPv4 9735]
- }
-{-# NOINLINE testNodeAnnouncement #-}
-
--- | Encoded NodeAnnouncement for decode benchmarks.
-encodedNodeAnnouncement :: BS.ByteString
-encodedNodeAnnouncement = case encodeNodeAnnouncement testNodeAnnouncement of
- Right bs -> bs
- Left _ -> error "encodedNodeAnnouncement: encode failed"
-{-# NOINLINE encodedNodeAnnouncement #-}
-
--- | Test ChannelUpdate message.
-testChannelUpdate :: ChannelUpdate
-testChannelUpdate = ChannelUpdate
- { chanUpdateSignature = testSignature
- , chanUpdateChainHash = testChainHash
- , chanUpdateShortChanId = testShortChannelId
- , chanUpdateTimestamp = 1234567890
- , chanUpdateChanFlags = ChannelFlags NodeOne Enabled
- , chanUpdateCltvExpDelta = CltvExpiryDelta 144
- , chanUpdateHtlcMinMsat = HtlcMinimumMsat 1000
- , chanUpdateFeeBaseMsat = FeeBaseMsat 1000
- , chanUpdateFeeProportional = FeeProportionalMillionths 100
- , chanUpdateHtlcMaxMsat = HtlcMaximumMsat 1000000000
- }
-{-# NOINLINE testChannelUpdate #-}
-
--- | Encoded ChannelUpdate for decode benchmarks.
-encodedChannelUpdate :: BS.ByteString
-encodedChannelUpdate = encodeChannelUpdate testChannelUpdate
-{-# NOINLINE encodedChannelUpdate #-}
-
--- | Test AnnouncementSignatures message.
-testAnnouncementSignatures :: AnnouncementSignatures
-testAnnouncementSignatures = AnnouncementSignatures
- { annSigChannelId = testChannelId
- , annSigShortChanId = testShortChannelId
- , annSigNodeSig = testSignature
- , annSigBitcoinSig = testSignature
- }
-{-# NOINLINE testAnnouncementSignatures #-}
-
--- | Encoded AnnouncementSignatures for decode benchmarks.
-encodedAnnouncementSignatures :: BS.ByteString
-encodedAnnouncementSignatures =
- encodeAnnouncementSignatures testAnnouncementSignatures
-{-# NOINLINE encodedAnnouncementSignatures #-}
-
--- | Test QueryShortChannelIds message.
-testQueryShortChannelIds :: QueryShortChannelIds
-testQueryShortChannelIds = QueryShortChannelIds
- { queryScidsChainHash = testChainHash
- , queryScidsData = encodeShortChannelIdList [testShortChannelId]
- , queryScidsTlvs = emptyTlvs
- }
-{-# NOINLINE testQueryShortChannelIds #-}
-
--- | Encoded QueryShortChannelIds for decode benchmarks.
-encodedQueryShortChannelIds :: BS.ByteString
-encodedQueryShortChannelIds =
- case encodeQueryShortChannelIds testQueryShortChannelIds of
- Right bs -> bs
- Left _ -> error "encodedQueryShortChannelIds: encode failed"
-{-# NOINLINE encodedQueryShortChannelIds #-}
-
--- | Test ReplyShortChannelIdsEnd message.
-testReplyShortChannelIdsEnd :: ReplyShortChannelIdsEnd
-testReplyShortChannelIdsEnd = ReplyShortChannelIdsEnd
- { replyScidsChainHash = testChainHash
- , replyScidsFullInfo = 1
- }
-{-# NOINLINE testReplyShortChannelIdsEnd #-}
-
--- | Encoded ReplyShortChannelIdsEnd for decode benchmarks.
-encodedReplyShortChannelIdsEnd :: BS.ByteString
-encodedReplyShortChannelIdsEnd =
- encodeReplyShortChannelIdsEnd testReplyShortChannelIdsEnd
-{-# NOINLINE encodedReplyShortChannelIdsEnd #-}
-
--- | Test QueryChannelRange message.
-testQueryChannelRange :: QueryChannelRange
-testQueryChannelRange = QueryChannelRange
- { queryRangeChainHash = testChainHash
- , queryRangeFirstBlock = BlockHeight 700000
- , queryRangeNumBlocks = BlockCount 10000
- , queryRangeTlvs = emptyTlvs
- }
-{-# NOINLINE testQueryChannelRange #-}
-
--- | Encoded QueryChannelRange for decode benchmarks.
-encodedQueryChannelRange :: BS.ByteString
-encodedQueryChannelRange = encodeQueryChannelRange testQueryChannelRange
-{-# NOINLINE encodedQueryChannelRange #-}
-
--- | Test ReplyChannelRange message.
-testReplyChannelRange :: ReplyChannelRange
-testReplyChannelRange = ReplyChannelRange
- { replyRangeChainHash = testChainHash
- , replyRangeFirstBlock = BlockHeight 700000
- , replyRangeNumBlocks = BlockCount 10000
- , replyRangeSyncComplete = 1
- , replyRangeData = encodeShortChannelIdList [testShortChannelId]
- , replyRangeTlvs = emptyTlvs
- }
-{-# NOINLINE testReplyChannelRange #-}
-
--- | Encoded ReplyChannelRange for decode benchmarks.
-encodedReplyChannelRange :: BS.ByteString
-encodedReplyChannelRange = case encodeReplyChannelRange testReplyChannelRange of
- Right bs -> bs
- Left _ -> error "encodedReplyChannelRange: encode failed"
-{-# NOINLINE encodedReplyChannelRange #-}
-
--- | Test GossipTimestampFilter message.
-testGossipTimestampFilter :: GossipTimestampFilter
-testGossipTimestampFilter = GossipTimestampFilter
- { gossipFilterChainHash = testChainHash
- , gossipFilterFirstTimestamp = 1609459200
- , gossipFilterTimestampRange = 86400
- }
-{-# NOINLINE testGossipTimestampFilter #-}
-
--- | Encoded GossipTimestampFilter for decode benchmarks.
-encodedGossipTimestampFilter :: BS.ByteString
-encodedGossipTimestampFilter =
- encodeGossipTimestampFilter testGossipTimestampFilter
-{-# NOINLINE encodedGossipTimestampFilter #-}
-
--- Benchmark groups ------------------------------------------------------------
+import System.Exit (exitFailure)
main :: IO ()
-main = defaultMain
- [ bgroup "channel_announcement"
- [ bench "encode" $ nf encodeChannelAnnouncement testChannelAnnouncement
- , bench "decode" $ nf decodeChannelAnnouncement encodedChannelAnnouncement
- ]
- , bgroup "node_announcement"
- [ bench "encode" $ nf encodeNodeAnnouncement testNodeAnnouncement
- , bench "decode" $ nf decodeNodeAnnouncement encodedNodeAnnouncement
- ]
- , bgroup "channel_update"
- [ bench "encode" $ nf encodeChannelUpdate testChannelUpdate
- , bench "decode" $ nf decodeChannelUpdate encodedChannelUpdate
- ]
- , bgroup "announcement_signatures"
- [ bench "encode" $
- nf encodeAnnouncementSignatures testAnnouncementSignatures
- , bench "decode" $
- nf decodeAnnouncementSignatures encodedAnnouncementSignatures
- ]
- , bgroup "query_short_channel_ids"
- [ bench "encode" $
- nf encodeQueryShortChannelIds testQueryShortChannelIds
- , bench "decode" $
- nf decodeQueryShortChannelIds encodedQueryShortChannelIds
- ]
- , bgroup "reply_short_channel_ids_end"
- [ bench "encode" $
- nf encodeReplyShortChannelIdsEnd testReplyShortChannelIdsEnd
- , bench "decode" $
- nf decodeReplyShortChannelIdsEnd encodedReplyShortChannelIdsEnd
- ]
- , bgroup "query_channel_range"
- [ bench "encode" $ nf encodeQueryChannelRange testQueryChannelRange
- , bench "decode" $ nf decodeQueryChannelRange encodedQueryChannelRange
- ]
- , bgroup "reply_channel_range"
- [ bench "encode" $ nf encodeReplyChannelRange testReplyChannelRange
- , bench "decode" $ nf decodeReplyChannelRange encodedReplyChannelRange
- ]
- , bgroup "gossip_timestamp_filter"
- [ bench "encode" $
- nf encodeGossipTimestampFilter testGossipTimestampFilter
- , bench "decode" $
- nf decodeGossipTimestampFilter encodedGossipTimestampFilter
- ]
- , bgroup "scid_list"
- [ bench "encode (100)" $ nf encodeShortChannelIdList testScidList
- , bench "decode (100)" $ nf decodeShortChannelIdList encodedScidList
- ]
- , bgroup "hash"
- [ bench "channelAnnouncementHash" $
- nf channelAnnouncementHash encodedChannelAnnouncement
- , bench "nodeAnnouncementHash" $
- nf nodeAnnouncementHash encodedNodeAnnouncement
- , bench "channelUpdateHash" $
- nf channelUpdateHash encodedChannelUpdate
- , bench "channelUpdateChecksum" $
- nf channelUpdateChecksum encodedChannelUpdate
- ]
- , bgroup "validate"
- [ bench "channelAnnouncement" $
- nf validateChannelAnnouncement testChannelAnnouncement
- , bench "nodeAnnouncement" $
- nf validateNodeAnnouncement testNodeAnnouncement
- , bench "channelUpdate" $
- nf validateChannelUpdate testChannelUpdate
- , bench "queryChannelRange" $
- nf validateQueryChannelRange testQueryChannelRange
- , bench "replyChannelRange" $
- nf validateReplyChannelRange testReplyChannelRange
- ]
- ]
+main = case fixtures of
+ Nothing -> putStrLn "fixtures failed to build" >> exitFailure
+ Just f -> defaultMain [
+ bgroup "decode" [
+ bench "channel_announcement" $
+ nf decode_channel_announcement (f_ann_bytes f)
+ , bench "node_announcement" $
+ nf decode_node_announcement (f_node_bytes f)
+ , bench "channel_update" $ nf decode_channel_update (f_upd_bytes f)
+ , bench "channel_update (decode_message)" $
+ nf (decode_message 258) (f_upd_bytes f)
+ , bench "query_short_channel_ids (1000 ids, flags)" $
+ nf decode_query_short_channel_ids (f_qsci_bytes f)
+ , bench "reply_channel_range (1000 ids, timestamps, checksums)" $
+ nf decode_reply_channel_range (f_rcr_bytes f)
+ ]
+ , bgroup "encode" [
+ bench "channel_announcement" $
+ nf encode_channel_announcement (f_ann f)
+ , bench "node_announcement" $ nf encode_node_announcement (f_node f)
+ , bench "channel_update" $ nf encode_channel_update (f_upd f)
+ , bench "query_short_channel_ids (1000 ids, flags)" $
+ nf encode_query_short_channel_ids (f_qsci f)
+ , bench "reply_channel_range (1000 ids, timestamps, checksums)" $
+ nf encode_reply_channel_range (f_rcr f)
+ ]
+ , bgroup "hash" [
+ bench "channel_announcement_hash" $
+ nf channel_announcement_hash (f_ann f)
+ , bench "channel_update_hash" $ nf channel_update_hash (f_upd f)
+ , bench "channel_update_checksum" $
+ nf channel_update_checksum (f_upd f)
+ ]
+ , bgroup "verify" [
+ bench "verify_channel_announcement" $
+ nf verify_channel_announcement (f_ann f)
+ , bench "verify_node_announcement" $
+ nf verify_node_announcement (f_node f)
+ , bench "verify_channel_update" $
+ nf (verify_channel_update (f_upd_key f)) (f_upd f)
+ ]
+ , bgroup "validate" [
+ bench "validate_reply_channel_range (1000 ids)" $
+ nf validate_reply_channel_range (f_rcr f)
+ ]
+ ]
diff --git a/bench/Weight.hs b/bench/Weight.hs
@@ -1,361 +1,44 @@
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE OverloadedStrings #-}
-
-- |
-- Module: Main
-- Copyright: (c) 2025 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
--- Weigh allocation benchmarks for BOLT #7 gossip codecs.
+-- Weigh allocation benchmarks for ppad-bolt7.
module Main where
-import qualified Data.ByteString as BS
-import Lightning.Protocol.BOLT1 (TlvStream, unsafeTlvStream)
+import Fixtures
import Lightning.Protocol.BOLT7
+import System.Exit (exitFailure)
import Weigh
--- Test data construction ------------------------------------------------------
-
--- | 32 zero bytes for chain hashes, etc.
-zeroBytes32 :: BS.ByteString
-zeroBytes32 = BS.replicate 32 0x00
-{-# NOINLINE zeroBytes32 #-}
-
--- | 8 zero bytes for short channel IDs.
-zeroBytes8 :: BS.ByteString
-zeroBytes8 = BS.replicate 8 0x00
-{-# NOINLINE zeroBytes8 #-}
-
--- | 64-byte signature.
-testSignature :: Signature
-testSignature = case signature (BS.replicate 64 0x01) of
- Just s -> s
- Nothing -> error "testSignature: invalid"
-{-# NOINLINE testSignature #-}
-
--- | 33-byte compressed public key (02 prefix + 32 zero bytes).
-testPoint :: Point
-testPoint = case point (BS.cons 0x02 zeroBytes32) of
- Just p -> p
- Nothing -> error "testPoint: invalid"
-{-# NOINLINE testPoint #-}
-
--- | 32-byte chain hash.
-testChainHash :: ChainHash
-testChainHash = case chainHash zeroBytes32 of
- Just h -> h
- Nothing -> error "testChainHash: invalid"
-{-# NOINLINE testChainHash #-}
-
--- | 8-byte short channel ID.
-testShortChannelId :: ShortChannelId
-testShortChannelId = case scidFromBytes zeroBytes8 of
- Just s -> s
- Nothing -> error "testShortChannelId: invalid"
-{-# NOINLINE testShortChannelId #-}
-
--- | 32-byte channel ID.
-testChannelId :: ChannelId
-testChannelId = case channelId zeroBytes32 of
- Just c -> c
- Nothing -> error "testChannelId: invalid"
-{-# NOINLINE testChannelId #-}
-
--- | 33-byte node ID (03 prefix).
-testNodeId :: NodeId
-testNodeId = case nodeId (BS.cons 0x03 zeroBytes32) of
- Just n -> n
- Nothing -> error "testNodeId: invalid"
-{-# NOINLINE testNodeId #-}
-
--- | Second node ID (02 prefix, lexicographically smaller).
-testNodeId2 :: NodeId
-testNodeId2 = case nodeId (BS.cons 0x02 zeroBytes32) of
- Just n -> n
- Nothing -> error "testNodeId2: invalid"
-{-# NOINLINE testNodeId2 #-}
-
--- | RGB color.
-testRgbColor :: RgbColor
-testRgbColor = case rgbColor (BS.pack [0xff, 0x00, 0x00]) of
- Just c -> c
- Nothing -> error "testRgbColor: invalid"
-{-# NOINLINE testRgbColor #-}
-
--- | 32-byte alias.
-testAlias :: Alias
-testAlias = case alias zeroBytes32 of
- Just a -> a
- Nothing -> error "testAlias: invalid"
-{-# NOINLINE testAlias #-}
-
--- | IPv4 address.
-testIPv4 :: IPv4Addr
-testIPv4 = case ipv4Addr (BS.pack [127, 0, 0, 1]) of
- Just a -> a
- Nothing -> error "testIPv4: invalid"
-{-# NOINLINE testIPv4 #-}
-
--- | Empty feature bits.
-emptyFeatures :: FeatureBits
-emptyFeatures = featureBits BS.empty
-{-# NOINLINE emptyFeatures #-}
-
--- | Empty TLV stream.
-emptyTlvs :: TlvStream
-emptyTlvs = unsafeTlvStream []
-{-# NOINLINE emptyTlvs #-}
-
--- | List of test SCIDs for list encoding benchmarks.
-testScidList :: [ShortChannelId]
-testScidList = map mkScid [1..100]
- where
- mkScid n = case scidFromBytes (BS.pack [0, 0, 0, n, 0, 0, 0, n]) of
- Just s -> s
- Nothing -> error "mkScid: invalid"
-{-# NOINLINE testScidList #-}
-
--- | Encoded SCID list for decode benchmarks.
-encodedScidList :: BS.ByteString
-encodedScidList = encodeShortChannelIdList testScidList
-{-# NOINLINE encodedScidList #-}
-
--- Message constructors --------------------------------------------------------
-
--- | Construct ChannelAnnouncement message.
-mkChannelAnnouncement
- :: Signature -> Signature -> ChainHash -> ShortChannelId
- -> NodeId -> NodeId -> Point -> Point -> FeatureBits
- -> ChannelAnnouncement
-mkChannelAnnouncement !ns1 !ns2 !ch !scid !nid1 !nid2 !bk1 !bk2 !feat =
- ChannelAnnouncement
- { channelAnnNodeSig1 = ns1
- , channelAnnNodeSig2 = ns2
- , channelAnnBitcoinSig1 = ns1
- , channelAnnBitcoinSig2 = ns2
- , channelAnnFeatures = feat
- , channelAnnChainHash = ch
- , channelAnnShortChanId = scid
- , channelAnnNodeId1 = nid1
- , channelAnnNodeId2 = nid2
- , channelAnnBitcoinKey1 = bk1
- , channelAnnBitcoinKey2 = bk2
- }
-
--- | Construct NodeAnnouncement message.
-mkNodeAnnouncement
- :: Signature -> FeatureBits -> NodeId -> RgbColor -> Alias
- -> [Address] -> NodeAnnouncement
-mkNodeAnnouncement !sig !feat !nid !col !al !addrs = NodeAnnouncement
- { nodeAnnSignature = sig
- , nodeAnnFeatures = feat
- , nodeAnnTimestamp = 1234567890
- , nodeAnnNodeId = nid
- , nodeAnnRgbColor = col
- , nodeAnnAlias = al
- , nodeAnnAddresses = addrs
- }
-
--- | Construct ChannelUpdate message.
-mkChannelUpdate :: Signature -> ChainHash -> ShortChannelId -> ChannelUpdate
-mkChannelUpdate !sig !ch !scid = ChannelUpdate
- { chanUpdateSignature = sig
- , chanUpdateChainHash = ch
- , chanUpdateShortChanId = scid
- , chanUpdateTimestamp = 1234567890
- , chanUpdateChanFlags = ChannelFlags NodeOne Enabled
- , chanUpdateCltvExpDelta = CltvExpiryDelta 144
- , chanUpdateHtlcMinMsat = HtlcMinimumMsat 1000
- , chanUpdateFeeBaseMsat = FeeBaseMsat 1000
- , chanUpdateFeeProportional = FeeProportionalMillionths 100
- , chanUpdateHtlcMaxMsat = HtlcMaximumMsat 1000000000
- }
-
--- | Construct AnnouncementSignatures message.
-mkAnnouncementSignatures
- :: ChannelId -> ShortChannelId -> Signature -> AnnouncementSignatures
-mkAnnouncementSignatures !cid !scid !sig = AnnouncementSignatures
- { annSigChannelId = cid
- , annSigShortChanId = scid
- , annSigNodeSig = sig
- , annSigBitcoinSig = sig
- }
-
--- | Construct GossipTimestampFilter message.
-mkGossipTimestampFilter :: ChainHash -> GossipTimestampFilter
-mkGossipTimestampFilter !ch = GossipTimestampFilter
- { gossipFilterChainHash = ch
- , gossipFilterFirstTimestamp = 1609459200
- , gossipFilterTimestampRange = 86400
- }
-
--- | Construct QueryChannelRange message.
-mkQueryChannelRange :: ChainHash -> TlvStream -> QueryChannelRange
-mkQueryChannelRange !ch !tlvs = QueryChannelRange
- { queryRangeChainHash = ch
- , queryRangeFirstBlock = BlockHeight 700000
- , queryRangeNumBlocks = BlockCount 10000
- , queryRangeTlvs = tlvs
- }
-
--- | Construct ReplyChannelRange message.
-mkReplyChannelRange :: ChainHash -> TlvStream -> ReplyChannelRange
-mkReplyChannelRange !ch !tlvs = ReplyChannelRange
- { replyRangeChainHash = ch
- , replyRangeFirstBlock = BlockHeight 700000
- , replyRangeNumBlocks = BlockCount 10000
- , replyRangeSyncComplete = 1
- , replyRangeData = encodeShortChannelIdList [testShortChannelId]
- , replyRangeTlvs = tlvs
- }
-
--- Pre-constructed messages ----------------------------------------------------
-
--- | Test ChannelAnnouncement message.
-testChannelAnnouncement :: ChannelAnnouncement
-testChannelAnnouncement = mkChannelAnnouncement
- testSignature testSignature testChainHash testShortChannelId
- testNodeId2 testNodeId testPoint testPoint emptyFeatures
-{-# NOINLINE testChannelAnnouncement #-}
-
--- | Encoded ChannelAnnouncement for decode benchmarks.
-encodedChannelAnnouncement :: BS.ByteString
-encodedChannelAnnouncement =
- case encodeChannelAnnouncement testChannelAnnouncement of
- Right bs -> bs
- Left _ -> error "encodedChannelAnnouncement: encode failed"
-{-# NOINLINE encodedChannelAnnouncement #-}
-
--- | Test NodeAnnouncement message.
-testNodeAnnouncement :: NodeAnnouncement
-testNodeAnnouncement = mkNodeAnnouncement
- testSignature emptyFeatures testNodeId testRgbColor testAlias
- [AddrIPv4 testIPv4 9735]
-{-# NOINLINE testNodeAnnouncement #-}
-
--- | Encoded NodeAnnouncement for decode benchmarks.
-encodedNodeAnnouncement :: BS.ByteString
-encodedNodeAnnouncement = case encodeNodeAnnouncement testNodeAnnouncement of
- Right bs -> bs
- Left _ -> error "encodedNodeAnnouncement: encode failed"
-{-# NOINLINE encodedNodeAnnouncement #-}
-
--- | Test ChannelUpdate message.
-testChannelUpdate :: ChannelUpdate
-testChannelUpdate = mkChannelUpdate testSignature testChainHash testShortChannelId
-{-# NOINLINE testChannelUpdate #-}
-
--- | Encoded ChannelUpdate for decode benchmarks.
-encodedChannelUpdate :: BS.ByteString
-encodedChannelUpdate = encodeChannelUpdate testChannelUpdate
-{-# NOINLINE encodedChannelUpdate #-}
-
--- | Test AnnouncementSignatures message.
-testAnnouncementSignatures :: AnnouncementSignatures
-testAnnouncementSignatures =
- mkAnnouncementSignatures testChannelId testShortChannelId testSignature
-{-# NOINLINE testAnnouncementSignatures #-}
-
--- | Encoded AnnouncementSignatures for decode benchmarks.
-encodedAnnouncementSignatures :: BS.ByteString
-encodedAnnouncementSignatures =
- encodeAnnouncementSignatures testAnnouncementSignatures
-{-# NOINLINE encodedAnnouncementSignatures #-}
-
--- | Test GossipTimestampFilter message.
-testGossipTimestampFilter :: GossipTimestampFilter
-testGossipTimestampFilter = mkGossipTimestampFilter testChainHash
-{-# NOINLINE testGossipTimestampFilter #-}
-
--- | Encoded GossipTimestampFilter for decode benchmarks.
-encodedGossipTimestampFilter :: BS.ByteString
-encodedGossipTimestampFilter =
- encodeGossipTimestampFilter testGossipTimestampFilter
-{-# NOINLINE encodedGossipTimestampFilter #-}
-
--- | Test QueryChannelRange message.
-testQueryChannelRange :: QueryChannelRange
-testQueryChannelRange = mkQueryChannelRange testChainHash emptyTlvs
-{-# NOINLINE testQueryChannelRange #-}
-
--- | Encoded QueryChannelRange for decode benchmarks.
-encodedQueryChannelRange :: BS.ByteString
-encodedQueryChannelRange = encodeQueryChannelRange testQueryChannelRange
-{-# NOINLINE encodedQueryChannelRange #-}
-
--- | Test ReplyChannelRange message.
-testReplyChannelRange :: ReplyChannelRange
-testReplyChannelRange = mkReplyChannelRange testChainHash emptyTlvs
-{-# NOINLINE testReplyChannelRange #-}
-
--- | Encoded ReplyChannelRange for decode benchmarks.
-encodedReplyChannelRange :: BS.ByteString
-encodedReplyChannelRange = case encodeReplyChannelRange testReplyChannelRange of
- Right bs -> bs
- Left _ -> error "encodedReplyChannelRange: encode failed"
-{-# NOINLINE encodedReplyChannelRange #-}
-
--- Weigh benchmarks ------------------------------------------------------------
-
main :: IO ()
-main = mainWith $ do
- wgroup "channel_announcement" $ do
- func "construct" (mkChannelAnnouncement
- testSignature testSignature testChainHash testShortChannelId
- testNodeId2 testNodeId testPoint testPoint) emptyFeatures
- func "encode" encodeChannelAnnouncement testChannelAnnouncement
- func "decode" decodeChannelAnnouncement encodedChannelAnnouncement
-
- wgroup "node_announcement" $ do
- func "construct" (mkNodeAnnouncement
- testSignature emptyFeatures testNodeId testRgbColor testAlias)
- [AddrIPv4 testIPv4 9735]
- func "encode" encodeNodeAnnouncement testNodeAnnouncement
- func "decode" decodeNodeAnnouncement encodedNodeAnnouncement
-
- wgroup "channel_update" $ do
- func "construct" (mkChannelUpdate testSignature testChainHash)
- testShortChannelId
- func "encode" encodeChannelUpdate testChannelUpdate
- func "decode" decodeChannelUpdate encodedChannelUpdate
-
- wgroup "announcement_signatures" $ do
- func "construct" (mkAnnouncementSignatures testChannelId testShortChannelId)
- testSignature
- func "encode" encodeAnnouncementSignatures testAnnouncementSignatures
- func "decode" decodeAnnouncementSignatures encodedAnnouncementSignatures
-
- wgroup "query_channel_range" $ do
- func "construct" (mkQueryChannelRange testChainHash) emptyTlvs
- func "encode" encodeQueryChannelRange testQueryChannelRange
- func "decode" decodeQueryChannelRange encodedQueryChannelRange
-
- wgroup "reply_channel_range" $ do
- func "construct" (mkReplyChannelRange testChainHash) emptyTlvs
- func "encode" encodeReplyChannelRange testReplyChannelRange
- func "decode" decodeReplyChannelRange encodedReplyChannelRange
-
- wgroup "gossip_timestamp_filter" $ do
- func "construct" mkGossipTimestampFilter testChainHash
- func "encode" encodeGossipTimestampFilter testGossipTimestampFilter
- func "decode" decodeGossipTimestampFilter encodedGossipTimestampFilter
-
- wgroup "scid_list" $ do
- func "encode (100)" encodeShortChannelIdList testScidList
- func "decode (100)" decodeShortChannelIdList encodedScidList
-
- wgroup "hash" $ do
- func "channelAnnouncementHash" channelAnnouncementHash
- encodedChannelAnnouncement
- func "nodeAnnouncementHash" nodeAnnouncementHash encodedNodeAnnouncement
- func "channelUpdateHash" channelUpdateHash encodedChannelUpdate
- func "channelUpdateChecksum" channelUpdateChecksum encodedChannelUpdate
-
- wgroup "validate" $ do
- func "channelAnnouncement" validateChannelAnnouncement testChannelAnnouncement
- func "nodeAnnouncement" validateNodeAnnouncement testNodeAnnouncement
- func "channelUpdate" validateChannelUpdate testChannelUpdate
- func "queryChannelRange" validateQueryChannelRange testQueryChannelRange
- func "replyChannelRange" validateReplyChannelRange testReplyChannelRange
+main = case fixtures of
+ Nothing -> putStrLn "fixtures failed to build" >> exitFailure
+ Just f -> mainWith $ do
+ wgroup "decode" $ do
+ func "channel_announcement" decode_channel_announcement (f_ann_bytes f)
+ func "node_announcement" decode_node_announcement (f_node_bytes f)
+ func "channel_update" decode_channel_update (f_upd_bytes f)
+ func "query_short_channel_ids (1000 ids, flags)"
+ decode_query_short_channel_ids (f_qsci_bytes f)
+ func "reply_channel_range (1000 ids, timestamps, checksums)"
+ decode_reply_channel_range (f_rcr_bytes f)
+ wgroup "encode" $ do
+ func "channel_announcement" encode_channel_announcement (f_ann f)
+ func "node_announcement" encode_node_announcement (f_node f)
+ func "channel_update" encode_channel_update (f_upd f)
+ func "query_short_channel_ids (1000 ids, flags)"
+ encode_query_short_channel_ids (f_qsci f)
+ func "reply_channel_range (1000 ids, timestamps, checksums)"
+ encode_reply_channel_range (f_rcr f)
+ wgroup "hash" $ do
+ func "channel_announcement_hash" channel_announcement_hash (f_ann f)
+ func "channel_update_hash" channel_update_hash (f_upd f)
+ func "channel_update_checksum" channel_update_checksum (f_upd f)
+ wgroup "verify" $ do
+ func "verify_channel_announcement" verify_channel_announcement (f_ann f)
+ func "verify_node_announcement" verify_node_announcement (f_node f)
+ func "verify_channel_update"
+ (verify_channel_update (f_upd_key f)) (f_upd f)
diff --git a/ppad-bolt7.cabal b/ppad-bolt7.cabal
@@ -70,6 +70,8 @@ benchmark bolt7-bench
default-language: Haskell2010
hs-source-dirs: bench
main-is: Main.hs
+ other-modules:
+ Fixtures
ghc-options:
-rtsopts -O2 -Wall
@@ -78,7 +80,6 @@ benchmark bolt7-bench
base
, bytestring
, criterion
- , deepseq
, ppad-base16
, ppad-bolt1
, ppad-bolt7
@@ -88,6 +89,8 @@ benchmark bolt7-weigh
default-language: Haskell2010
hs-source-dirs: bench
main-is: Weight.hs
+ other-modules:
+ Fixtures
ghc-options:
-rtsopts -O2 -Wall
@@ -95,7 +98,6 @@ benchmark bolt7-weigh
build-depends:
base
, bytestring
- , deepseq
, ppad-base16
, ppad-bolt1
, ppad-bolt7