ppad-bolt7-0.0.1: bench/Weight.hs
{-# 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.
module Main where
import qualified Data.ByteString as BS
import Lightning.Protocol.BOLT1 (TlvStream, unsafeTlvStream)
import Lightning.Protocol.BOLT7
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 shortChannelId 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 shortChannelId (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
, chanUpdateMsgFlags = 0x01
, chanUpdateChanFlags = 0x00
, chanUpdateCltvExpDelta = 144
, chanUpdateHtlcMinMsat = 1000
, chanUpdateFeeBaseMsat = 1000
, chanUpdateFeeProportional = 100
, chanUpdateHtlcMaxMsat = Just 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 = 700000
, queryRangeNumBlocks = 10000
, queryRangeTlvs = tlvs
}
-- | Construct ReplyChannelRange message.
mkReplyChannelRange :: ChainHash -> TlvStream -> ReplyChannelRange
mkReplyChannelRange !ch !tlvs = ReplyChannelRange
{ replyRangeChainHash = ch
, replyRangeFirstBlock = 700000
, replyRangeNumBlocks = 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 = encodeChannelAnnouncement testChannelAnnouncement
{-# 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