Types.hs (14122B)
1 {-# OPTIONS_HADDOCK prune #-} 2 {-# LANGUAGE BangPatterns #-} 3 {-# LANGUAGE DeriveGeneric #-} 4 {-# LANGUAGE DerivingStrategies #-} 5 {-# LANGUAGE GeneralizedNewtypeDeriving #-} 6 7 -- | 8 -- Module: Lightning.Protocol.BOLT2.Types 9 -- Copyright: (c) 2025 Jared Tobin 10 -- License: MIT 11 -- Maintainer: Jared Tobin <jared@ppad.tech> 12 -- 13 -- Core types for BOLT #2 peer protocol. 14 -- 15 -- This module provides newtypes for identifiers, amounts, hashes, and 16 -- keys used in the Lightning Network peer protocol. 17 18 module Lightning.Protocol.BOLT2.Types ( 19 -- * Identifiers 20 ChannelId 21 , channelId 22 , unChannelId 23 24 -- * Amounts 25 , Satoshis(..) 26 , MilliSatoshis(..) 27 , satoshisToMsat 28 , msatToSatoshis 29 30 -- * Cryptographic types 31 , Signature 32 , signature 33 , unSignature 34 , Point 35 , point 36 , unPoint 37 , PaymentHash 38 , paymentHash 39 , unPaymentHash 40 , PaymentPreimage 41 , paymentPreimage 42 , unPaymentPreimage 43 , Secret 44 , secret 45 , unSecret 46 47 -- * Transaction types 48 , TxId(..) 49 , mkTxId 50 , OutPoint(..) 51 , ScriptPubKey 52 , scriptPubKey 53 , unScriptPubKey 54 55 -- * Chain types 56 , ChainHash 57 , chainHash 58 , unChainHash 59 , ShortChannelId(..) 60 , shortChannelId 61 , scidBlockHeight 62 , scidTxIndex 63 , scidOutputIndex 64 65 -- * Protocol types 66 , FeatureBits 67 , featureBits 68 , unFeatureBits 69 , OnionPacket 70 , onionPacket 71 , unOnionPacket 72 73 -- * Constants 74 , channelIdLen 75 , signatureLen 76 , pointLen 77 , chainHashLen 78 , shortChannelIdLen 79 , paymentHashLen 80 , paymentPreimageLen 81 , onionPacketLen 82 , secretLen 83 ) where 84 85 import Bitcoin.Prim.Tx (TxId(..), mkTxId, OutPoint(..)) 86 import Control.DeepSeq (NFData) 87 import Data.Bits (unsafeShiftL, unsafeShiftR, (.&.), (.|.)) 88 import qualified Data.ByteString as BS 89 import Data.Word (Word16, Word32, Word64) 90 import GHC.Generics (Generic) 91 92 -- constants ------------------------------------------------------------------- 93 94 -- | Length of a channel_id in bytes (32). 95 channelIdLen :: Int 96 channelIdLen = 32 97 {-# INLINE channelIdLen #-} 98 99 -- | Length of a signature in bytes (64, compact format). 100 signatureLen :: Int 101 signatureLen = 64 102 {-# INLINE signatureLen #-} 103 104 -- | Length of a compressed secp256k1 public key in bytes (33). 105 pointLen :: Int 106 pointLen = 33 107 {-# INLINE pointLen #-} 108 109 -- | Length of a chain hash in bytes (32). 110 chainHashLen :: Int 111 chainHashLen = 32 112 {-# INLINE chainHashLen #-} 113 114 -- | Length of a short_channel_id in bytes (8). 115 shortChannelIdLen :: Int 116 shortChannelIdLen = 8 117 {-# INLINE shortChannelIdLen #-} 118 119 -- | Length of a payment hash in bytes (32). 120 paymentHashLen :: Int 121 paymentHashLen = 32 122 {-# INLINE paymentHashLen #-} 123 124 -- | Length of a payment preimage in bytes (32). 125 paymentPreimageLen :: Int 126 paymentPreimageLen = 32 127 {-# INLINE paymentPreimageLen #-} 128 129 -- | Length of an onion routing packet in bytes (1366). 130 onionPacketLen :: Int 131 onionPacketLen = 1366 132 {-# INLINE onionPacketLen #-} 133 134 -- | Length of a per-commitment secret in bytes (32). 135 secretLen :: Int 136 secretLen = 32 137 {-# INLINE secretLen #-} 138 139 -- identifiers ----------------------------------------------------------------- 140 141 -- | A 32-byte channel identifier. 142 -- 143 -- Derived from the funding transaction by XORing @funding_txid@ with 144 -- @funding_output_index@ (big-endian, altering the last 2 bytes). 145 -- 146 -- For v2 channels, derived as @SHA256(lesser-revocation-basepoint || 147 -- greater-revocation-basepoint)@. 148 newtype ChannelId = ChannelId BS.ByteString 149 deriving stock (Eq, Ord, Show, Generic) 150 deriving newtype NFData 151 152 -- | Construct a 'ChannelId' from a 32-byte 'BS.ByteString'. 153 -- 154 -- Returns 'Nothing' if the input is not exactly 32 bytes. 155 -- 156 -- >>> channelId (BS.replicate 32 0x00) 157 -- Just (ChannelId ...) 158 -- >>> channelId (BS.replicate 31 0x00) 159 -- Nothing 160 channelId :: BS.ByteString -> Maybe ChannelId 161 channelId !bs 162 | BS.length bs == channelIdLen = Just $! ChannelId bs 163 | otherwise = Nothing 164 {-# INLINABLE channelId #-} 165 166 -- | Extract the underlying 'BS.ByteString' from a 'ChannelId'. 167 unChannelId :: ChannelId -> BS.ByteString 168 unChannelId (ChannelId bs) = bs 169 {-# INLINE unChannelId #-} 170 171 -- amounts --------------------------------------------------------------------- 172 173 -- | Amount in satoshis (1/100,000,000 of a bitcoin). 174 -- 175 -- Stored as a 'Word64'. Maximum valid value is 21,000,000 * 100,000,000 176 -- = 2,100,000,000,000,000 satoshis. 177 newtype Satoshis = Satoshis { unSatoshis :: Word64 } 178 deriving stock (Eq, Ord, Show, Generic) 179 deriving newtype (NFData, Num, Enum, Real, Integral) 180 181 -- | Amount in millisatoshis (1/1000 of a satoshi). 182 -- 183 -- Stored as a 'Word64'. Used for HTLC amounts and channel balances. 184 newtype MilliSatoshis = MilliSatoshis { unMilliSatoshis :: Word64 } 185 deriving stock (Eq, Ord, Show, Generic) 186 deriving newtype (NFData, Num, Enum, Real, Integral) 187 188 -- | Convert 'Satoshis' to 'MilliSatoshis'. 189 -- 190 -- >>> satoshisToMsat (Satoshis 1) 191 -- MilliSatoshis 1000 192 satoshisToMsat :: Satoshis -> MilliSatoshis 193 satoshisToMsat (Satoshis !s) = MilliSatoshis $! s * 1000 194 {-# INLINE satoshisToMsat #-} 195 196 -- | Convert 'MilliSatoshis' to 'Satoshis', rounding down. 197 -- 198 -- >>> msatToSatoshis (MilliSatoshis 1500) 199 -- Satoshis 1 200 msatToSatoshis :: MilliSatoshis -> Satoshis 201 msatToSatoshis (MilliSatoshis !m) = Satoshis $! m `div` 1000 202 {-# INLINE msatToSatoshis #-} 203 204 -- cryptographic types --------------------------------------------------------- 205 206 -- | A 64-byte compact ECDSA signature. 207 -- 208 -- Used for commitment transaction signatures, HTLC signatures, and 209 -- closing transaction signatures. 210 newtype Signature = Signature BS.ByteString 211 deriving stock (Eq, Ord, Show, Generic) 212 deriving newtype NFData 213 214 -- | Construct a 'Signature' from a 64-byte 'BS.ByteString'. 215 -- 216 -- Returns 'Nothing' if the input is not exactly 64 bytes. 217 signature :: BS.ByteString -> Maybe Signature 218 signature !bs 219 | BS.length bs == signatureLen = Just $! Signature bs 220 | otherwise = Nothing 221 {-# INLINABLE signature #-} 222 223 -- | Extract the underlying 'BS.ByteString' from a 'Signature'. 224 unSignature :: Signature -> BS.ByteString 225 unSignature (Signature bs) = bs 226 {-# INLINE unSignature #-} 227 228 -- | A 33-byte compressed secp256k1 public key. 229 -- 230 -- Used for funding pubkeys, basepoints, and per-commitment points. 231 newtype Point = Point BS.ByteString 232 deriving stock (Eq, Ord, Show, Generic) 233 deriving newtype NFData 234 235 -- | Construct a 'Point' from a 33-byte 'BS.ByteString'. 236 -- 237 -- Returns 'Nothing' if the input is not exactly 33 bytes. 238 -- 239 -- Note: This only validates the length. Use secp256k1 libraries for 240 -- full point validation. 241 point :: BS.ByteString -> Maybe Point 242 point !bs 243 | BS.length bs == pointLen = Just $! Point bs 244 | otherwise = Nothing 245 {-# INLINABLE point #-} 246 247 -- | Extract the underlying 'BS.ByteString' from a 'Point'. 248 unPoint :: Point -> BS.ByteString 249 unPoint (Point bs) = bs 250 {-# INLINE unPoint #-} 251 252 -- | A 32-byte SHA256 payment hash. 253 -- 254 -- Used to identify HTLCs. The preimage that hashes to this value is 255 -- required to claim the HTLC. 256 newtype PaymentHash = PaymentHash BS.ByteString 257 deriving stock (Eq, Ord, Show, Generic) 258 deriving newtype NFData 259 260 -- | Construct a 'PaymentHash' from a 32-byte 'BS.ByteString'. 261 -- 262 -- Returns 'Nothing' if the input is not exactly 32 bytes. 263 paymentHash :: BS.ByteString -> Maybe PaymentHash 264 paymentHash !bs 265 | BS.length bs == paymentHashLen = Just $! PaymentHash bs 266 | otherwise = Nothing 267 {-# INLINABLE paymentHash #-} 268 269 -- | Extract the underlying 'BS.ByteString' from a 'PaymentHash'. 270 unPaymentHash :: PaymentHash -> BS.ByteString 271 unPaymentHash (PaymentHash bs) = bs 272 {-# INLINE unPaymentHash #-} 273 274 -- | A 32-byte payment preimage. 275 -- 276 -- The SHA256 hash of this value produces the corresponding 'PaymentHash'. 277 -- Knowledge of the preimage allows claiming an HTLC. 278 newtype PaymentPreimage = PaymentPreimage BS.ByteString 279 deriving stock (Eq, Ord, Show, Generic) 280 deriving newtype NFData 281 282 -- | Construct a 'PaymentPreimage' from a 32-byte 'BS.ByteString'. 283 -- 284 -- Returns 'Nothing' if the input is not exactly 32 bytes. 285 paymentPreimage :: BS.ByteString -> Maybe PaymentPreimage 286 paymentPreimage !bs 287 | BS.length bs == paymentPreimageLen = Just $! PaymentPreimage bs 288 | otherwise = Nothing 289 {-# INLINABLE paymentPreimage #-} 290 291 -- | Extract the underlying 'BS.ByteString' from a 'PaymentPreimage'. 292 unPaymentPreimage :: PaymentPreimage -> BS.ByteString 293 unPaymentPreimage (PaymentPreimage bs) = bs 294 {-# INLINE unPaymentPreimage #-} 295 296 -- | A 32-byte per-commitment secret. 297 -- 298 -- Used in revoke_and_ack and channel_reestablish messages to revoke 299 -- old commitment transactions. 300 newtype Secret = Secret BS.ByteString 301 deriving stock (Eq, Ord, Show, Generic) 302 deriving newtype NFData 303 304 -- | Construct a 'Secret' from a 32-byte 'BS.ByteString'. 305 -- 306 -- Returns 'Nothing' if the input is not exactly 32 bytes. 307 secret :: BS.ByteString -> Maybe Secret 308 secret !bs 309 | BS.length bs == secretLen = Just $! Secret bs 310 | otherwise = Nothing 311 {-# INLINABLE secret #-} 312 313 -- | Extract the underlying 'BS.ByteString' from a 'Secret'. 314 unSecret :: Secret -> BS.ByteString 315 unSecret (Secret bs) = bs 316 {-# INLINE unSecret #-} 317 318 -- transaction types ----------------------------------------------------------- 319 320 -- | A script pubkey (output script). 321 -- 322 -- Variable length; used in shutdown messages, closing transactions, etc. 323 newtype ScriptPubKey = ScriptPubKey BS.ByteString 324 deriving stock (Eq, Ord, Show, Generic) 325 deriving newtype NFData 326 327 -- | Construct a 'ScriptPubKey' from a 'BS.ByteString'. 328 -- 329 -- Accepts any length; validation of script structure is left to higher 330 -- layers. 331 scriptPubKey :: BS.ByteString -> ScriptPubKey 332 scriptPubKey = ScriptPubKey 333 {-# INLINE scriptPubKey #-} 334 335 -- | Extract the underlying 'BS.ByteString' from a 'ScriptPubKey'. 336 unScriptPubKey :: ScriptPubKey -> BS.ByteString 337 unScriptPubKey (ScriptPubKey bs) = bs 338 {-# INLINE unScriptPubKey #-} 339 340 -- chain types ----------------------------------------------------------------- 341 342 -- | A 32-byte chain hash. 343 -- 344 -- Identifies the blockchain (typically the genesis block hash). 345 -- Used in @open_channel@ to specify which chain the channel will reside on. 346 newtype ChainHash = ChainHash BS.ByteString 347 deriving stock (Eq, Ord, Show, Generic) 348 deriving newtype NFData 349 350 -- | Construct a 'ChainHash' from a 32-byte 'BS.ByteString'. 351 -- 352 -- Returns 'Nothing' if the input is not exactly 32 bytes. 353 chainHash :: BS.ByteString -> Maybe ChainHash 354 chainHash !bs 355 | BS.length bs == chainHashLen = Just $! ChainHash bs 356 | otherwise = Nothing 357 {-# INLINABLE chainHash #-} 358 359 -- | Extract the underlying 'BS.ByteString' from a 'ChainHash'. 360 unChainHash :: ChainHash -> BS.ByteString 361 unChainHash (ChainHash bs) = bs 362 {-# INLINE unChainHash #-} 363 364 -- | A short channel identifier (8 bytes). 365 -- 366 -- Encodes the block height (3 bytes), transaction index (3 bytes), and 367 -- output index (2 bytes) of the funding transaction output. 368 -- 369 -- This is a compact representation for referencing channels in gossip 370 -- and routing. 371 data ShortChannelId = ShortChannelId 372 { scidBytes :: {-# UNPACK #-} !Word64 373 } 374 deriving stock (Eq, Ord, Show, Generic) 375 376 instance NFData ShortChannelId 377 378 -- | Construct a 'ShortChannelId' from block height, tx index, and 379 -- output index. 380 -- 381 -- Returns 'Nothing' if any component exceeds its maximum value: 382 -- 383 -- * block height: max 16,777,215 (2^24 - 1) 384 -- * tx index: max 16,777,215 (2^24 - 1) 385 -- * output index: max 65,535 (2^16 - 1) 386 -- 387 -- >>> shortChannelId 800000 1234 0 388 -- Just (ShortChannelId ...) 389 shortChannelId 390 :: Word32 -- ^ Block height (24 bits max) 391 -> Word32 -- ^ Transaction index (24 bits max) 392 -> Word16 -- ^ Output index 393 -> Maybe ShortChannelId 394 shortChannelId !blockHeight !txIndex !outputIndex 395 | blockHeight > 0xFFFFFF = Nothing 396 | txIndex > 0xFFFFFF = Nothing 397 | otherwise = Just $! ShortChannelId scid 398 where 399 !scid = (fromIntegral blockHeight `unsafeShiftL` 40) 400 .|. (fromIntegral txIndex `unsafeShiftL` 16) 401 .|. fromIntegral outputIndex 402 {-# INLINABLE shortChannelId #-} 403 404 -- | Extract the block height from a 'ShortChannelId'. 405 scidBlockHeight :: ShortChannelId -> Word32 406 scidBlockHeight (ShortChannelId !w) = 407 fromIntegral $! (w `unsafeShiftR` 40) .&. 0xFFFFFF 408 {-# INLINE scidBlockHeight #-} 409 410 -- | Extract the transaction index from a 'ShortChannelId'. 411 scidTxIndex :: ShortChannelId -> Word32 412 scidTxIndex (ShortChannelId !w) = 413 fromIntegral $! (w `unsafeShiftR` 16) .&. 0xFFFFFF 414 {-# INLINE scidTxIndex #-} 415 416 -- | Extract the output index from a 'ShortChannelId'. 417 scidOutputIndex :: ShortChannelId -> Word16 418 scidOutputIndex (ShortChannelId !w) = fromIntegral $! w .&. 0xFFFF 419 {-# INLINE scidOutputIndex #-} 420 421 -- protocol types -------------------------------------------------------------- 422 423 -- | Feature bits (variable length). 424 -- 425 -- Encodes supported/required features. Even bits indicate required 426 -- features; odd bits indicate optional features. 427 newtype FeatureBits = FeatureBits BS.ByteString 428 deriving stock (Eq, Ord, Show, Generic) 429 deriving newtype NFData 430 431 -- | Construct 'FeatureBits' from a 'BS.ByteString'. 432 -- 433 -- Accepts any length; feature bit parsing is left to higher layers. 434 featureBits :: BS.ByteString -> FeatureBits 435 featureBits = FeatureBits 436 {-# INLINE featureBits #-} 437 438 -- | Extract the underlying 'BS.ByteString' from 'FeatureBits'. 439 unFeatureBits :: FeatureBits -> BS.ByteString 440 unFeatureBits (FeatureBits bs) = bs 441 {-# INLINE unFeatureBits #-} 442 443 -- | A 1366-byte onion routing packet. 444 -- 445 -- Contains encrypted routing information for HTLC forwarding, as 446 -- specified in BOLT #4. 447 newtype OnionPacket = OnionPacket BS.ByteString 448 deriving stock (Eq, Ord, Show, Generic) 449 deriving newtype NFData 450 451 -- | Construct an 'OnionPacket' from a 1366-byte 'BS.ByteString'. 452 -- 453 -- Returns 'Nothing' if the input is not exactly 1366 bytes. 454 onionPacket :: BS.ByteString -> Maybe OnionPacket 455 onionPacket !bs 456 | BS.length bs == onionPacketLen = Just $! OnionPacket bs 457 | otherwise = Nothing 458 {-# INLINABLE onionPacket #-} 459 460 -- | Extract the underlying 'BS.ByteString' from an 'OnionPacket'. 461 unOnionPacket :: OnionPacket -> BS.ByteString 462 unOnionPacket (OnionPacket bs) = bs 463 {-# INLINE unOnionPacket #-}