bolt9

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

BOLT9.hs (24124B)


      1 {-# OPTIONS_HADDOCK prune #-}
      2 {-# LANGUAGE BangPatterns #-}
      3 {-# LANGUAGE DeriveGeneric #-}
      4 
      5 -- |
      6 -- Module: Lightning.Protocol.BOLT9
      7 -- Copyright: (c) 2025 Jared Tobin
      8 -- License: MIT
      9 -- Maintainer: Jared Tobin <jared@ppad.tech>
     10 --
     11 -- Feature flags for the Lightning Network, per
     12 -- [BOLT #9](https://github.com/lightning/bolts/blob/master/09-features.md).
     13 --
     14 -- A feature vector is a big-endian bit field. Features are assigned
     15 -- pairs of bits: setting the even bit means the feature is required,
     16 -- setting the odd bit means it is optional (/it's ok to be odd/).
     17 --
     18 -- The examples below assume:
     19 --
     20 -- >>> :set -XOverloadedStrings
     21 -- >>> import Lightning.Protocol.BOLT9
     22 --
     23 -- Build a vector, check it before sending it, and render it:
     24 --
     25 -- >>> let fv = set_feature_with_deps OptionZeroconf Optional empty
     26 -- >>> list_features fv
     27 -- [(OptionScidAlias,Optional),(OptionZeroconf,Optional)]
     28 -- >>> validate_local InitContext fv
     29 -- Right ()
     30 -- >>> render fv
     31 -- "\b\128\NUL\NUL\NUL\NUL\NUL"
     32 --
     33 -- Check a vector received from a peer:
     34 --
     35 -- >>> validate_remote InitContext (parse "\DLE\NUL\NUL")
     36 -- Left (UnknownBit 20 :| [])
     37 -- >>> validate_remote InitContext (parse "\STX\NUL\NUL")
     38 -- Right ()
     39 
     40 module Lightning.Protocol.BOLT9 (
     41   -- * Feature vectors
     42     FeatureVector
     43   , parse
     44   , render
     45   , empty
     46   , union
     47 
     48   -- * Bits
     49   , set_bit
     50   , clear_bit
     51   , test_bit
     52   , set_bits
     53 
     54   -- * Known features
     55   , Feature(..)
     56   , known_features
     57   , feature_by_bit
     58   , feature_bit
     59   , feature_name
     60   , feature_contexts
     61   , feature_dependencies
     62   , feature_assumed
     63 
     64   -- * Feature operations
     65   , FeatureLevel(..)
     66   , set_feature
     67   , set_feature_with_deps
     68   , clear_feature
     69   , test_feature
     70   , list_features
     71 
     72   -- * Validation
     73   , Context(..)
     74   , ValidationError(..)
     75   , validate_local
     76   , validate_remote
     77 
     78   -- * Channel types
     79   , ChannelType(..)
     80   , BasicChannelType(..)
     81   , channel_type
     82   , channel_type_features
     83   ) where
     84 
     85 import Control.DeepSeq (NFData(..))
     86 import qualified Data.Bits as B
     87 import Data.ByteString (ByteString)
     88 import qualified Data.ByteString as BS
     89 import Data.List (find)
     90 import Data.List.NonEmpty (NonEmpty(..))
     91 import Data.Maybe (isNothing)
     92 import Data.Word (Word8)
     93 import GHC.Generics (Generic)
     94 
     95 -- feature vectors -----------------------------------------------------------
     96 
     97 -- | A feature vector.
     98 --
     99 --   Bit 0 is the least significant bit of the last byte. A vector
    100 --   produced by 'parse' keeps its bytes exactly, so 'render' gives
    101 --   them back unchanged (signatures over gossip messages cover them).
    102 --   Every other operation produces a minimally-encoded vector, i.e.
    103 --   one without leading zero bytes.
    104 --
    105 --   Equality ignores leading zero bytes.
    106 --
    107 --   >>> parse "\NUL\STX" == parse "\STX"
    108 --   True
    109 --   >>> set_bit 1 empty
    110 --   parse "\STX"
    111 newtype FeatureVector = FeatureVector ByteString
    112 
    113 instance Eq FeatureVector where
    114   FeatureVector a == FeatureVector b = strip a == strip b
    115 
    116 instance Show FeatureVector where
    117   showsPrec d (FeatureVector bs) = showParen (d > 10) $
    118     showString "parse " . showsPrec 11 bs
    119 
    120 instance NFData FeatureVector where
    121   rnf (FeatureVector bs) = rnf bs
    122 
    123 -- | Parse a feature vector from its wire bytes. Every byte string is a
    124 --   valid feature vector.
    125 --
    126 --   >>> test_bit 9 (parse "\STX\NUL")
    127 --   True
    128 parse :: ByteString -> FeatureVector
    129 parse = FeatureVector
    130 {-# INLINE parse #-}
    131 
    132 -- | The wire bytes of a feature vector: the original bytes of a vector
    133 --   produced by 'parse', and the minimal encoding of any other.
    134 --
    135 --   >>> render (parse "\NUL\STX")
    136 --   "\NUL\STX"
    137 --   >>> render (union (parse "\NUL\STX") empty)
    138 --   "\STX"
    139 render :: FeatureVector -> ByteString
    140 render (FeatureVector bs) = bs
    141 {-# INLINE render #-}
    142 
    143 -- | The empty feature vector.
    144 --
    145 --   >>> render empty
    146 --   ""
    147 empty :: FeatureVector
    148 empty = FeatureVector BS.empty
    149 
    150 -- | The bitwise OR of two feature vectors.
    151 --
    152 --   BOLT #1 requires the receiver of an @init@ message to combine its
    153 --   @globalfeatures@ and @features@ fields this way.
    154 --
    155 --   >>> set_bits (union (parse "\STX") (parse "\SOH\NUL"))
    156 --   [1,8]
    157 union :: FeatureVector -> FeatureVector -> FeatureVector
    158 union (FeatureVector a) (FeatureVector b) =
    159   FeatureVector (combine (B..|.) a b)
    160 
    161 -- bits ----------------------------------------------------------------------
    162 
    163 -- | Set the bit at the given index. Negative indices are ignored.
    164 --
    165 --   >>> render (set_bit 9 empty)
    166 --   "\STX\NUL"
    167 set_bit :: Int -> FeatureVector -> FeatureVector
    168 set_bit !i (FeatureVector bs)
    169   | i < 0     = FeatureVector (strip bs)
    170   | otherwise = FeatureVector (combine (B..|.) bs (single i))
    171 
    172 -- | Clear the bit at the given index. Negative indices are ignored.
    173 --
    174 --   >>> render (clear_bit 9 (parse "\STX\SOH"))
    175 --   "\SOH"
    176 clear_bit :: Int -> FeatureVector -> FeatureVector
    177 clear_bit !i (FeatureVector bs)
    178   | i < 0 || i `quot` 8 >= BS.length s = FeatureVector s
    179   | otherwise = FeatureVector (combine clr s (single i))
    180   where
    181     s = strip bs
    182     clr x y = x B..&. B.complement y
    183 
    184 -- | Test the bit at the given index. Negative indices are never set.
    185 --
    186 --   >>> test_bit 9 (parse "\STX\NUL")
    187 --   True
    188 --   >>> test_bit 8 (parse "\STX\NUL")
    189 --   False
    190 test_bit :: Int -> FeatureVector -> Bool
    191 test_bit !i (FeatureVector bs)
    192   | i < 0 || q >= len = False
    193   | otherwise         = B.testBit (BS.index bs (len - 1 - q)) r
    194   where
    195     len    = BS.length bs
    196     (q, r) = i `quotRem` 8
    197 
    198 -- | The indices of all set bits, in ascending order.
    199 --
    200 --   >>> set_bits (parse "\STX\NUL\SOH")
    201 --   [0,17]
    202 set_bits :: FeatureVector -> [Int]
    203 set_bits (FeatureVector bs) = go 0
    204   where
    205     !len = BS.length bs
    206     go !q
    207       | q >= len  = []
    208       | otherwise =
    209           let !w = BS.index bs (len - 1 - q)
    210           in  [q * 8 + r | r <- [0 .. 7], B.testBit w r] ++ go (q + 1)
    211 
    212 -- Drop leading zero bytes.
    213 strip :: ByteString -> ByteString
    214 strip = BS.dropWhile (== 0)
    215 {-# INLINE strip #-}
    216 
    217 -- The minimal encoding of a vector with only bit i set (i >= 0).
    218 single :: Int -> ByteString
    219 single i = BS.cons (B.bit r) (BS.replicate q 0)
    220   where
    221     (q, r) = i `quotRem` 8
    222 
    223 -- Combine two encodings bytewise, aligned at their last bytes (the
    224 -- shorter one padded with leading zeros), and strip the result.
    225 combine
    226   :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -> ByteString
    227 combine f a b = strip (fst (BS.unfoldrN n step 0))
    228   where
    229     !la = BS.length a
    230     !lb = BS.length b
    231     !n  = max la lb
    232     byte s ls k
    233       | k < n - ls = 0
    234       | otherwise  = BS.index s (k - n + ls)
    235     step !k = Just (f (byte a la k) (byte b lb k), k + 1)
    236 
    237 -- known features ------------------------------------------------------------
    238 
    239 -- | The features assigned in the BOLT #9 table.
    240 data Feature
    241   = OptionDataLossProtect           -- ^ 0/1 @option_data_loss_protect@
    242   | OptionUpfrontShutdownScript     -- ^ 4/5 @option_upfront_shutdown_script@
    243   | GossipQueries                   -- ^ 6/7 @gossip_queries@
    244   | VarOnionOptin                   -- ^ 8/9 @var_onion_optin@
    245   | GossipQueriesEx                 -- ^ 10/11 @gossip_queries_ex@
    246   | OptionStaticRemotekey           -- ^ 12/13 @option_static_remotekey@
    247   | PaymentSecret                   -- ^ 14/15 @payment_secret@
    248   | BasicMpp                        -- ^ 16/17 @basic_mpp@
    249   | OptionSupportLargeChannel       -- ^ 18/19 @option_support_large_channel@
    250   | OptionAnchors                   -- ^ 22/23 @option_anchors@
    251   | OptionRouteBlinding             -- ^ 24/25 @option_route_blinding@
    252   | OptionShutdownAnysegwit         -- ^ 26/27 @option_shutdown_anysegwit@
    253   | OptionDualFund                  -- ^ 28/29 @option_dual_fund@
    254   | OptionQuiesce                   -- ^ 34/35 @option_quiesce@
    255   | OptionAttributionData           -- ^ 36/37 @option_attribution_data@
    256   | OptionOnionMessages             -- ^ 38/39 @option_onion_messages@
    257   | ZeroFeeCommitments              -- ^ 40/41 @zero_fee_commitments@
    258   | OptionProvideStorage            -- ^ 42/43 @option_provide_storage@
    259   | OptionChannelType               -- ^ 44/45 @option_channel_type@
    260   | OptionScidAlias                 -- ^ 46/47 @option_scid_alias@
    261   | OptionPaymentMetadata           -- ^ 48/49 @option_payment_metadata@
    262   | OptionZeroconf                  -- ^ 50/51 @option_zeroconf@
    263   | OptionSimpleClose               -- ^ 60/61 @option_simple_close@
    264   | OptionSplice                    -- ^ 62/63 @option_splice@
    265   | OptionOnionMessagesOnlyChannels
    266     -- ^ 66/67 @option_onion_messages_only_channels@
    267   deriving (Eq, Ord, Show, Generic)
    268 
    269 instance NFData Feature
    270 
    271 -- | All known features, in bit order.
    272 --
    273 --   >>> length known_features
    274 --   25
    275 known_features :: [Feature]
    276 known_features = [
    277     OptionDataLossProtect
    278   , OptionUpfrontShutdownScript
    279   , GossipQueries
    280   , VarOnionOptin
    281   , GossipQueriesEx
    282   , OptionStaticRemotekey
    283   , PaymentSecret
    284   , BasicMpp
    285   , OptionSupportLargeChannel
    286   , OptionAnchors
    287   , OptionRouteBlinding
    288   , OptionShutdownAnysegwit
    289   , OptionDualFund
    290   , OptionQuiesce
    291   , OptionAttributionData
    292   , OptionOnionMessages
    293   , ZeroFeeCommitments
    294   , OptionProvideStorage
    295   , OptionChannelType
    296   , OptionScidAlias
    297   , OptionPaymentMetadata
    298   , OptionZeroconf
    299   , OptionSimpleClose
    300   , OptionSplice
    301   , OptionOnionMessagesOnlyChannels
    302   ]
    303 
    304 -- A row of the BOLT #9 table.
    305 data Entry = Entry {
    306     e_bit      :: !Int
    307   , e_name     :: !String
    308   , e_contexts :: ![Context]
    309   , e_deps     :: ![Feature]
    310   , e_assumed  :: !Bool
    311   }
    312 
    313 entry :: Feature -> Entry
    314 entry f = case f of
    315   OptionDataLossProtect ->
    316     Entry 0 "option_data_loss_protect" [] [] True
    317   OptionUpfrontShutdownScript ->
    318     Entry 4 "option_upfront_shutdown_script" _IN [] False
    319   GossipQueries ->
    320     Entry 6 "gossip_queries" [] [] False
    321   VarOnionOptin ->
    322     Entry 8 "var_onion_optin" [] [] True
    323   GossipQueriesEx ->
    324     Entry 10 "gossip_queries_ex" _IN [] False
    325   OptionStaticRemotekey ->
    326     Entry 12 "option_static_remotekey" [] [] True
    327   PaymentSecret ->
    328     Entry 14 "payment_secret" [] [] True
    329   BasicMpp ->
    330     Entry 16 "basic_mpp" _IN9 [PaymentSecret] False
    331   OptionSupportLargeChannel ->
    332     Entry 18 "option_support_large_channel" _IN [] False
    333   OptionAnchors ->
    334     Entry 22 "option_anchors" _INT [] False
    335   OptionRouteBlinding ->
    336     Entry 24 "option_route_blinding" _IN9 [] False
    337   OptionShutdownAnysegwit ->
    338     Entry 26 "option_shutdown_anysegwit" _IN [] False
    339   OptionDualFund ->
    340     Entry 28 "option_dual_fund" _IN [] False
    341   OptionQuiesce ->
    342     Entry 34 "option_quiesce" _IN [] False
    343   OptionAttributionData ->
    344     Entry 36 "option_attribution_data" _IN9 [] False
    345   OptionOnionMessages ->
    346     Entry 38 "option_onion_messages" _IN [] False
    347   ZeroFeeCommitments ->
    348     Entry 40 "zero_fee_commitments" _IN [OptionChannelType] False
    349   OptionProvideStorage ->
    350     Entry 42 "option_provide_storage" _IN [] False
    351   OptionChannelType ->
    352     Entry 44 "option_channel_type" [] [] True
    353   OptionScidAlias ->
    354     Entry 46 "option_scid_alias" _INT [] False
    355   OptionPaymentMetadata ->
    356     Entry 48 "option_payment_metadata" [InvoiceContext] [] False
    357   OptionZeroconf ->
    358     Entry 50 "option_zeroconf" _INT [OptionScidAlias] False
    359   OptionSimpleClose ->
    360     Entry 60 "option_simple_close" _IN [OptionShutdownAnysegwit] False
    361   OptionSplice ->
    362     Entry 62 "option_splice" _IN [] False
    363   OptionOnionMessagesOnlyChannels ->
    364     Entry 66 "option_onion_messages_only_channels" _IN
    365       [OptionOnionMessages] False
    366   where
    367     _IN  = [InitContext, NodeContext]
    368     _IN9 = [InitContext, NodeContext, InvoiceContext]
    369     _INT = [InitContext, NodeContext, ChannelTypeContext]
    370 
    371 -- | The feature that a bit (even or odd) belongs to, if any.
    372 --
    373 --   >>> feature_by_bit 16
    374 --   Just BasicMpp
    375 --   >>> feature_by_bit 17
    376 --   Just BasicMpp
    377 --   >>> feature_by_bit 20
    378 --   Nothing
    379 feature_by_bit :: Int -> Maybe Feature
    380 feature_by_bit !i
    381   | i < 0 || i > max_known_bit = Nothing
    382   | otherwise = find ((== base) . feature_bit) known_features
    383   where
    384     base = i - i `rem` 2
    385 
    386 -- The highest bit assigned to any known feature.
    387 max_known_bit :: Int
    388 max_known_bit = foldr (max . (+ 1) . feature_bit) 0 known_features
    389 
    390 -- | A feature's even (required) bit. Its odd (optional) bit is the
    391 --   next one up.
    392 --
    393 --   >>> feature_bit BasicMpp
    394 --   16
    395 feature_bit :: Feature -> Int
    396 feature_bit = e_bit . entry
    397 
    398 -- | A feature's name in the BOLT #9 table.
    399 --
    400 --   >>> feature_name BasicMpp
    401 --   "basic_mpp"
    402 feature_name :: Feature -> String
    403 feature_name = e_name . entry
    404 
    405 -- | The contexts the BOLT #9 table lists for a feature, in table order.
    406 --   The list is empty for ASSUMED features and for 'GossipQueries'.
    407 --
    408 --   >>> feature_contexts BasicMpp
    409 --   [InitContext,NodeContext,InvoiceContext]
    410 --   >>> feature_contexts PaymentSecret
    411 --   []
    412 feature_contexts :: Feature -> [Context]
    413 feature_contexts = e_contexts . entry
    414 
    415 -- | A feature's direct dependencies.
    416 --
    417 --   >>> feature_dependencies OptionZeroconf
    418 --   [OptionScidAlias]
    419 feature_dependencies :: Feature -> [Feature]
    420 feature_dependencies = e_deps . entry
    421 
    422 -- | Whether BOLT #9 marks a feature ASSUMED, i.e. supported by all
    423 --   nodes.
    424 --
    425 --   >>> feature_assumed PaymentSecret
    426 --   True
    427 feature_assumed :: Feature -> Bool
    428 feature_assumed = e_assumed . entry
    429 
    430 -- feature operations --------------------------------------------------------
    431 
    432 -- | The level at which a feature is set.
    433 data FeatureLevel
    434   = Required  -- ^ the even bit is set
    435   | Optional  -- ^ the odd bit is set
    436   deriving (Eq, Ord, Show, Generic)
    437 
    438 instance NFData FeatureLevel
    439 
    440 level_bit :: Feature -> FeatureLevel -> Int
    441 level_bit f Required = feature_bit f
    442 level_bit f Optional = feature_bit f + 1
    443 {-# INLINE level_bit #-}
    444 
    445 -- | Set a feature at the given level, clearing the other bit of its
    446 --   pair.
    447 --
    448 --   >>> set_bits (set_feature BasicMpp Optional empty)
    449 --   [17]
    450 --   >>> set_bits (set_feature BasicMpp Required (set_bit 17 empty))
    451 --   [16]
    452 set_feature :: Feature -> FeatureLevel -> FeatureVector -> FeatureVector
    453 set_feature f l = set_bit (level_bit f l) . clear_bit (level_bit f other)
    454   where
    455     other = case l of
    456       Required -> Optional
    457       Optional -> Required
    458 
    459 -- | Set a feature at the given level, together with its transitive
    460 --   dependencies (ASSUMED ones included). Dependencies that are not
    461 --   yet set are set at the same level; those already set keep theirs.
    462 --
    463 --   >>> list_features (set_feature_with_deps BasicMpp Optional empty)
    464 --   [(PaymentSecret,Optional),(BasicMpp,Optional)]
    465 set_feature_with_deps
    466   :: Feature -> FeatureLevel -> FeatureVector -> FeatureVector
    467 set_feature_with_deps f l fv =
    468     foldr ensure (set_feature f l fv) (feature_dependencies f)
    469   where
    470     ensure d acc =
    471       let acc' = case test_feature d acc of
    472             Just _  -> acc
    473             Nothing -> set_feature d l acc
    474       in  foldr ensure acc' (feature_dependencies d)
    475 
    476 -- | Clear both bits of a feature.
    477 --
    478 --   >>> clear_feature BasicMpp (set_feature BasicMpp Optional empty)
    479 --   parse ""
    480 clear_feature :: Feature -> FeatureVector -> FeatureVector
    481 clear_feature f =
    482   clear_bit (level_bit f Required) . clear_bit (level_bit f Optional)
    483 
    484 -- | The level at which a feature is set, if it is.
    485 --
    486 --   A feature with both bits set is 'Required', as BOLT #9 directs the
    487 --   receiver to treat it.
    488 --
    489 --   >>> test_feature BasicMpp (set_bit 17 empty)
    490 --   Just Optional
    491 --   >>> test_feature BasicMpp (set_bit 16 (set_bit 17 empty))
    492 --   Just Required
    493 --   >>> test_feature BasicMpp empty
    494 --   Nothing
    495 test_feature :: Feature -> FeatureVector -> Maybe FeatureLevel
    496 test_feature f fv
    497   | test_bit (level_bit f Required) fv = Just Required
    498   | test_bit (level_bit f Optional) fv = Just Optional
    499   | otherwise                          = Nothing
    500 
    501 -- | The known features set in a vector, in bit order.
    502 --
    503 --   >>> list_features (parse "\SOH\128\NUL")
    504 --   [(PaymentSecret,Optional),(BasicMpp,Required)]
    505 list_features :: FeatureVector -> [(Feature, FeatureLevel)]
    506 list_features fv =
    507   [(f, l) | f <- known_features, Just l <- [test_feature f fv]]
    508 
    509 -- validation ----------------------------------------------------------------
    510 
    511 -- | A field in which feature bits are presented: the values of the
    512 --   Context column of the BOLT #9 table.
    513 --
    514 --   The table's @C-@ and @C+@ are not further contexts. They mark a
    515 --   feature presented in @channel_announcement@ as always optional or
    516 --   always required. No feature at the implemented spec revision is
    517 --   presented in @channel_announcement@ in any form.
    518 data Context
    519   = InitContext         -- ^ @I@: the @init@ message
    520   | NodeContext         -- ^ @N@: @node_announcement@
    521   | ChannelContext      -- ^ @C@: @channel_announcement@
    522   | InvoiceContext      -- ^ @9@: BOLT #11 invoices
    523   | BlindedContext      -- ^ @B@: @allowed_features@ of a blinded path
    524   | ChannelTypeContext  -- ^ @T@: the @channel_type@ field
    525   deriving (Eq, Ord, Show, Generic)
    526 
    527 instance NFData Context
    528 
    529 -- | A rule a feature vector breaks.
    530 data ValidationError
    531   = UnknownBit {-# UNPACK #-} !Int
    532     -- ^ a bit belonging to no known feature is set
    533   | BothBitsSet !Feature
    534     -- ^ both bits of a feature are set
    535   | ContextNotAllowed !Feature !Context
    536     -- ^ a feature is set in a context that doesn't present it
    537   | MissingDependency !Feature !Feature
    538     -- ^ a set feature (first) lacks a dependency (second)
    539   | InvalidChannelType
    540     -- ^ a @channel_type@ is not a type that BOLT #2 defines
    541   deriving (Eq, Show, Generic)
    542 
    543 instance NFData ValidationError
    544 
    545 -- | Validate a feature vector that we're about to send in the given
    546 --   context, per the origin requirements of BOLT #9 and BOLT #1.
    547 --
    548 --   For 'ChannelTypeContext', the vector must be a channel type that
    549 --   BOLT #2 defines (see 'channel_type'). For every other context,
    550 --   checks that:
    551 --
    552 --   * no bit outside the known features is set;
    553 --   * no feature has both bits set;
    554 --   * each set feature is presented in the context. A feature with an
    555 --     empty Context column (the ASSUMED features and 'GossipQueries')
    556 --     is accepted in 'InitContext', 'NodeContext' and
    557 --     'InvoiceContext', where deployed nodes still present it;
    558 --   * each set feature's dependencies are set. A dependency on an
    559 --     ASSUMED feature counts as met even when its bits are clear.
    560 --
    561 --   Errors are reported in that order. No known feature is presented
    562 --   in 'ChannelContext' or 'BlindedContext', so only the empty vector
    563 --   passes there (as BOLT #4 requires of @allowed_features@).
    564 --
    565 --   >>> validate_local InitContext (set_feature OptionZeroconf Optional empty)
    566 --   Left (MissingDependency OptionZeroconf OptionScidAlias :| [])
    567 --   >>> validate_local InitContext (set_feature BasicMpp Optional empty)
    568 --   Right ()
    569 --   >>> validate_local InitContext (set_bit 101 empty)
    570 --   Left (UnknownBit 101 :| [])
    571 validate_local
    572   :: Context -> FeatureVector -> Either (NonEmpty ValidationError) ()
    573 validate_local ctx fv = to_either $ case ctx of
    574   ChannelTypeContext -> channel_type_errors fv
    575   _ ->  unknown_bits (const True) fv
    576      ++ both_bits_errors fv
    577      ++ context_errors ctx fv
    578      ++ dependency_errors fv
    579 
    580 -- | Validate a feature vector received in the given context, per the
    581 --   receiver requirements for that context:
    582 --
    583 --   * 'InitContext' (BOLT #1) and 'InvoiceContext' (BOLT #11): no
    584 --     unknown even bit is set, and each set feature's dependencies are
    585 --     set (ASSUMED dependencies count as met).
    586 --   * 'NodeContext' and 'ChannelContext' (BOLT #7): no unknown even
    587 --     bit is set. A failure here means the node or channel must not be
    588 --     routed through; the announcement itself is still valid.
    589 --   * 'BlindedContext' (BOLT #4): no unknown bit is set, odd or even.
    590 --   * 'ChannelTypeContext' (BOLT #2): the vector is a defined channel
    591 --     type (see 'channel_type').
    592 --
    593 --   Unknown odd bits are otherwise ignored. A feature with both bits
    594 --   set is not an error; it counts as 'Required' (see 'test_feature').
    595 --   Nor is a known feature outside its listed contexts, since that
    596 --   rule binds only the sender.
    597 --
    598 --   >>> validate_remote InitContext (set_bit 101 empty)
    599 --   Right ()
    600 --   >>> validate_remote InitContext (set_bit 100 empty)
    601 --   Left (UnknownBit 100 :| [])
    602 --   >>> validate_remote BlindedContext (set_bit 101 empty)
    603 --   Left (UnknownBit 101 :| [])
    604 validate_remote
    605   :: Context -> FeatureVector -> Either (NonEmpty ValidationError) ()
    606 validate_remote ctx fv = to_either $ case ctx of
    607   InitContext        -> unknown_even ++ dependency_errors fv
    608   NodeContext        -> unknown_even
    609   ChannelContext     -> unknown_even
    610   InvoiceContext     -> unknown_even ++ dependency_errors fv
    611   BlindedContext     -> unknown_bits (const True) fv
    612   ChannelTypeContext -> channel_type_errors fv
    613   where
    614     unknown_even = unknown_bits even fv
    615 
    616 to_either :: [e] -> Either (NonEmpty e) ()
    617 to_either []       = Right ()
    618 to_either (e : es) = Left (e :| es)
    619 
    620 -- Unknown set bits satisfying the predicate.
    621 unknown_bits :: (Int -> Bool) -> FeatureVector -> [ValidationError]
    622 unknown_bits p fv =
    623   [ UnknownBit i
    624   | i <- set_bits fv, p i, isNothing (feature_by_bit i) ]
    625 
    626 both_bits_errors :: FeatureVector -> [ValidationError]
    627 both_bits_errors fv =
    628   [ BothBitsSet f
    629   | f <- known_features
    630   , test_bit (level_bit f Required) fv
    631   , test_bit (level_bit f Optional) fv ]
    632 
    633 context_errors :: Context -> FeatureVector -> [ValidationError]
    634 context_errors ctx fv =
    635   [ ContextNotAllowed f ctx
    636   | (f, _) <- list_features fv, not (presented f) ]
    637   where
    638     presented f = case feature_contexts f of
    639       [] -> ctx `elem` [InitContext, NodeContext, InvoiceContext]
    640       cs -> ctx `elem` cs
    641 
    642 dependency_errors :: FeatureVector -> [ValidationError]
    643 dependency_errors fv =
    644   [ MissingDependency f d
    645   | (f, _) <- list_features fv
    646   , d <- feature_dependencies f
    647   , not (feature_assumed d)
    648   , isNothing (test_feature d fv) ]
    649 
    650 channel_type_errors :: FeatureVector -> [ValidationError]
    651 channel_type_errors fv = case channel_type fv of
    652   Nothing -> [InvalidChannelType]
    653   Just _  -> []
    654 
    655 -- channel types -------------------------------------------------------------
    656 
    657 -- | The basic channel types of BOLT #2.
    658 data BasicChannelType
    659   = BasicStaticRemotekey
    660     -- ^ 'OptionStaticRemotekey' (bit 12)
    661   | BasicAnchors
    662     -- ^ 'OptionAnchors' and 'OptionStaticRemotekey' (bits 22 and 12)
    663   | BasicZeroFeeCommitments
    664     -- ^ 'ZeroFeeCommitments' (bit 40)
    665   deriving (Eq, Ord, Show, Generic)
    666 
    667 instance NFData BasicChannelType
    668 
    669 -- | A channel type, per BOLT #2: a basic type plus any of the
    670 --   'OptionScidAlias' and 'OptionZeroconf' variations.
    671 --
    672 --   Channel types are an enumeration that reuses even feature bits;
    673 --   they aren't subject to the dependency or context rules for
    674 --   feature vectors. BOLT #2 also forbids 'OptionScidAlias' in the
    675 --   channel type of a channel to be announced, which needs the
    676 --   @announce_channel@ flag to check.
    677 data ChannelType = ChannelType {
    678     ct_basic      :: !BasicChannelType
    679   , ct_scid_alias :: !Bool
    680   , ct_zeroconf   :: !Bool
    681   }
    682   deriving (Eq, Show, Generic)
    683 
    684 instance NFData ChannelType
    685 
    686 -- | The channel type that a @channel_type@ vector encodes, if it is a
    687 --   defined one. Leading zero bytes are ignored.
    688 --
    689 --   >>> let zeroconf = ChannelType BasicStaticRemotekey False True
    690 --   >>> channel_type (parse "\EOT\NUL\NUL\NUL\NUL\DLE\NUL") == Just zeroconf
    691 --   True
    692 --   >>> channel_type (set_bit 13 empty)
    693 --   Nothing
    694 channel_type :: FeatureVector -> Maybe ChannelType
    695 channel_type fv = find ((== fv) . channel_type_features) channel_types
    696 
    697 -- All defined channel types.
    698 channel_types :: [ChannelType]
    699 channel_types =
    700   [ ChannelType b s z
    701   | b <- [BasicStaticRemotekey, BasicAnchors, BasicZeroFeeCommitments]
    702   , s <- [False, True]
    703   , z <- [False, True] ]
    704 
    705 -- | The @channel_type@ vector for a channel type.
    706 --
    707 --   >>> let anchors = ChannelType BasicAnchors False False
    708 --   >>> render (channel_type_features anchors)
    709 --   "@\DLE\NUL"
    710 channel_type_features :: ChannelType -> FeatureVector
    711 channel_type_features (ChannelType b s z) =
    712     foldr (\f -> set_feature f Required) empty
    713       (basic b ++ [OptionScidAlias | s] ++ [OptionZeroconf | z])
    714   where
    715     basic BasicStaticRemotekey    = [OptionStaticRemotekey]
    716     basic BasicAnchors            = [OptionAnchors, OptionStaticRemotekey]
    717     basic BasicZeroFeeCommitments = [ZeroFeeCommitments]