commit 897e5397e0818a9014ba6f4ba2e29df8788a0295
parent e1594651e67c02a83079506762b019fb4fe42218
Author: Jared Tobin <jared@jtobin.io>
Date: Sat, 18 Apr 2026 21:15:27 +0800
Add criterion and weigh benchmarks
Criterion benchmarks for spend_to_local, spend_revoked_to_local,
spend_anchor_owner, spend_revoked_batch (10/100/483 outputs),
spending_fee, and htlc_timed_out.
Weigh allocation benchmarks for spend_to_local,
spend_anchor_owner, and spend_revoked_batch (10/100/483 outputs).
Both suites include orphan NFData instances for bolt3 and bolt5
types needed by criterion's nf and weigh's func.
Diffstat:
| M | bench/Main.hs | | | 177 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
| M | bench/Weight.hs | | | 142 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
2 files changed, 309 insertions(+), 10 deletions(-)
diff --git a/bench/Main.hs b/bench/Main.hs
@@ -1,16 +1,183 @@
{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
module Main where
+import Bitcoin.Prim.Tx.Sighash (SighashType(..))
+import Control.DeepSeq (NFData(..))
import Criterion.Main
-import qualified Lightning.Protocol.BOLT5 as BOLT5
+import qualified Data.ByteString as BS
+import Lightning.Protocol.BOLT3 hiding
+ (txout_value, txout_script)
+import qualified Lightning.Protocol.BOLT5 as B5
+
+-- NFData orphan instances for criterion -----------------------------
+
+instance NFData Satoshi where
+ rnf (Satoshi x) = rnf x
+
+instance NFData MilliSatoshi where
+ rnf (MilliSatoshi x) = rnf x
+
+instance NFData Script where
+ rnf (Script bs) = rnf bs
+
+instance NFData Pubkey where
+ rnf (Pubkey x) = rnf x
+
+instance NFData Point where
+ rnf (Point x) = rnf x
+
+instance NFData RevocationPubkey where
+ rnf (RevocationPubkey x) = rnf x
+
+instance NFData LocalDelayedPubkey where
+ rnf (LocalDelayedPubkey p) = rnf p
+
+instance NFData FundingPubkey where
+ rnf (FundingPubkey p) = rnf p
+
+instance NFData FeeratePerKw where
+ rnf (FeeratePerKw x) = rnf x
+
+instance NFData ToSelfDelay where
+ rnf (ToSelfDelay x) = rnf x
+
+instance NFData PaymentHash where
+ rnf (PaymentHash x) = rnf x
+
+instance NFData CltvExpiry where
+ rnf (CltvExpiry x) = rnf x
+
+instance NFData HTLCDirection where
+ rnf HTLCOffered = ()
+ rnf HTLCReceived = ()
+
+instance NFData HTLC where
+ rnf (HTLC d a h c) =
+ rnf d `seq` rnf a `seq` rnf h `seq` rnf c
+
+instance NFData SighashType
+
+instance NFData B5.OutputResolution where
+ rnf B5.Resolved = ()
+ rnf (B5.Revoke rk) = rnf rk
+ rnf _ = ()
+
+instance NFData B5.UnresolvedOutput where
+ rnf (B5.UnresolvedOutput op v t) =
+ rnf op `seq` rnf v `seq` rnf t
+
+instance NFData B5.SpendingTx where
+ rnf (B5.SpendingTx tx scr val sh) =
+ rnf tx `seq` rnf scr `seq` rnf val `seq` rnf sh
+
+instance NFData B5.PenaltyContext where
+ rnf (B5.PenaltyContext os rk d f) =
+ rnf os `seq` rnf rk `seq` rnf d `seq` rnf f
main :: IO ()
main = defaultMain [
- placeholder
+ spend_benchmarks
+ , classify_benchmarks
]
-placeholder :: Benchmark
-placeholder = bgroup "placeholder" [
- bench "placeholder" $ nf (const BOLT5.placeholder) ()
+-- fixtures -----------------------------------------------------------
+
+dummyPubkey :: Pubkey
+dummyPubkey = case pubkey (BS.pack (0x02 : replicate 32 0x01)) of
+ Just pk -> pk
+ Nothing -> error "impossible"
+
+dummyTxId :: TxId
+dummyTxId = case mkTxId (BS.replicate 32 0x00) of
+ Just tid -> tid
+ Nothing -> error "impossible"
+
+dummyOutPoint :: OutPoint
+dummyOutPoint = OutPoint dummyTxId 0
+
+dummyRevPk :: RevocationPubkey
+dummyRevPk = RevocationPubkey dummyPubkey
+
+dummyDelayedPk :: LocalDelayedPubkey
+dummyDelayedPk = LocalDelayedPubkey dummyPubkey
+
+dummyFundPk :: FundingPubkey
+dummyFundPk = FundingPubkey dummyPubkey
+
+dummyDest :: Script
+dummyDest = Script $ BS.pack [0x00, 0x14] <>
+ BS.replicate 20 0xCC
+
+dummyFeerate :: FeeratePerKw
+dummyFeerate = FeeratePerKw 253
+
+dummyDelay :: ToSelfDelay
+dummyDelay = ToSelfDelay 144
+
+mkRevokedOutputs :: Int -> [B5.UnresolvedOutput]
+mkRevokedOutputs n =
+ [ B5.UnresolvedOutput
+ (OutPoint dummyTxId (fromIntegral i))
+ (Satoshi 10000)
+ (B5.Revoke dummyRevPk)
+ | i <- [0..n-1]
+ ]
+
+-- benchmarks ---------------------------------------------------------
+
+spend_benchmarks :: Benchmark
+spend_benchmarks = bgroup "spend" [
+ bench "spend_to_local" $
+ nf (\v -> B5.spend_to_local
+ dummyOutPoint v dummyRevPk dummyDelay
+ dummyDelayedPk dummyDest dummyFeerate)
+ (Satoshi 100000)
+
+ , bench "spend_revoked_to_local" $
+ nf (\v -> B5.spend_revoked_to_local
+ dummyOutPoint v dummyRevPk dummyDelay
+ dummyDelayedPk dummyDest dummyFeerate)
+ (Satoshi 100000)
+
+ , bench "spend_anchor_owner" $
+ nf (\v -> B5.spend_anchor_owner
+ dummyOutPoint v dummyFundPk dummyDest)
+ (Satoshi 330)
+
+ , bench "spend_revoked_batch/10" $
+ nf B5.spend_revoked_batch
+ (B5.PenaltyContext
+ (mkRevokedOutputs 10)
+ dummyRevPk dummyDest dummyFeerate)
+
+ , bench "spend_revoked_batch/100" $
+ nf B5.spend_revoked_batch
+ (B5.PenaltyContext
+ (mkRevokedOutputs 100)
+ dummyRevPk dummyDest dummyFeerate)
+
+ , bench "spend_revoked_batch/483" $
+ nf B5.spend_revoked_batch
+ (B5.PenaltyContext
+ (mkRevokedOutputs 483)
+ dummyRevPk dummyDest dummyFeerate)
+ ]
+
+classify_benchmarks :: Benchmark
+classify_benchmarks = bgroup "classify" [
+ bench "spending_fee" $
+ nf (B5.spending_fee dummyFeerate) 538
+
+ , bench "htlc_timed_out" $
+ nf (B5.htlc_timed_out 500001)
+ (HTLC HTLCOffered (MilliSatoshi 1000000)
+ dummyPaymentHash (CltvExpiry 500000))
]
+ where
+ dummyPaymentHash = case payment_hash
+ (BS.replicate 32 0xAA) of
+ Just ph -> ph
+ Nothing -> error "impossible"
diff --git a/bench/Weight.hs b/bench/Weight.hs
@@ -1,14 +1,146 @@
{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
module Main where
-import qualified Lightning.Protocol.BOLT5 as BOLT5
+import Bitcoin.Prim.Tx.Sighash (SighashType(..))
+import Control.DeepSeq (NFData(..))
+import qualified Data.ByteString as BS
+import Lightning.Protocol.BOLT3 hiding
+ (txout_value, txout_script)
+import qualified Lightning.Protocol.BOLT5 as B5
import Weigh
+-- NFData orphan instances for weigh ---------------------------------
+
+instance NFData Satoshi where
+ rnf (Satoshi x) = rnf x
+
+instance NFData Script where
+ rnf (Script bs) = rnf bs
+
+instance NFData Pubkey where
+ rnf (Pubkey x) = rnf x
+
+instance NFData Point where
+ rnf (Point x) = rnf x
+
+instance NFData RevocationPubkey where
+ rnf (RevocationPubkey x) = rnf x
+
+instance NFData LocalDelayedPubkey where
+ rnf (LocalDelayedPubkey p) = rnf p
+
+instance NFData FundingPubkey where
+ rnf (FundingPubkey p) = rnf p
+
+instance NFData FeeratePerKw where
+ rnf (FeeratePerKw x) = rnf x
+
+instance NFData ToSelfDelay where
+ rnf (ToSelfDelay x) = rnf x
+
+instance NFData SighashType
+
+instance NFData B5.OutputResolution where
+ rnf B5.Resolved = ()
+ rnf (B5.Revoke rk) = rnf rk
+ rnf _ = ()
+
+instance NFData B5.UnresolvedOutput where
+ rnf (B5.UnresolvedOutput op v t) =
+ rnf op `seq` rnf v `seq` rnf t
+
+instance NFData B5.SpendingTx where
+ rnf (B5.SpendingTx tx scr val sh) =
+ rnf tx `seq` rnf scr `seq` rnf val `seq` rnf sh
+
+instance NFData B5.PenaltyContext where
+ rnf (B5.PenaltyContext os rk d f) =
+ rnf os `seq` rnf rk `seq` rnf d `seq` rnf f
+
-- note that 'weigh' doesn't work properly in a repl
main :: IO ()
-main = mainWith placeholder
+main = mainWith $ do
+ spend_weights
+ batch_weights
+
+-- fixtures -----------------------------------------------------------
+
+dummyPubkey :: Pubkey
+dummyPubkey = case pubkey (BS.pack (0x02 : replicate 32 0x01)) of
+ Just pk -> pk
+ Nothing -> error "impossible"
+
+dummyTxId :: TxId
+dummyTxId = case mkTxId (BS.replicate 32 0x00) of
+ Just tid -> tid
+ Nothing -> error "impossible"
+
+dummyOutPoint :: OutPoint
+dummyOutPoint = OutPoint dummyTxId 0
+
+dummyRevPk :: RevocationPubkey
+dummyRevPk = RevocationPubkey dummyPubkey
+
+dummyDelayedPk :: LocalDelayedPubkey
+dummyDelayedPk = LocalDelayedPubkey dummyPubkey
+
+dummyFundPk :: FundingPubkey
+dummyFundPk = FundingPubkey dummyPubkey
+
+dummyDest :: Script
+dummyDest = Script $ BS.pack [0x00, 0x14] <>
+ BS.replicate 20 0xCC
+
+dummyFeerate :: FeeratePerKw
+dummyFeerate = FeeratePerKw 253
+
+dummyDelay :: ToSelfDelay
+dummyDelay = ToSelfDelay 144
+
+mkRevokedOutputs :: Int -> [B5.UnresolvedOutput]
+mkRevokedOutputs n =
+ [ B5.UnresolvedOutput
+ (OutPoint dummyTxId (fromIntegral i))
+ (Satoshi 10000)
+ (B5.Revoke dummyRevPk)
+ | i <- [0..n-1]
+ ]
+
+-- weights ------------------------------------------------------------
+
+spend_weights :: Weigh ()
+spend_weights = wgroup "spend" $ do
+ func "spend_to_local"
+ (\v -> B5.spend_to_local
+ dummyOutPoint v dummyRevPk dummyDelay
+ dummyDelayedPk dummyDest dummyFeerate)
+ (Satoshi 100000)
+
+ func "spend_anchor_owner"
+ (\v -> B5.spend_anchor_owner
+ dummyOutPoint v dummyFundPk dummyDest)
+ (Satoshi 330)
+
+batch_weights :: Weigh ()
+batch_weights = wgroup "batch" $ do
+ func "spend_revoked_batch/10"
+ B5.spend_revoked_batch
+ (B5.PenaltyContext
+ (mkRevokedOutputs 10)
+ dummyRevPk dummyDest dummyFeerate)
+
+ func "spend_revoked_batch/100"
+ B5.spend_revoked_batch
+ (B5.PenaltyContext
+ (mkRevokedOutputs 100)
+ dummyRevPk dummyDest dummyFeerate)
-placeholder :: Weigh ()
-placeholder = wgroup "placeholder" $
- func "placeholder" (const BOLT5.placeholder) ()
+ func "spend_revoked_batch/483"
+ B5.spend_revoked_batch
+ (B5.PenaltyContext
+ (mkRevokedOutputs 483)
+ dummyRevPk dummyDest dummyFeerate)