packages feed

ppad-bolt1-0.0.1: bench/Fixtures.hs

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}

-- |
-- Module: Fixtures
-- Copyright: (c) 2025 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
-- Test fixtures for BOLT #1 benchmarks.

module Fixtures where

import qualified Data.ByteString as BS
import Data.Maybe (fromJust)
import Lightning.Protocol.BOLT1

-- Sample ByteStrings -----------------------------------------------------

-- | 64-byte sample data.
bytes64 :: BS.ByteString
bytes64 = BS.replicate 64 0xAB
{-# NOINLINE bytes64 #-}

-- | 1KB sample data.
bytes1k :: BS.ByteString
bytes1k = BS.replicate 1024 0xCD
{-# NOINLINE bytes1k #-}

-- | 16KB sample data.
bytes16k :: BS.ByteString
bytes16k = BS.replicate 16384 0xEF
{-# NOINLINE bytes16k #-}

-- Sample chain hashes (32 bytes each) ------------------------------------

-- | Bitcoin mainnet genesis block hash (reversed, as used in LN).
mainnetChainHash :: ChainHash
mainnetChainHash = fromJust $ chainHash $ BS.pack
  [ 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72
  , 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f
  , 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c
  , 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00
  ]
{-# NOINLINE mainnetChainHash #-}

-- | Bitcoin testnet genesis block hash (reversed, as used in LN).
testnetChainHash :: ChainHash
testnetChainHash = fromJust $ chainHash $ BS.pack
  [ 0x43, 0x49, 0x7f, 0xd7, 0xf8, 0x26, 0x95, 0x71
  , 0x08, 0xf4, 0xa3, 0x0f, 0xd9, 0xce, 0xc3, 0xae
  , 0xba, 0x79, 0x97, 0x20, 0x84, 0xe9, 0x0e, 0xad
  , 0x01, 0xea, 0x33, 0x09, 0x00, 0x00, 0x00, 0x00
  ]
{-# NOINLINE testnetChainHash #-}

-- Sample channel IDs (32 bytes each) -------------------------------------

-- | Sample channel ID (non-zero).
sampleChannelId :: ChannelId
sampleChannelId = fromJust $ channelId $ BS.pack
  [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
  , 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
  , 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
  , 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
  ]
{-# NOINLINE sampleChannelId #-}

-- Sample Init messages ---------------------------------------------------

-- | Minimal Init message (empty features, no TLVs).
minimalInit :: Init
minimalInit = Init
  { initGlobalFeatures = BS.empty
  , initFeatures       = BS.empty
  , initTlvs           = []
  }
{-# NOINLINE minimalInit #-}

-- | Init with feature bits set.
initWithFeatures :: Init
initWithFeatures = Init
  { initGlobalFeatures = BS.pack [0x00, 0x01]  -- 2 bytes
  , initFeatures       = BS.pack [0x02, 0xa2]  -- data_loss_protect, etc.
  , initTlvs           = []
  }
{-# NOINLINE initWithFeatures #-}

-- | Init with TLV extensions.
initWithTlvs :: Init
initWithTlvs = Init
  { initGlobalFeatures = BS.empty
  , initFeatures       = BS.pack [0x02, 0xa2]
  , initTlvs           = [InitNetworks [mainnetChainHash]]
  }
{-# NOINLINE initWithTlvs #-}

-- | Init with multiple chain hashes.
initWithMultipleChains :: Init
initWithMultipleChains = Init
  { initGlobalFeatures = BS.empty
  , initFeatures       = BS.pack [0x02, 0xa2]
  , initTlvs           = [InitNetworks [mainnetChainHash, testnetChainHash]]
  }
{-# NOINLINE initWithMultipleChains #-}

-- | Full Init with features and remote_addr TLV.
fullInit :: Init
fullInit = Init
  { initGlobalFeatures = BS.pack [0x00, 0x01]
  , initFeatures       = BS.pack [0x02, 0xa2, 0x01]
  , initTlvs           =
      [ InitNetworks [mainnetChainHash]
      , InitRemoteAddr (BS.pack [0x01, 0x7f, 0x00, 0x00, 0x01, 0x27, 0x10])
      ]
  }
{-# NOINLINE fullInit #-}

-- Sample Error messages --------------------------------------------------

-- | Minimal Error message (connection-level, empty data).
minimalError :: Error
minimalError = Error
  { errorChannelId = allChannels
  , errorData      = BS.empty
  }
{-# NOINLINE minimalError #-}

-- | Error with channel ID and message.
errorWithData :: Error
errorWithData = Error
  { errorChannelId = sampleChannelId
  , errorData      = "funding transaction failed"
  }
{-# NOINLINE errorWithData #-}

-- | Error with longer data.
errorWithLongData :: Error
errorWithLongData = Error
  { errorChannelId = sampleChannelId
  , errorData      = bytes1k
  }
{-# NOINLINE errorWithLongData #-}

-- Sample Warning messages ------------------------------------------------

-- | Minimal Warning message.
minimalWarning :: Warning
minimalWarning = Warning
  { warningChannelId = allChannels
  , warningData      = BS.empty
  }
{-# NOINLINE minimalWarning #-}

-- | Warning with message.
warningWithData :: Warning
warningWithData = Warning
  { warningChannelId = sampleChannelId
  , warningData      = "channel fee too low"
  }
{-# NOINLINE warningWithData #-}

-- Sample Ping messages ---------------------------------------------------

-- | Minimal Ping (no padding, no response requested).
minimalPing :: Ping
minimalPing = Ping
  { pingNumPongBytes = 0
  , pingIgnored      = BS.empty
  }
{-# NOINLINE minimalPing #-}

-- | Ping with response requested but no padding.
pingWithResponse :: Ping
pingWithResponse = Ping
  { pingNumPongBytes = 64
  , pingIgnored      = BS.empty
  }
{-# NOINLINE pingWithResponse #-}

-- | Ping with padding (64 bytes).
pingWithPadding :: Ping
pingWithPadding = Ping
  { pingNumPongBytes = 64
  , pingIgnored      = bytes64
  }
{-# NOINLINE pingWithPadding #-}

-- | Ping with large padding (1KB).
pingWithLargePadding :: Ping
pingWithLargePadding = Ping
  { pingNumPongBytes = 128
  , pingIgnored      = bytes1k
  }
{-# NOINLINE pingWithLargePadding #-}

-- Sample Pong messages ---------------------------------------------------

-- | Minimal Pong (no ignored bytes).
minimalPong :: Pong
minimalPong = Pong
  { pongIgnored = BS.empty
  }
{-# NOINLINE minimalPong #-}

-- | Pong with padding (64 bytes).
pongWithPadding :: Pong
pongWithPadding = Pong
  { pongIgnored = bytes64
  }
{-# NOINLINE pongWithPadding #-}

-- | Pong with large padding (1KB).
pongWithLargePadding :: Pong
pongWithLargePadding = Pong
  { pongIgnored = bytes1k
  }
{-# NOINLINE pongWithLargePadding #-}

-- Sample PeerStorage messages --------------------------------------------

-- | Minimal PeerStorage (empty blob).
minimalPeerStorage :: PeerStorage
minimalPeerStorage = PeerStorage
  { peerStorageBlob = BS.empty
  }
{-# NOINLINE minimalPeerStorage #-}

-- | PeerStorage with 1KB blob.
peerStorageSmall :: PeerStorage
peerStorageSmall = PeerStorage
  { peerStorageBlob = bytes1k
  }
{-# NOINLINE peerStorageSmall #-}

-- | PeerStorage with 16KB blob.
peerStorageLarge :: PeerStorage
peerStorageLarge = PeerStorage
  { peerStorageBlob = bytes16k
  }
{-# NOINLINE peerStorageLarge #-}

-- Sample PeerStorageRetrieval messages -----------------------------------

-- | Minimal PeerStorageRetrieval (empty blob).
minimalPeerStorageRetrieval :: PeerStorageRetrieval
minimalPeerStorageRetrieval = PeerStorageRetrieval
  { peerStorageRetrievalBlob = BS.empty
  }
{-# NOINLINE minimalPeerStorageRetrieval #-}

-- | PeerStorageRetrieval with 1KB blob.
peerStorageRetrievalSmall :: PeerStorageRetrieval
peerStorageRetrievalSmall = PeerStorageRetrieval
  { peerStorageRetrievalBlob = bytes1k
  }
{-# NOINLINE peerStorageRetrievalSmall #-}

-- | PeerStorageRetrieval with 16KB blob.
peerStorageRetrievalLarge :: PeerStorageRetrieval
peerStorageRetrievalLarge = PeerStorageRetrieval
  { peerStorageRetrievalBlob = bytes16k
  }
{-# NOINLINE peerStorageRetrievalLarge #-}

-- Sample TLV streams -----------------------------------------------------

-- | Empty TLV stream.
emptyTlvStream :: TlvStream
emptyTlvStream = unsafeTlvStream []
{-# NOINLINE emptyTlvStream #-}

-- | TLV stream with 1 record.
smallTlvStream :: TlvStream
smallTlvStream = unsafeTlvStream
  [ TlvRecord 1 (BS.replicate 32 0x01)
  ]
{-# NOINLINE smallTlvStream #-}

-- | TLV stream with 5 records.
mediumTlvStream :: TlvStream
mediumTlvStream = unsafeTlvStream
  [ TlvRecord 1 (BS.replicate 8 0x01)
  , TlvRecord 3 (BS.replicate 16 0x03)
  , TlvRecord 5 (BS.replicate 32 0x05)
  , TlvRecord 7 (BS.replicate 64 0x07)
  , TlvRecord 9 (BS.replicate 128 0x09)
  ]
{-# NOINLINE mediumTlvStream #-}

-- | TLV stream with 20 records.
largeTlvStream :: TlvStream
largeTlvStream = unsafeTlvStream
  [ TlvRecord 1  (BS.replicate 8 0x01)
  , TlvRecord 3  (BS.replicate 16 0x02)
  , TlvRecord 5  (BS.replicate 8 0x03)
  , TlvRecord 7  (BS.replicate 16 0x04)
  , TlvRecord 9  (BS.replicate 8 0x05)
  , TlvRecord 11 (BS.replicate 16 0x06)
  , TlvRecord 13 (BS.replicate 8 0x07)
  , TlvRecord 15 (BS.replicate 16 0x08)
  , TlvRecord 17 (BS.replicate 8 0x09)
  , TlvRecord 19 (BS.replicate 16 0x0a)
  , TlvRecord 21 (BS.replicate 8 0x0b)
  , TlvRecord 23 (BS.replicate 16 0x0c)
  , TlvRecord 25 (BS.replicate 8 0x0d)
  , TlvRecord 27 (BS.replicate 16 0x0e)
  , TlvRecord 29 (BS.replicate 8 0x0f)
  , TlvRecord 31 (BS.replicate 16 0x10)
  , TlvRecord 33 (BS.replicate 8 0x11)
  , TlvRecord 35 (BS.replicate 16 0x12)
  , TlvRecord 37 (BS.replicate 8 0x13)
  , TlvRecord 39 (BS.replicate 16 0x14)
  ]
{-# NOINLINE largeTlvStream #-}

-- Encoded message bytes (for decode benchmarks) --------------------------

-- Helper to encode or fail.
encodeOrFail :: Either EncodeError BS.ByteString -> BS.ByteString
encodeOrFail (Right bs) = bs
encodeOrFail (Left _)   = error "encodeOrFail: encoding failed"

-- | Encoded minimal Init.
encodedMinimalInit :: BS.ByteString
encodedMinimalInit = encodeOrFail $ encodeEnvelope (MsgInitVal minimalInit) Nothing
{-# NOINLINE encodedMinimalInit #-}

-- | Encoded Init with TLVs.
encodedInitWithTlvs :: BS.ByteString
encodedInitWithTlvs = encodeOrFail $ encodeEnvelope (MsgInitVal initWithTlvs) Nothing
{-# NOINLINE encodedInitWithTlvs #-}

-- | Encoded full Init.
encodedFullInit :: BS.ByteString
encodedFullInit = encodeOrFail $ encodeEnvelope (MsgInitVal fullInit) Nothing
{-# NOINLINE encodedFullInit #-}

-- | Encoded minimal Error.
encodedMinimalError :: BS.ByteString
encodedMinimalError = encodeOrFail $ encodeEnvelope (MsgErrorVal minimalError) Nothing
{-# NOINLINE encodedMinimalError #-}

-- | Encoded Error with data.
encodedErrorWithData :: BS.ByteString
encodedErrorWithData = encodeOrFail $ encodeEnvelope (MsgErrorVal errorWithData) Nothing
{-# NOINLINE encodedErrorWithData #-}

-- | Encoded minimal Warning.
encodedMinimalWarning :: BS.ByteString
encodedMinimalWarning = encodeOrFail $
  encodeEnvelope (MsgWarningVal minimalWarning) Nothing
{-# NOINLINE encodedMinimalWarning #-}

-- | Encoded Warning with data.
encodedWarningWithData :: BS.ByteString
encodedWarningWithData = encodeOrFail $
  encodeEnvelope (MsgWarningVal warningWithData) Nothing
{-# NOINLINE encodedWarningWithData #-}

-- | Encoded minimal Ping.
encodedMinimalPing :: BS.ByteString
encodedMinimalPing = encodeOrFail $ encodeEnvelope (MsgPingVal minimalPing) Nothing
{-# NOINLINE encodedMinimalPing #-}

-- | Encoded Ping with padding.
encodedPingWithPadding :: BS.ByteString
encodedPingWithPadding = encodeOrFail $
  encodeEnvelope (MsgPingVal pingWithPadding) Nothing
{-# NOINLINE encodedPingWithPadding #-}

-- | Encoded Ping with large padding.
encodedPingWithLargePadding :: BS.ByteString
encodedPingWithLargePadding = encodeOrFail $
  encodeEnvelope (MsgPingVal pingWithLargePadding) Nothing
{-# NOINLINE encodedPingWithLargePadding #-}

-- | Encoded minimal Pong.
encodedMinimalPong :: BS.ByteString
encodedMinimalPong = encodeOrFail $ encodeEnvelope (MsgPongVal minimalPong) Nothing
{-# NOINLINE encodedMinimalPong #-}

-- | Encoded Pong with padding.
encodedPongWithPadding :: BS.ByteString
encodedPongWithPadding = encodeOrFail $
  encodeEnvelope (MsgPongVal pongWithPadding) Nothing
{-# NOINLINE encodedPongWithPadding #-}

-- | Encoded minimal PeerStorage.
encodedMinimalPeerStorage :: BS.ByteString
encodedMinimalPeerStorage = encodeOrFail $
  encodeEnvelope (MsgPeerStorageVal minimalPeerStorage) Nothing
{-# NOINLINE encodedMinimalPeerStorage #-}

-- | Encoded PeerStorage with 1KB blob.
encodedPeerStorageSmall :: BS.ByteString
encodedPeerStorageSmall = encodeOrFail $
  encodeEnvelope (MsgPeerStorageVal peerStorageSmall) Nothing
{-# NOINLINE encodedPeerStorageSmall #-}

-- | Encoded minimal PeerStorageRetrieval.
encodedMinimalPeerStorageRetrieval :: BS.ByteString
encodedMinimalPeerStorageRetrieval = encodeOrFail $
  encodeEnvelope (MsgPeerStorageRetrievalVal minimalPeerStorageRetrieval) Nothing
{-# NOINLINE encodedMinimalPeerStorageRetrieval #-}

-- | Encoded PeerStorageRetrieval with 1KB blob.
encodedPeerStorageRetrievalSmall :: BS.ByteString
encodedPeerStorageRetrievalSmall = encodeOrFail $
  encodeEnvelope (MsgPeerStorageRetrievalVal peerStorageRetrievalSmall) Nothing
{-# NOINLINE encodedPeerStorageRetrievalSmall #-}

-- Encoded TLV streams (for decode benchmarks) ----------------------------

-- | Encoded empty TLV stream.
encodedEmptyTlvStream :: BS.ByteString
encodedEmptyTlvStream = encodeTlvStream emptyTlvStream
{-# NOINLINE encodedEmptyTlvStream #-}

-- | Encoded small TLV stream (1 record).
encodedSmallTlvStream :: BS.ByteString
encodedSmallTlvStream = encodeTlvStream smallTlvStream
{-# NOINLINE encodedSmallTlvStream #-}

-- | Encoded medium TLV stream (5 records).
encodedMediumTlvStream :: BS.ByteString
encodedMediumTlvStream = encodeTlvStream mediumTlvStream
{-# NOINLINE encodedMediumTlvStream #-}

-- | Encoded large TLV stream (20 records).
encodedLargeTlvStream :: BS.ByteString
encodedLargeTlvStream = encodeTlvStream largeTlvStream
{-# NOINLINE encodedLargeTlvStream #-}