bolt9

Lightning feature flags, per BOLT #9.
git clone git://git.ppad.tech/bolt9.git
Log | Files | Refs | README | LICENSE

commit f1117eb44c3d2ceaeb1a19e2bb8444d161b7e607
parent 78c23f1935dceff739ae99086e579b6bfe1afd00
Author: Jared Tobin <jared@jtobin.io>
Date:   Sun, 25 Jan 2026 16:04:26 +0400

Add Criterion and Weigh benchmarks

Criterion benchmarks for parse, render, bit operations, validation,
and feature lookups. Weigh benchmarks for allocation profiling.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Diffstat:
Abench/Fixtures.hs | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbench/Main.hs | 36+++++++++++++++++++++++++++++++++++-
Mbench/Weight.hs | 17+++++++++++++++--
Mppad-bolt9.cabal | 2++
4 files changed, 109 insertions(+), 3 deletions(-)

diff --git a/bench/Fixtures.hs b/bench/Fixtures.hs @@ -0,0 +1,57 @@ +module Fixtures ( + -- * ByteString fixtures + typicalBytes + , emptyBytes + , largeBytes + + -- * FeatureVector fixtures + , typicalFV + , emptyFV + , validFV + , unknownBitsFV + ) where + +import Data.ByteString (ByteString) +import qualified Data.ByteString as BS +import qualified Lightning.Protocol.BOLT9 as B9 + +-- ByteString fixtures -------------------------------------------------------- + +-- | A typical 8-byte feature vector with several common features set: +-- basic_mpp (bit 17), option_anchors (bit 23), option_route_blinding (bit 25) +typicalBytes :: ByteString +typicalBytes = BS.pack [0x02, 0x82, 0x00, 0x00] + +-- | Empty ByteString for parsing. +emptyBytes :: ByteString +emptyBytes = BS.empty + +-- | Large 64-byte feature vector for stress testing. +largeBytes :: ByteString +largeBytes = BS.pack $ replicate 64 0xAA + +-- FeatureVector fixtures ----------------------------------------------------- + +-- | A typical feature vector with common features set (optional bits): +-- basic_mpp (17), option_anchors (23), option_route_blinding (25) +typicalFV :: B9.FeatureVector +typicalFV = B9.parse typicalBytes + +-- | Empty feature vector. +emptyFV :: B9.FeatureVector +emptyFV = B9.empty + +-- | A valid feature vector for validation benchmarks. +-- Sets payment_secret (required for basic_mpp dependency) and basic_mpp. +validFV :: B9.FeatureVector +validFV = B9.setBit 15 -- payment_secret (optional) + $ B9.setBit 17 -- basic_mpp (optional) + $ B9.setBit 23 -- option_anchors (optional) + $ B9.empty + +-- | A feature vector with unknown bits for remote validation. +-- Contains a known feature plus an unknown odd bit (safe to ignore). +unknownBitsFV :: B9.FeatureVector +unknownBitsFV = B9.setBit 15 -- payment_secret (optional, known) + $ B9.setBit 99 -- unknown odd bit (should be ignored) + $ B9.empty diff --git a/bench/Main.hs b/bench/Main.hs @@ -1,8 +1,42 @@ module Main where import Criterion.Main +import Data.Maybe (fromJust) +import qualified Lightning.Protocol.BOLT9 as B9 +import Fixtures + +basic_mpp :: B9.Feature +basic_mpp = fromJust (B9.featureByName "basic_mpp") main :: IO () main = defaultMain [ - -- TODO + bgroup "parse" [ + bench "typical (8 bytes)" $ nf B9.parse typicalBytes + , bench "empty" $ nf B9.parse emptyBytes + , bench "large (64 bytes)" $ nf B9.parse largeBytes + ] + + , bgroup "render" [ + bench "typical" $ nf B9.render typicalFV + , bench "empty" $ nf B9.render emptyFV + ] + + , bgroup "bit-ops" [ + bench "setBit" $ nf (B9.setBit 50) typicalFV + , bench "testBit" $ nf (B9.testBit 17) typicalFV + , bench "hasFeature" $ + nf (flip B9.hasFeature typicalFV) basic_mpp + ] + + , bgroup "validate" [ + bench "validateLocal (valid)" $ + nf (B9.validateLocal B9.Init) validFV + , bench "validateRemote (unknown bits)" $ + nf (B9.validateRemote B9.Init) unknownBitsFV + ] + + , bgroup "lookup" [ + bench "featureByBit" $ nf B9.featureByBit 16 + , bench "featureByName" $ nf B9.featureByName "basic_mpp" + ] ] diff --git a/bench/Weight.hs b/bench/Weight.hs @@ -1,8 +1,21 @@ module Main where import Weigh +import qualified Lightning.Protocol.BOLT9 as B9 +import Fixtures main :: IO () main = mainWith $ do - pure () - -- TODO + func "FeatureVector (5 features)" mkFiveFeatures () + func "validateLocal" (B9.validateLocal B9.Init) validFV + func "listFeatures" B9.listFeatures validFV + +-- | Create a FeatureVector with 5 features set. +mkFiveFeatures :: () -> B9.FeatureVector +mkFiveFeatures _ = + B9.setBit 15 -- payment_secret + $ B9.setBit 17 -- basic_mpp + $ B9.setBit 23 -- option_anchors + $ B9.setBit 25 -- option_route_blinding + $ B9.setBit 27 -- option_shutdown_anysegwit + $ B9.empty diff --git a/ppad-bolt9.cabal b/ppad-bolt9.cabal @@ -56,6 +56,7 @@ benchmark bolt9-bench default-language: Haskell2010 hs-source-dirs: bench main-is: Main.hs + other-modules: Fixtures ghc-options: -rtsopts -O2 -Wall -fno-warn-orphans @@ -72,6 +73,7 @@ benchmark bolt9-weigh default-language: Haskell2010 hs-source-dirs: bench main-is: Weight.hs + other-modules: Fixtures ghc-options: -rtsopts -O2 -Wall -fno-warn-orphans