ppad-bolt9-0.0.1: Feature flags per BOLT #9
Copyright(c) 2025 Jared Tobin
LicenseMIT
MaintainerJared Tobin <jared@ppad.tech>
Safe HaskellSafe-Inferred
LanguageHaskell2010

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 fv
Just Optional

Validate a feature vector for a specific context:

>>> validateLocal Init fv
Left [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

Context

Contexts specify where feature flags appear in the protocol.

data Context Source #

Presentation context for feature flags.

Per BOLT #9, features are presented in different message contexts:

  • Init - the init message
  • NodeAnn - node_announcement messages
  • ChanAnn - channel_announcement messages (normal)
  • ChanAnnOdd - channel_announcement, always odd (optional)
  • ChanAnnEven - channel_announcement, always even (required)
  • Invoice - BOLT 11 invoices
  • Blinded - allowed_features field of a blinded path
  • ChanType - channel_type field when opening channels

Constructors

Init

I: presented in the init message

NodeAnn

N: presented in node_announcement messages

ChanAnn

C: presented in channel_announcement message

ChanAnnOdd

C-: channel_announcement, always odd (optional)

ChanAnnEven

C+: channel_announcement, always even (required)

Invoice

9: presented in BOLT 11 invoices

Blinded

B: allowed_features field of a blinded path

ChanType

T: channel_type field when opening channels

Instances

Instances details
NFData Context Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Methods

rnf :: Context -> () #

Generic Context Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Associated Types

type Rep Context 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

type Rep Context = D1 ('MetaData "Context" "Lightning.Protocol.BOLT9.Types" "ppad-bolt9-0.0.1-SCTy7SY2nBJMXEGG76XgS" 'False) (((C1 ('MetaCons "Init" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "NodeAnn" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "ChanAnn" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "ChanAnnOdd" 'PrefixI 'False) (U1 :: Type -> Type))) :+: ((C1 ('MetaCons "ChanAnnEven" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Invoice" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "Blinded" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "ChanType" 'PrefixI 'False) (U1 :: Type -> Type))))

Methods

from :: Context -> Rep Context x #

to :: Rep Context x -> Context #

Show Context Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Eq Context Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Methods

(==) :: Context -> Context -> Bool #

(/=) :: Context -> Context -> Bool #

Ord Context Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

type Rep Context Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

type Rep Context = D1 ('MetaData "Context" "Lightning.Protocol.BOLT9.Types" "ppad-bolt9-0.0.1-SCTy7SY2nBJMXEGG76XgS" 'False) (((C1 ('MetaCons "Init" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "NodeAnn" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "ChanAnn" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "ChanAnnOdd" 'PrefixI 'False) (U1 :: Type -> Type))) :+: ((C1 ('MetaCons "ChanAnnEven" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Invoice" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "Blinded" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "ChanType" 'PrefixI 'False) (U1 :: Type -> Type))))

isChannelContext :: Context -> Bool Source #

Check if a context is a channel announcement context (C, C-, or C+).

channelParity :: Context -> Maybe Bool Source #

For channel contexts with forced parity, return Just the required parity: True for even (C+), False for odd (C-). Returns Nothing for contexts without forced parity.

Bit indices

Low-level bit index types for direct bit manipulation.

data BitIndex Source #

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

Instances details
NFData BitIndex Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Methods

rnf :: BitIndex -> () #

Generic BitIndex Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Associated Types

type Rep BitIndex 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

type Rep BitIndex = D1 ('MetaData "BitIndex" "Lightning.Protocol.BOLT9.Types" "ppad-bolt9-0.0.1-SCTy7SY2nBJMXEGG76XgS" 'True) (C1 ('MetaCons "BitIndex" 'PrefixI 'True) (S1 ('MetaSel ('Just "unBitIndex") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Word16)))

Methods

from :: BitIndex -> Rep BitIndex x #

to :: Rep BitIndex x -> BitIndex #

Show BitIndex Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Eq BitIndex Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Ord BitIndex Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

type Rep BitIndex Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

type Rep BitIndex = D1 ('MetaData "BitIndex" "Lightning.Protocol.BOLT9.Types" "ppad-bolt9-0.0.1-SCTy7SY2nBJMXEGG76XgS" 'True) (C1 ('MetaCons "BitIndex" 'PrefixI 'True) (S1 ('MetaSel ('Just "unBitIndex") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Word16)))

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

Instances details
NFData FeatureLevel Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Methods

rnf :: FeatureLevel -> () #

Generic FeatureLevel Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Associated Types

type Rep FeatureLevel 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

type Rep FeatureLevel = D1 ('MetaData "FeatureLevel" "Lightning.Protocol.BOLT9.Types" "ppad-bolt9-0.0.1-SCTy7SY2nBJMXEGG76XgS" 'False) (C1 ('MetaCons "Required" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Optional" 'PrefixI 'False) (U1 :: Type -> Type))
Show FeatureLevel Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Eq FeatureLevel Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Ord FeatureLevel Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

type Rep FeatureLevel Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

type Rep FeatureLevel = D1 ('MetaData "FeatureLevel" "Lightning.Protocol.BOLT9.Types" "ppad-bolt9-0.0.1-SCTy7SY2nBJMXEGG76XgS" 'False) (C1 ('MetaCons "Required" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Optional" 'PrefixI 'False) (U1 :: Type -> Type))

Required/optional bits

Type-safe wrappers ensuring correct parity.

data RequiredBit Source #

A required (compulsory) feature bit. Required bits are always even.

Instances

Instances details
NFData RequiredBit Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Methods

rnf :: RequiredBit -> () #

Generic RequiredBit Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Associated Types

type Rep RequiredBit 
Instance details

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)))
Show RequiredBit Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Eq RequiredBit Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Ord RequiredBit Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

type Rep RequiredBit Source # 
Instance details

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 16
Just (RequiredBit {unRequiredBit = 16})
>>> requiredBit 17
Nothing

data OptionalBit Source #

An optional feature bit. Optional bits are always odd.

Instances

Instances details
NFData OptionalBit Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Methods

rnf :: OptionalBit -> () #

Generic OptionalBit Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Associated Types

type Rep OptionalBit 
Instance details

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)))
Show OptionalBit Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Eq OptionalBit Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Ord OptionalBit Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

type Rep OptionalBit Source # 
Instance details

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 17
Just (OptionalBit {unOptionalBit = 17})
>>> optionalBit 16
Nothing

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

Instances details
NFData FeatureVector Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Methods

rnf :: FeatureVector -> () #

Generic FeatureVector Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Associated Types

type Rep FeatureVector 
Instance details

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)))
Show FeatureVector Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Eq FeatureVector Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

Ord FeatureVector Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Types

type Rep FeatureVector Source # 
Instance details

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).

>>> empty
FeatureVector {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) empty
FeatureVector {unFeatureVector = "\SOH"}
>>> set (bitIndex 8) empty
FeatureVector {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.

data Feature Source #

A known feature from the BOLT #9 specification.

Constructors

Feature 

Fields

Instances

Instances details
NFData Feature Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Features

Methods

rnf :: Feature -> () #

Generic Feature Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Features

Associated Types

type Rep Feature 
Instance details

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)))))

Methods

from :: Feature -> Rep Feature x #

to :: Rep Feature x -> Feature #

Show Feature Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Features

Eq Feature Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Features

Methods

(==) :: Feature -> Feature -> Bool #

(/=) :: Feature -> Feature -> Bool #

type Rep Feature Source # 
Instance details

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 works
Just "basic_mpp"
>>> featureByBit 999
Nothing

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 empty
FeatureVector {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 Required if the required (even) bit is set
  • Just Optional if the optional (odd) bit is set (and required is not)
  • Nothing if 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 empty
Nothing

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 empty
False

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

Instances details
NFData ValidationError Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Validate

Methods

rnf :: ValidationError -> () #

Generic ValidationError Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Validate

Show ValidationError Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Validate

Eq ValidationError Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Validate

type Rep ValidationError Source # 
Instance details

Defined in Lightning.Protocol.BOLT9.Validate

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: ok
Right ()
>>> validateRemote Init (setBit 998 empty)  -- unknown even bit: error
Left [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.