| Copyright | (c) 2025 Jared Tobin |
|---|---|
| License | MIT |
| Maintainer | Jared Tobin <jared@ppad.tech> |
| Safe Haskell | Safe-Inferred |
| Language | Haskell2010 |
Lightning.Protocol.BOLT9
Description
Feature flags for the Lightning Network, per BOLT #9.
Overview
BOLT #9 defines feature flags that Lightning nodes advertise to indicate support for optional protocol features. Features are represented as bit positions in a variable-length bit vector, where even bits indicate required (compulsory) support and odd bits indicate optional support.
This library provides:
- Type-safe feature vectors with efficient bit manipulation
- A complete table of known features from the BOLT #9 specification
- Validation for both locally-created and remotely-received vectors
- Context-aware validation (init, node_announcement, invoice, etc.)
Quick Start
Create a feature vector and set some features:
>>>import Lightning.Protocol.BOLT9>>>let Just mpp = featureByName "basic_mpp">>>let fv = setFeature mpp Optional empty>>>hasFeature mpp fvJust Optional
Validate a feature vector for a specific context:
>>>validateLocal Init fvLeft [MissingDependency "basic_mpp" "payment_secret"]
Fix by adding the dependency:
>>>let Just ps = featureByName "payment_secret">>>let fv' = setFeature ps Optional (setFeature mpp Optional empty)>>>validateLocal Init fv'Right ()
Bit Numbering
Features use paired bits: even bits (0, 2, 4, ...) indicate required
support, while odd bits (1, 3, 5, ...) indicate optional support.
For example, basic_mpp uses bit 16 (required) and 17 (optional).
A node setting bit 16 requires all peers to support basic_mpp.
A node setting bit 17 indicates optional support (peers without it
may still connect).
Synopsis
- data Context
- = Init
- | NodeAnn
- | ChanAnn
- | ChanAnnOdd
- | ChanAnnEven
- | Invoice
- | Blinded
- | ChanType
- isChannelContext :: Context -> Bool
- channelParity :: Context -> Maybe Bool
- data BitIndex
- bitIndex :: Word16 -> BitIndex
- data FeatureLevel
- data RequiredBit
- requiredBit :: Word16 -> Maybe RequiredBit
- requiredFromBitIndex :: BitIndex -> Maybe RequiredBit
- data OptionalBit
- optionalBit :: Word16 -> Maybe OptionalBit
- optionalFromBitIndex :: BitIndex -> Maybe OptionalBit
- data FeatureVector
- empty :: FeatureVector
- fromByteString :: ByteString -> FeatureVector
- set :: BitIndex -> FeatureVector -> FeatureVector
- clear :: BitIndex -> FeatureVector -> FeatureVector
- member :: BitIndex -> FeatureVector -> Bool
- data Feature = Feature {
- featureName :: !String
- featureBaseBit :: !Word16
- featureContexts :: ![Context]
- featureDependencies :: ![String]
- featureAssumed :: !Bool
- featureByBit :: Word16 -> Maybe Feature
- featureByName :: String -> Maybe Feature
- knownFeatures :: [Feature]
- parse :: ByteString -> FeatureVector
- render :: FeatureVector -> ByteString
- setBit :: Word16 -> FeatureVector -> FeatureVector
- clearBit :: Word16 -> FeatureVector -> FeatureVector
- testBit :: Word16 -> FeatureVector -> Bool
- setFeature :: Feature -> FeatureLevel -> FeatureVector -> FeatureVector
- hasFeature :: Feature -> FeatureVector -> Maybe FeatureLevel
- isFeatureSet :: Feature -> FeatureVector -> Bool
- listFeatures :: FeatureVector -> [(Feature, FeatureLevel)]
- data ValidationError
- validateLocal :: Context -> FeatureVector -> Either [ValidationError] ()
- validateRemote :: Context -> FeatureVector -> Either [ValidationError] ()
- highestSetBit :: FeatureVector -> Maybe Word16
- setBits :: FeatureVector -> [Word16]
Context
Contexts specify where feature flags appear in the protocol.
Presentation context for feature flags.
Per BOLT #9, features are presented in different message contexts:
Init- theinitmessageNodeAnn-node_announcementmessagesChanAnn-channel_announcementmessages (normal)ChanAnnOdd-channel_announcement, always odd (optional)ChanAnnEven-channel_announcement, always even (required)Invoice- BOLT 11 invoicesBlinded-allowed_featuresfield of a blinded pathChanType-channel_typefield when opening channels
Constructors
| Init | I: presented in the |
| NodeAnn | N: presented in |
| ChanAnn | C: presented in |
| ChanAnnOdd | C-: |
| ChanAnnEven | C+: |
| Invoice | 9: presented in BOLT 11 invoices |
| Blinded | B: |
| ChanType | T: |
Instances
isChannelContext :: Context -> Bool Source #
Check if a context is a channel announcement context (C, C-, or C+).
Bit indices
Low-level bit index types for direct bit manipulation.
A bit index into a feature vector. Bit 0 is the least significant bit.
Valid range: 0-65535 (sufficient for any practical feature flag).
Instances
| NFData BitIndex Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types | |||||
| Generic BitIndex Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Associated Types
| |||||
| Show BitIndex Source # | |||||
| Eq BitIndex Source # | |||||
| Ord BitIndex Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types | |||||
| type Rep BitIndex Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types | |||||
bitIndex :: Word16 -> BitIndex Source #
Smart constructor for BitIndex. Always succeeds since all Word16
values are valid.
Required/optional level
Whether a feature is set as required or optional.
data FeatureLevel Source #
Whether a feature is set as required or optional.
Per BOLT #9, each feature has a pair of bits: the even bit indicates required (compulsory) support, the odd bit indicates optional support.
Constructors
| Required | The feature is required (even bit set) |
| Optional | The feature is optional (odd bit set) |
Instances
| NFData FeatureLevel Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods rnf :: FeatureLevel -> () # | |||||
| Generic FeatureLevel Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Associated Types
| |||||
| Show FeatureLevel Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods showsPrec :: Int -> FeatureLevel -> ShowS # show :: FeatureLevel -> String # showList :: [FeatureLevel] -> ShowS # | |||||
| Eq FeatureLevel Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types | |||||
| Ord FeatureLevel Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods compare :: FeatureLevel -> FeatureLevel -> Ordering # (<) :: FeatureLevel -> FeatureLevel -> Bool # (<=) :: FeatureLevel -> FeatureLevel -> Bool # (>) :: FeatureLevel -> FeatureLevel -> Bool # (>=) :: FeatureLevel -> FeatureLevel -> Bool # max :: FeatureLevel -> FeatureLevel -> FeatureLevel # min :: FeatureLevel -> FeatureLevel -> FeatureLevel # | |||||
| type Rep FeatureLevel Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types | |||||
Required/optional bits
Type-safe wrappers ensuring correct parity.
data RequiredBit Source #
A required (compulsory) feature bit. Required bits are always even.
Instances
| NFData RequiredBit Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods rnf :: RequiredBit -> () # | |||||
| Generic RequiredBit Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Associated Types
| |||||
| Show RequiredBit Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods showsPrec :: Int -> RequiredBit -> ShowS # show :: RequiredBit -> String # showList :: [RequiredBit] -> ShowS # | |||||
| Eq RequiredBit Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types | |||||
| Ord RequiredBit Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods compare :: RequiredBit -> RequiredBit -> Ordering # (<) :: RequiredBit -> RequiredBit -> Bool # (<=) :: RequiredBit -> RequiredBit -> Bool # (>) :: RequiredBit -> RequiredBit -> Bool # (>=) :: RequiredBit -> RequiredBit -> Bool # max :: RequiredBit -> RequiredBit -> RequiredBit # min :: RequiredBit -> RequiredBit -> RequiredBit # | |||||
| type Rep RequiredBit Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types type Rep RequiredBit = D1 ('MetaData "RequiredBit" "Lightning.Protocol.BOLT9.Types" "ppad-bolt9-0.0.1-SCTy7SY2nBJMXEGG76XgS" 'True) (C1 ('MetaCons "RequiredBit" 'PrefixI 'True) (S1 ('MetaSel ('Just "unRequiredBit") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Word16))) | |||||
requiredBit :: Word16 -> Maybe RequiredBit Source #
Smart constructor for RequiredBit. Returns Nothing if the bit
index is odd.
>>>requiredBit 16Just (RequiredBit {unRequiredBit = 16})>>>requiredBit 17Nothing
requiredFromBitIndex :: BitIndex -> Maybe RequiredBit Source #
Convert a BitIndex to a RequiredBit. Returns Nothing if odd.
data OptionalBit Source #
An optional feature bit. Optional bits are always odd.
Instances
| NFData OptionalBit Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods rnf :: OptionalBit -> () # | |||||
| Generic OptionalBit Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Associated Types
| |||||
| Show OptionalBit Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods showsPrec :: Int -> OptionalBit -> ShowS # show :: OptionalBit -> String # showList :: [OptionalBit] -> ShowS # | |||||
| Eq OptionalBit Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types | |||||
| Ord OptionalBit Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods compare :: OptionalBit -> OptionalBit -> Ordering # (<) :: OptionalBit -> OptionalBit -> Bool # (<=) :: OptionalBit -> OptionalBit -> Bool # (>) :: OptionalBit -> OptionalBit -> Bool # (>=) :: OptionalBit -> OptionalBit -> Bool # max :: OptionalBit -> OptionalBit -> OptionalBit # min :: OptionalBit -> OptionalBit -> OptionalBit # | |||||
| type Rep OptionalBit Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types type Rep OptionalBit = D1 ('MetaData "OptionalBit" "Lightning.Protocol.BOLT9.Types" "ppad-bolt9-0.0.1-SCTy7SY2nBJMXEGG76XgS" 'True) (C1 ('MetaCons "OptionalBit" 'PrefixI 'True) (S1 ('MetaSel ('Just "unOptionalBit") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Word16))) | |||||
optionalBit :: Word16 -> Maybe OptionalBit Source #
Smart constructor for OptionalBit. Returns Nothing if the bit
index is even.
>>>optionalBit 17Just (OptionalBit {unOptionalBit = 17})>>>optionalBit 16Nothing
optionalFromBitIndex :: BitIndex -> Maybe OptionalBit Source #
Convert a BitIndex to an OptionalBit. Returns Nothing if even.
Feature vectors
The core feature vector type and basic operations.
data FeatureVector Source #
A feature vector represented as a strict ByteString.
The vector is stored in big-endian byte order (most significant byte first), with bits numbered from the least significant bit of the last byte. Bit 0 is at position 0 of the last byte.
Instances
| NFData FeatureVector Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods rnf :: FeatureVector -> () # | |||||
| Generic FeatureVector Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Associated Types
| |||||
| Show FeatureVector Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods showsPrec :: Int -> FeatureVector -> ShowS # show :: FeatureVector -> String # showList :: [FeatureVector] -> ShowS # | |||||
| Eq FeatureVector Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods (==) :: FeatureVector -> FeatureVector -> Bool # (/=) :: FeatureVector -> FeatureVector -> Bool # | |||||
| Ord FeatureVector Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types Methods compare :: FeatureVector -> FeatureVector -> Ordering # (<) :: FeatureVector -> FeatureVector -> Bool # (<=) :: FeatureVector -> FeatureVector -> Bool # (>) :: FeatureVector -> FeatureVector -> Bool # (>=) :: FeatureVector -> FeatureVector -> Bool # max :: FeatureVector -> FeatureVector -> FeatureVector # min :: FeatureVector -> FeatureVector -> FeatureVector # | |||||
| type Rep FeatureVector Source # | |||||
Defined in Lightning.Protocol.BOLT9.Types type Rep FeatureVector = D1 ('MetaData "FeatureVector" "Lightning.Protocol.BOLT9.Types" "ppad-bolt9-0.0.1-SCTy7SY2nBJMXEGG76XgS" 'True) (C1 ('MetaCons "FeatureVector" 'PrefixI 'True) (S1 ('MetaSel ('Just "unFeatureVector") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ByteString))) | |||||
empty :: FeatureVector Source #
The empty feature vector (no features set).
>>>emptyFeatureVector {unFeatureVector = ""}
fromByteString :: ByteString -> FeatureVector Source #
Wrap a ByteString as a FeatureVector.
set :: BitIndex -> FeatureVector -> FeatureVector Source #
Set a bit in the feature vector.
>>>set (bitIndex 0) emptyFeatureVector {unFeatureVector = "\SOH"}>>>set (bitIndex 8) emptyFeatureVector {unFeatureVector = "\SOH\NUL"}
clear :: BitIndex -> FeatureVector -> FeatureVector Source #
Clear a bit in the feature vector.
member :: BitIndex -> FeatureVector -> Bool Source #
Test if a bit is set in the feature vector.
>>>member (bitIndex 0) (set (bitIndex 0) empty)True>>>member (bitIndex 1) (set (bitIndex 0) empty)False
Known features
The BOLT #9 feature table and lookup functions.
A known feature from the BOLT #9 specification.
Constructors
| Feature | |
Fields
| |
Instances
| NFData Feature Source # | |||||
Defined in Lightning.Protocol.BOLT9.Features | |||||
| Generic Feature Source # | |||||
Defined in Lightning.Protocol.BOLT9.Features Associated Types
| |||||
| Show Feature Source # | |||||
| Eq Feature Source # | |||||
| type Rep Feature Source # | |||||
Defined in Lightning.Protocol.BOLT9.Features type Rep Feature = D1 ('MetaData "Feature" "Lightning.Protocol.BOLT9.Features" "ppad-bolt9-0.0.1-SCTy7SY2nBJMXEGG76XgS" 'False) (C1 ('MetaCons "Feature" 'PrefixI 'True) ((S1 ('MetaSel ('Just "featureName") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 String) :*: S1 ('MetaSel ('Just "featureBaseBit") 'SourceUnpack 'SourceStrict 'DecidedStrict) (Rec0 Word16)) :*: (S1 ('MetaSel ('Just "featureContexts") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 [Context]) :*: (S1 ('MetaSel ('Just "featureDependencies") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 [String]) :*: S1 ('MetaSel ('Just "featureAssumed") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Bool))))) | |||||
featureByBit :: Word16 -> Maybe Feature Source #
Look up a feature by bit number.
Accepts either the even (compulsory) or odd (optional) bit of the pair.
>>>fmap featureName (featureByBit 16)Just "basic_mpp">>>fmap featureName (featureByBit 17) -- odd bit also worksJust "basic_mpp">>>featureByBit 999Nothing
featureByName :: String -> Maybe Feature Source #
Look up a feature by its canonical name.
>>>fmap featureBaseBit (featureByName "basic_mpp")Just 16>>>featureByName "nonexistent"Nothing
knownFeatures :: [Feature] Source #
The complete table of known features from BOLT #9.
Parsing and rendering
Wire format conversion.
parse :: ByteString -> FeatureVector Source #
Parse a ByteString into a FeatureVector.
Alias for fromByteString.
render :: FeatureVector -> ByteString Source #
Render a FeatureVector to a ByteString, trimming leading zero bytes for compact encoding.
Low-level bit operations
Direct bit manipulation by index.
setBit :: Word16 -> FeatureVector -> FeatureVector Source #
Set a bit by raw index.
>>>setBit 17 emptyFeatureVector {unFeatureVector = "\STX"}
clearBit :: Word16 -> FeatureVector -> FeatureVector Source #
Clear a bit by raw index.
>>>clearBit 17 (setBit 17 empty)FeatureVector {unFeatureVector = ""}
testBit :: Word16 -> FeatureVector -> Bool Source #
Test if a bit is set.
>>>testBit 17 (setBit 17 empty)True>>>testBit 16 (setBit 17 empty)False
Feature operations
High-level operations using Feature values.
setFeature :: Feature -> FeatureLevel -> FeatureVector -> FeatureVector Source #
Set a feature's bit at the given level.
Required sets the even bit, Optional sets the odd bit.
>>>import Data.Maybe (fromJust)>>>let mpp = fromJust (featureByName "basic_mpp")>>>setFeature mpp Optional empty -- set optional bit (17)FeatureVector {unFeatureVector = "\STX"}>>>setFeature mpp Required empty -- set required bit (16)FeatureVector {unFeatureVector = "\SOH"}
hasFeature :: Feature -> FeatureVector -> Maybe FeatureLevel Source #
Check if a feature is set in the vector.
Returns:
Just Requiredif the required (even) bit is setJust Optionalif the optional (odd) bit is set (and required is not)Nothingif neither bit is set
>>>import Data.Maybe (fromJust)>>>let mpp = fromJust (featureByName "basic_mpp")>>>hasFeature mpp (setFeature mpp Optional empty)Just Optional>>>hasFeature mpp (setFeature mpp Required empty)Just Required>>>hasFeature mpp emptyNothing
isFeatureSet :: Feature -> FeatureVector -> Bool Source #
Check if either bit of a feature is set in the vector.
>>>import Data.Maybe (fromJust)>>>let mpp = fromJust (featureByName "basic_mpp")>>>isFeatureSet mpp (setFeature mpp Optional empty)True>>>isFeatureSet mpp emptyFalse
listFeatures :: FeatureVector -> [(Feature, FeatureLevel)] Source #
List all known features that are set in the vector.
Returns pairs of (Feature, FeatureLevel) indicating whether each feature is set as required or optional.
>>>import Data.Maybe (fromJust)>>>let mpp = fromJust (featureByName "basic_mpp")>>>let ps = fromJust (featureByName "payment_secret")>>>let fv = setFeature mpp Optional (setFeature ps Required empty)>>>map (\(f, l) -> (featureName f, l)) (listFeatures fv)[("payment_secret",Required),("basic_mpp",Optional)]
Validation
Validate feature vectors for correctness.
data ValidationError Source #
Validation errors for feature vectors.
Constructors
| BothBitsSet !Word16 !String | Both optional and required bits are set for a feature. Arguments: base bit index, feature name. |
| MissingDependency !String !String | A feature's dependency is not set. Arguments: feature name, missing dependency name. |
| ContextNotAllowed !String !Context | A feature is not allowed in the given context. Arguments: feature name, context. |
| UnknownRequiredBit !Word16 | An unknown required (even) bit is set (remote validation only). Argument: bit index. |
| InvalidParity !Word16 !Context | A bit has invalid parity for a channel context. Arguments: bit index, context (ChanAnnOdd or ChanAnnEven). |
Instances
| NFData ValidationError Source # | |||||
Defined in Lightning.Protocol.BOLT9.Validate Methods rnf :: ValidationError -> () # | |||||
| Generic ValidationError Source # | |||||
Defined in Lightning.Protocol.BOLT9.Validate Associated Types
Methods from :: ValidationError -> Rep ValidationError x # to :: Rep ValidationError x -> ValidationError # | |||||
| Show ValidationError Source # | |||||
Defined in Lightning.Protocol.BOLT9.Validate Methods showsPrec :: Int -> ValidationError -> ShowS # show :: ValidationError -> String # showList :: [ValidationError] -> ShowS # | |||||
| Eq ValidationError Source # | |||||
Defined in Lightning.Protocol.BOLT9.Validate Methods (==) :: ValidationError -> ValidationError -> Bool # (/=) :: ValidationError -> ValidationError -> Bool # | |||||
| type Rep ValidationError Source # | |||||
Defined in Lightning.Protocol.BOLT9.Validate type Rep ValidationError = D1 ('MetaData "ValidationError" "Lightning.Protocol.BOLT9.Validate" "ppad-bolt9-0.0.1-SCTy7SY2nBJMXEGG76XgS" 'False) ((C1 ('MetaCons "BothBitsSet" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'SourceUnpack 'SourceStrict 'DecidedStrict) (Rec0 Word16) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 String)) :+: C1 ('MetaCons "MissingDependency" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 String) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 String))) :+: (C1 ('MetaCons "ContextNotAllowed" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 String) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Context)) :+: (C1 ('MetaCons "UnknownRequiredBit" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'SourceUnpack 'SourceStrict 'DecidedStrict) (Rec0 Word16)) :+: C1 ('MetaCons "InvalidParity" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'SourceUnpack 'SourceStrict 'DecidedStrict) (Rec0 Word16) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Context))))) | |||||
validateLocal :: Context -> FeatureVector -> Either [ValidationError] () Source #
Validate a feature vector for local use (vectors we create/send).
Checks:
- No feature has both optional and required bits set
- All set features are valid for the given context
- All dependencies of set features are also set
- C- context forces odd bits only, C+ forces even bits only
>>>import Data.Maybe (fromJust)>>>import Lightning.Protocol.BOLT9.Codec (setFeature)>>>let mpp = fromJust (featureByName "basic_mpp")>>>let ps = fromJust (featureByName "payment_secret")>>>validateLocal Init (setFeature mpp False empty)Left [MissingDependency "basic_mpp" "payment_secret"]>>>validateLocal Init (setFeature mpp False (setFeature ps False empty))Right ()
validateRemote :: Context -> FeatureVector -> Either [ValidationError] () Source #
Validate a feature vector received from a remote peer.
Checks:
- Unknown odd (optional) bits are acceptable (ignored)
- Unknown even (required) bits are errors
- If both bits of a pair are set, treat as required (not an error)
- Context restrictions still apply for known features
>>>import Lightning.Protocol.BOLT9.Codec (setBit)>>>validateRemote Init (setBit 999 empty) -- unknown odd bit: okRight ()>>>validateRemote Init (setBit 998 empty) -- unknown even bit: errorLeft [UnknownRequiredBit 998]
highestSetBit :: FeatureVector -> Maybe Word16 Source #
Find the highest set bit in a feature vector.
Returns Nothing if the vector is empty or has no bits set.
setBits :: FeatureVector -> [Word16] Source #
Collect all set bits in a feature vector.
Returns a list of bit indices in ascending order.