bolt9

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

commit 86b8dc8b59cecdb3147b5c4c2fe543cf7dd6767f
parent 24d8381ecd16052d3d40ad702961cc366c6f7d15
Author: Jared Tobin <jared@jtobin.io>
Date:   Sat, 10 Oct 2026 13:13:53 +0400

lib: clear the opposite bit when setting a feature

BOLT 9 forbids setting both bits of a pair. setFeature now clears the
other bit of the pair, which setFeatureWithDeps and
setFeatureForContext inherit. setFeatureWithDeps no longer changes the
level of a dependency that is already set.

Diffstat:
Mlib/Lightning/Protocol/BOLT9/Codec.hs | 21+++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/lib/Lightning/Protocol/BOLT9/Codec.hs b/lib/Lightning/Protocol/BOLT9/Codec.hs @@ -89,7 +89,8 @@ testBit !idx = member (bitIndex idx) -- | Set a feature's bit at the given level. -- --- 'Required' sets the even bit, 'Optional' sets the odd bit. +-- 'Required' sets the even bit, 'Optional' sets the odd bit. The +-- other bit of the pair is cleared, so both are never set. -- -- >>> import Data.Maybe (fromJust) -- >>> let mpp = fromJust (featureByName "basic_mpp") @@ -98,17 +99,17 @@ testBit !idx = member (bitIndex idx) -- >>> setFeature mpp Required empty -- set required bit (16) -- FeatureVector {unFeatureVector = "\SOH"} setFeature :: Feature -> FeatureLevel -> FeatureVector -> FeatureVector -setFeature !f !level = setBit targetBit +setFeature !f !level = case level of + Required -> setBit baseBit . clearBit (baseBit + 1) + Optional -> setBit (baseBit + 1) . clearBit baseBit where - !baseBit = featureBaseBit f - !targetBit = case level of - Required -> baseBit - Optional -> baseBit + 1 + !baseBit = featureBaseBit f {-# INLINE setFeature #-} -- | Set a feature and all its transitive dependencies. -- --- Dependencies are set at the same level as the feature itself. +-- Dependencies that are not yet set are set at the same level as +-- the feature itself; dependencies already set keep their level. -- Unknown dependencies (not in the known features table) are -- silently skipped. -- @@ -128,7 +129,11 @@ setFeatureWithDeps !f !level !fv = where setDep !depName !acc = case featureByName depName of Nothing -> acc - Just dep -> setFeatureWithDeps dep level acc + Just dep + | isFeatureSet dep acc -> + foldr setDep acc (featureDependencies dep) + | otherwise -> + setFeatureWithDeps dep level acc -- | Check if a feature is set in the vector. --