bolt7

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

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:
Abench/Fixtures.hs | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbench/Main.hs | 399++++++++++---------------------------------------------------------------------
Mbench/Weight.hs | 379+++++++------------------------------------------------------------------------
Mppad-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