Features.hs (4222B)
1 {-# OPTIONS_HADDOCK prune #-} 2 {-# LANGUAGE BangPatterns #-} 3 {-# LANGUAGE DeriveGeneric #-} 4 5 -- | 6 -- Module: Lightning.Protocol.BOLT9.Features 7 -- Copyright: (c) 2025 Jared Tobin 8 -- License: MIT 9 -- Maintainer: Jared Tobin <jared@ppad.tech> 10 -- 11 -- Known feature table for the Lightning Network, per 12 -- [BOLT #9](https://github.com/lightning/bolts/blob/master/09-features.md). 13 14 module Lightning.Protocol.BOLT9.Features ( 15 -- * Feature 16 Feature(..) 17 18 -- * Lookup 19 , featureByBit 20 , featureByName 21 22 -- * Known features table 23 , knownFeatures 24 ) where 25 26 import Control.DeepSeq (NFData) 27 import Data.IntMap.Strict (IntMap) 28 import qualified Data.IntMap.Strict as IM 29 import Data.Map.Strict (Map) 30 import qualified Data.Map.Strict as M 31 import Data.Word (Word16) 32 import GHC.Generics (Generic) 33 import Lightning.Protocol.BOLT9.Types (Context(..)) 34 35 -- | A known feature from the BOLT #9 specification. 36 data Feature = Feature { 37 featureName :: !String 38 -- ^ The canonical name of the feature. 39 , featureBaseBit :: {-# UNPACK #-} !Word16 40 -- ^ The even (compulsory) bit number; the odd (optional) bit is 41 -- @baseBit + 1@. 42 , featureContexts :: ![Context] 43 -- ^ Contexts in which this feature may be presented. 44 , featureDependencies :: ![String] 45 -- ^ Names of features this feature depends on. 46 , featureAssumed :: !Bool 47 -- ^ Whether this feature is assumed to be universally supported. 48 } 49 deriving (Eq, Show, Generic) 50 51 instance NFData Feature 52 53 -- | The complete table of known features from BOLT #9. 54 knownFeatures :: [Feature] 55 knownFeatures = [ 56 Feature "option_data_loss_protect" 0 [] [] True 57 , Feature "option_upfront_shutdown_script" 4 [Init, NodeAnn] [] False 58 , Feature "gossip_queries" 6 [] [] False 59 , Feature "var_onion_optin" 8 [] [] True 60 , Feature "gossip_queries_ex" 10 [Init, NodeAnn] [] False 61 , Feature "option_static_remotekey" 12 [] [] True 62 , Feature "payment_secret" 14 [] [] True 63 , Feature "basic_mpp" 16 [Init, NodeAnn, Invoice] 64 ["payment_secret"] False 65 , Feature "option_support_large_channel" 18 [Init, NodeAnn] [] False 66 , Feature "option_anchors" 22 [Init, NodeAnn, ChanType] [] False 67 , Feature "option_route_blinding" 24 [Init, NodeAnn, Invoice] [] False 68 , Feature "option_shutdown_anysegwit" 26 [Init, NodeAnn] [] False 69 , Feature "option_dual_fund" 28 [Init, NodeAnn] [] False 70 , Feature "option_quiesce" 34 [Init, NodeAnn] [] False 71 , Feature "option_attribution_data" 36 [Init, NodeAnn, Invoice] 72 [] False 73 , Feature "option_onion_messages" 38 [Init, NodeAnn] [] False 74 , Feature "option_provide_storage" 42 [Init, NodeAnn] [] False 75 , Feature "option_channel_type" 44 [] [] True 76 , Feature "option_scid_alias" 46 [Init, NodeAnn, ChanType] [] False 77 , Feature "option_payment_metadata" 48 [Invoice] [] False 78 , Feature "option_zeroconf" 50 [Init, NodeAnn, ChanType] 79 ["option_scid_alias"] False 80 , Feature "option_simple_close" 60 [Init, NodeAnn] 81 ["option_shutdown_anysegwit"] False 82 ] 83 84 -- | Look up a feature by bit number. 85 -- 86 -- Accepts either the even (compulsory) or odd (optional) bit of the pair. 87 -- 88 -- >>> fmap featureName (featureByBit 16) 89 -- Just "basic_mpp" 90 -- >>> fmap featureName (featureByBit 17) -- odd bit also works 91 -- Just "basic_mpp" 92 -- >>> featureByBit 999 93 -- Nothing 94 featureByBit :: Word16 -> Maybe Feature 95 featureByBit !bit = 96 let !baseBit = fromIntegral bit - (fromIntegral bit `mod` 2) 97 in IM.lookup baseBit featuresByBit 98 {-# INLINE featureByBit #-} 99 100 -- | Look up a feature by its canonical name. 101 -- 102 -- >>> fmap featureBaseBit (featureByName "basic_mpp") 103 -- Just 16 104 -- >>> featureByName "nonexistent" 105 -- Nothing 106 featureByName :: String -> Maybe Feature 107 featureByName !name = M.lookup name featuresByName 108 {-# INLINE featureByName #-} 109 110 -- Lookup tables ------------------------------------------------------------- 111 112 -- | Features indexed by base bit (even bit number). 113 featuresByBit :: IntMap Feature 114 featuresByBit = IM.fromList 115 [(fromIntegral (featureBaseBit f), f) | f <- knownFeatures] 116 117 -- | Features indexed by canonical name. 118 featuresByName :: Map String Feature 119 featuresByName = M.fromList 120 [(featureName f, f) | f <- knownFeatures]