Types.hs (12632B)
1 {-# OPTIONS_HADDOCK prune #-} 2 3 {-# LANGUAGE BangPatterns #-} 4 {-# LANGUAGE DeriveGeneric #-} 5 6 -- | 7 -- Module: Lightning.Protocol.BOLT7.Types 8 -- Copyright: (c) 2025 Jared Tobin 9 -- License: MIT 10 -- Maintainer: Jared Tobin <jared@ppad.tech> 11 -- 12 -- Core types for BOLT #7 routing gossip. 13 14 module Lightning.Protocol.BOLT7.Types ( 15 -- * Identifiers (re-exported from BOLT1) 16 ChainHash(..) 17 , chainHash 18 , unChainHash 19 , mainnetChainHash 20 , ShortChannelId(..) 21 , shortChannelId 22 , scidBlockHeight 23 , scidTxIndex 24 , scidOutputIndex 25 , scidWord64 26 , scidFromBytes 27 , scidToBytes 28 , formatScid 29 , ChannelId(..) 30 , channelId 31 , unChannelId 32 33 -- * Cryptographic types (re-exported from BOLT1) 34 , Signature(..) 35 , signature 36 , unSignature 37 , Point(..) 38 , point 39 , unPoint 40 , NodeId 41 , nodeId 42 , getNodeId 43 44 -- * Node metadata 45 , RgbColor 46 , rgbColor 47 , getRgbColor 48 , Alias 49 , alias 50 , getAlias 51 , Timestamp 52 , FeatureBits 53 , featureBits 54 , getFeatureBits 55 56 -- * Address types 57 , Address(..) 58 , IPv4Addr 59 , ipv4Addr 60 , getIPv4Addr 61 , IPv6Addr 62 , ipv6Addr 63 , getIPv6Addr 64 , TorV3Addr 65 , torV3Addr 66 , getTorV3Addr 67 , Hostname 68 , hostname 69 , getHostname 70 71 -- * Channel update flags 72 , Direction(..) 73 , ChannelStatus(..) 74 , ChannelFlags(..) 75 , encodeChannelFlags 76 , decodeChannelFlags 77 78 -- * Routing parameters 79 , CltvExpiryDelta(..) 80 , FeeBaseMsat(..) 81 , FeeProportionalMillionths(..) 82 , HtlcMinimumMsat(..) 83 , HtlcMaximumMsat(..) 84 85 -- * Block range types 86 , BlockHeight(..) 87 , BlockCount(..) 88 89 -- * Constants 90 , chainHashLen 91 , shortChannelIdLen 92 , channelIdLen 93 , signatureLen 94 , pointLen 95 , nodeIdLen 96 , rgbColorLen 97 , aliasLen 98 , ipv4AddrLen 99 , ipv6AddrLen 100 , torV3AddrLen 101 ) where 102 103 import Control.DeepSeq (NFData) 104 import Data.Bits (shiftL, shiftR, (.&.), (.|.)) 105 import Data.ByteString (ByteString) 106 import qualified Data.ByteString as BS 107 import Data.Word (Word8, Word16, Word32, Word64) 108 import GHC.Generics (Generic) 109 import Lightning.Protocol.BOLT1.Prim 110 ( ChainHash(..), unChainHash, chainHash 111 , ShortChannelId(..), shortChannelId 112 , scidBlockHeight, scidTxIndex, scidOutputIndex, scidWord64 113 , ChannelId(..), unChannelId, channelId 114 , Signature(..), unSignature, signature 115 , Point(..), unPoint, point 116 ) 117 118 -- Constants ------------------------------------------------------------------- 119 120 -- | Length of a chain hash (32 bytes). 121 chainHashLen :: Int 122 chainHashLen = 32 123 {-# INLINE chainHashLen #-} 124 125 -- | Length of a short channel ID (8 bytes). 126 shortChannelIdLen :: Int 127 shortChannelIdLen = 8 128 {-# INLINE shortChannelIdLen #-} 129 130 -- | Length of a channel ID (32 bytes). 131 channelIdLen :: Int 132 channelIdLen = 32 133 {-# INLINE channelIdLen #-} 134 135 -- | Length of a signature (64 bytes). 136 signatureLen :: Int 137 signatureLen = 64 138 {-# INLINE signatureLen #-} 139 140 -- | Length of a compressed public key (33 bytes). 141 pointLen :: Int 142 pointLen = 33 143 {-# INLINE pointLen #-} 144 145 -- | Length of a node ID (33 bytes, same as compressed public key). 146 nodeIdLen :: Int 147 nodeIdLen = 33 148 {-# INLINE nodeIdLen #-} 149 150 -- | Length of RGB color (3 bytes). 151 rgbColorLen :: Int 152 rgbColorLen = 3 153 {-# INLINE rgbColorLen #-} 154 155 -- | Length of node alias (32 bytes). 156 aliasLen :: Int 157 aliasLen = 32 158 {-# INLINE aliasLen #-} 159 160 -- | Length of IPv4 address (4 bytes). 161 ipv4AddrLen :: Int 162 ipv4AddrLen = 4 163 {-# INLINE ipv4AddrLen #-} 164 165 -- | Length of IPv6 address (16 bytes). 166 ipv6AddrLen :: Int 167 ipv6AddrLen = 16 168 {-# INLINE ipv6AddrLen #-} 169 170 -- | Length of Tor v3 address (35 bytes). 171 torV3AddrLen :: Int 172 torV3AddrLen = 35 173 {-# INLINE torV3AddrLen #-} 174 175 -- Identifiers ----------------------------------------------------------------- 176 177 -- | Bitcoin mainnet chain hash (genesis block hash, little-endian). 178 mainnetChainHash :: ChainHash 179 mainnetChainHash = ChainHash $ BS.pack 180 [ 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72 181 , 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f 182 , 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c 183 , 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00 184 ] 185 186 -- | Parse ShortChannelId from 8 big-endian bytes. 187 scidFromBytes :: ByteString -> Maybe ShortChannelId 188 scidFromBytes !bs 189 | BS.length bs /= shortChannelIdLen = Nothing 190 | otherwise = 191 let !w = (fromIntegral (BS.index bs 0) `shiftL` 56) 192 .|. (fromIntegral (BS.index bs 1) `shiftL` 48) 193 .|. (fromIntegral (BS.index bs 2) `shiftL` 40) 194 .|. (fromIntegral (BS.index bs 3) `shiftL` 32) 195 .|. (fromIntegral (BS.index bs 4) `shiftL` 24) 196 .|. (fromIntegral (BS.index bs 5) `shiftL` 16) 197 .|. (fromIntegral (BS.index bs 6) `shiftL` 8) 198 .|. fromIntegral (BS.index bs 7) :: Word64 199 in Just (ShortChannelId w) 200 {-# INLINE scidFromBytes #-} 201 202 -- | Encode ShortChannelId as 8 big-endian bytes. 203 scidToBytes :: ShortChannelId -> ByteString 204 scidToBytes !sci = 205 let !w = scidWord64 sci 206 in BS.pack 207 [ fromIntegral (w `shiftR` 56) 208 , fromIntegral (w `shiftR` 48) 209 , fromIntegral (w `shiftR` 40) 210 , fromIntegral (w `shiftR` 32) 211 , fromIntegral (w `shiftR` 24) 212 , fromIntegral (w `shiftR` 16) 213 , fromIntegral (w `shiftR` 8) 214 , fromIntegral w 215 ] 216 {-# INLINE scidToBytes #-} 217 218 -- | Format short channel ID as human-readable string. 219 formatScid :: ShortChannelId -> String 220 formatScid sci = 221 show (scidBlockHeight sci) ++ "x" ++ 222 show (scidTxIndex sci) ++ "x" ++ 223 show (scidOutputIndex sci) 224 {-# INLINE formatScid #-} 225 226 -- Cryptographic types --------------------------------------------------------- 227 228 -- | Node ID (33 bytes, same as compressed public key). 229 -- 230 -- Has Ord instance for lexicographic comparison (required by spec for 231 -- channel announcements where node_id_1 < node_id_2). 232 newtype NodeId = NodeId { getNodeId :: ByteString } 233 deriving (Eq, Ord, Show, Generic) 234 235 instance NFData NodeId 236 237 -- | Smart constructor for NodeId. Returns Nothing if not 33 bytes. 238 nodeId :: ByteString -> Maybe NodeId 239 nodeId !bs 240 | BS.length bs == nodeIdLen = Just (NodeId bs) 241 | otherwise = Nothing 242 {-# INLINE nodeId #-} 243 244 -- Node metadata --------------------------------------------------------------- 245 246 -- | RGB color (3 bytes). 247 newtype RgbColor = RgbColor { getRgbColor :: ByteString } 248 deriving (Eq, Show, Generic) 249 250 instance NFData RgbColor 251 252 -- | Smart constructor for RgbColor. Returns Nothing if not 3 bytes. 253 rgbColor :: ByteString -> Maybe RgbColor 254 rgbColor !bs 255 | BS.length bs == rgbColorLen = Just (RgbColor bs) 256 | otherwise = Nothing 257 {-# INLINE rgbColor #-} 258 259 -- | Node alias (32 bytes, UTF-8 padded with zero bytes). 260 newtype Alias = Alias { getAlias :: ByteString } 261 deriving (Eq, Show, Generic) 262 263 instance NFData Alias 264 265 -- | Smart constructor for Alias. Returns Nothing if not 32 bytes. 266 alias :: ByteString -> Maybe Alias 267 alias !bs 268 | BS.length bs == aliasLen = Just (Alias bs) 269 | otherwise = Nothing 270 {-# INLINE alias #-} 271 272 -- | Timestamp (Unix epoch seconds). 273 type Timestamp = Word32 274 275 -- | Feature bits (variable length). 276 newtype FeatureBits = FeatureBits { getFeatureBits :: ByteString } 277 deriving (Eq, Show, Generic) 278 279 instance NFData FeatureBits 280 281 -- | Smart constructor for FeatureBits (any length). 282 featureBits :: ByteString -> FeatureBits 283 featureBits = FeatureBits 284 {-# INLINE featureBits #-} 285 286 -- Address types --------------------------------------------------------------- 287 288 -- | IPv4 address (4 bytes). 289 newtype IPv4Addr = IPv4Addr { getIPv4Addr :: ByteString } 290 deriving (Eq, Show, Generic) 291 292 instance NFData IPv4Addr 293 294 -- | Smart constructor for IPv4Addr. Returns Nothing if not 4 bytes. 295 ipv4Addr :: ByteString -> Maybe IPv4Addr 296 ipv4Addr !bs 297 | BS.length bs == ipv4AddrLen = Just (IPv4Addr bs) 298 | otherwise = Nothing 299 {-# INLINE ipv4Addr #-} 300 301 -- | IPv6 address (16 bytes). 302 newtype IPv6Addr = IPv6Addr { getIPv6Addr :: ByteString } 303 deriving (Eq, Show, Generic) 304 305 instance NFData IPv6Addr 306 307 -- | Smart constructor for IPv6Addr. Returns Nothing if not 16 bytes. 308 ipv6Addr :: ByteString -> Maybe IPv6Addr 309 ipv6Addr !bs 310 | BS.length bs == ipv6AddrLen = Just (IPv6Addr bs) 311 | otherwise = Nothing 312 {-# INLINE ipv6Addr #-} 313 314 -- | Tor v3 onion address (35 bytes: 32 pubkey + 2 checksum + 1 version). 315 newtype TorV3Addr = TorV3Addr { getTorV3Addr :: ByteString } 316 deriving (Eq, Show, Generic) 317 318 instance NFData TorV3Addr 319 320 -- | Smart constructor for TorV3Addr. Returns Nothing if not 35 bytes. 321 torV3Addr :: ByteString -> Maybe TorV3Addr 322 torV3Addr !bs 323 | BS.length bs == torV3AddrLen = Just (TorV3Addr bs) 324 | otherwise = Nothing 325 {-# INLINE torV3Addr #-} 326 327 -- | DNS hostname (1-255 bytes). 328 -- 329 -- Per BOLT #7 address descriptor type 5, the hostname is 330 -- a length-prefixed DNS name. The length byte limits it to 331 -- 255 bytes. 332 newtype Hostname = Hostname { getHostname :: ByteString } 333 deriving (Eq, Show, Generic) 334 335 instance NFData Hostname 336 337 -- | Smart constructor for Hostname. 338 -- 339 -- Returns Nothing if the hostname is empty or exceeds 340 -- 255 bytes. 341 hostname :: ByteString -> Maybe Hostname 342 hostname !bs 343 | BS.null bs = Nothing 344 | BS.length bs > 255 = Nothing 345 | otherwise = Just (Hostname bs) 346 {-# INLINE hostname #-} 347 348 -- | Network address with port. 349 data Address 350 = AddrIPv4 !IPv4Addr !Word16 -- ^ IPv4 address + port 351 | AddrIPv6 !IPv6Addr !Word16 -- ^ IPv6 address + port 352 | AddrTorV3 !TorV3Addr !Word16 -- ^ Tor v3 address + port 353 | AddrDNS !Hostname !Word16 -- ^ DNS hostname + port 354 deriving (Eq, Show, Generic) 355 356 instance NFData Address 357 358 -- Channel update flags -------------------------------------------------------- 359 360 -- | Direction of a channel_update. 361 -- 362 -- Per BOLT #7, bit 0 of channel_flags indicates which node 363 -- is the origin of the update. 364 data Direction 365 = NodeOne -- ^ Update from node_id_1 (bit 0 = 0) 366 | NodeTwo -- ^ Update from node_id_2 (bit 0 = 1) 367 deriving (Eq, Ord, Show, Generic) 368 369 instance NFData Direction 370 371 -- | Channel enabled\/disabled status. 372 -- 373 -- Per BOLT #7, bit 1 of channel_flags indicates whether 374 -- the channel is disabled. 375 data ChannelStatus 376 = Enabled -- ^ Channel is active (bit 1 = 0) 377 | Disabled -- ^ Channel is disabled (bit 1 = 1) 378 deriving (Eq, Ord, Show, Generic) 379 380 instance NFData ChannelStatus 381 382 -- | Channel flags for channel_update. 383 -- 384 -- Bit 0: direction (0 = node_id_1, 1 = node_id_2). 385 -- Bit 1: disabled (0 = enabled, 1 = disabled). 386 data ChannelFlags = ChannelFlags 387 { cfDirection :: !Direction -- ^ Update origin 388 , cfStatus :: !ChannelStatus -- ^ Channel status 389 } 390 deriving (Eq, Show, Generic) 391 392 instance NFData ChannelFlags 393 394 -- | Encode ChannelFlags to Word8. 395 encodeChannelFlags :: ChannelFlags -> Word8 396 encodeChannelFlags cf = 397 dir .|. sta 398 where 399 dir = case cfDirection cf of 400 NodeOne -> 0x00 401 NodeTwo -> 0x01 402 sta = case cfStatus cf of 403 Enabled -> 0x00 404 Disabled -> 0x02 405 {-# INLINE encodeChannelFlags #-} 406 407 -- | Decode Word8 to ChannelFlags. 408 decodeChannelFlags :: Word8 -> ChannelFlags 409 decodeChannelFlags w = ChannelFlags 410 { cfDirection = if w .&. 0x01 /= 0 411 then NodeTwo 412 else NodeOne 413 , cfStatus = if w .&. 0x02 /= 0 414 then Disabled 415 else Enabled 416 } 417 {-# INLINE decodeChannelFlags #-} 418 419 -- Routing parameters ---------------------------------------------------------- 420 421 -- | CLTV expiry delta. 422 newtype CltvExpiryDelta = CltvExpiryDelta { getCltvExpiryDelta :: Word16 } 423 deriving (Eq, Ord, Show, Generic) 424 425 instance NFData CltvExpiryDelta 426 427 -- | Base fee in millisatoshis. 428 newtype FeeBaseMsat = FeeBaseMsat { getFeeBaseMsat :: Word32 } 429 deriving (Eq, Ord, Show, Generic) 430 431 instance NFData FeeBaseMsat 432 433 -- | Proportional fee in millionths. 434 newtype FeeProportionalMillionths = FeeProportionalMillionths 435 { getFeeProportionalMillionths :: Word32 } 436 deriving (Eq, Ord, Show, Generic) 437 438 instance NFData FeeProportionalMillionths 439 440 -- | Minimum HTLC value in millisatoshis. 441 newtype HtlcMinimumMsat = HtlcMinimumMsat { getHtlcMinimumMsat :: Word64 } 442 deriving (Eq, Ord, Show, Generic) 443 444 instance NFData HtlcMinimumMsat 445 446 -- | Maximum HTLC value in millisatoshis. 447 newtype HtlcMaximumMsat = HtlcMaximumMsat 448 { getHtlcMaximumMsat :: Word64 } 449 deriving (Eq, Ord, Show, Generic) 450 451 instance NFData HtlcMaximumMsat 452 453 -- Block range types ----------------------------------------------------------- 454 455 -- | Absolute block height. 456 -- 457 -- Used in query_channel_range and reply_channel_range for 458 -- the first_blocknum field. 459 newtype BlockHeight = BlockHeight 460 { getBlockHeight :: Word32 } 461 deriving (Eq, Ord, Show, Generic) 462 463 instance NFData BlockHeight 464 465 -- | Block count (relative duration). 466 -- 467 -- Used in query_channel_range and reply_channel_range for 468 -- the number_of_blocks field. 469 newtype BlockCount = BlockCount 470 { getBlockCount :: Word32 } 471 deriving (Eq, Ord, Show, Generic) 472 473 instance NFData BlockCount