Types.hs (10495B)
1 {-# OPTIONS_HADDOCK prune #-} 2 {-# LANGUAGE BangPatterns #-} 3 {-# LANGUAGE DeriveGeneric #-} 4 {-# LANGUAGE PatternSynonyms #-} 5 6 -- | 7 -- Module: Lightning.Protocol.BOLT4.Types 8 -- Copyright: (c) 2025 Jared Tobin 9 -- License: MIT 10 -- Maintainer: Jared Tobin <jared@ppad.tech> 11 -- 12 -- Core data types for BOLT4 onion routing. 13 14 module Lightning.Protocol.BOLT4.Types ( 15 -- * Fixed-size newtypes 16 Hmac32(..) 17 , hmac32 18 , unHmac32 19 , HopPayloads(..) 20 , hopPayloads 21 , unHopPayloads 22 , PaymentSecret(..) 23 , paymentSecret 24 , unPaymentSecret 25 26 -- * Packet types 27 , OnionPacket(..) 28 , HopPayload(..) 29 , ShortChannelId(..) 30 , shortChannelId 31 , scidBlockHeight 32 , scidTxIndex 33 , scidOutputIndex 34 , scidWord64 35 , PaymentData(..) 36 , TlvRecord(..) 37 38 -- * Error types 39 , FailureMessage(..) 40 , FailureCode(..) 41 -- ** Flag bits 42 , pattern BADONION 43 , pattern PERM 44 , pattern NODE 45 , pattern UPDATE 46 -- ** Common failure codes 47 , pattern InvalidRealm 48 , pattern TemporaryNodeFailure 49 , pattern PermanentNodeFailure 50 , pattern RequiredNodeFeatureMissing 51 , pattern InvalidOnionVersion 52 , pattern InvalidOnionHmac 53 , pattern InvalidOnionKey 54 , pattern TemporaryChannelFailure 55 , pattern PermanentChannelFailure 56 , pattern AmountBelowMinimum 57 , pattern FeeInsufficient 58 , pattern IncorrectCltvExpiry 59 , pattern ExpiryTooSoon 60 , pattern IncorrectOrUnknownPaymentDetails 61 , pattern FinalIncorrectCltvExpiry 62 , pattern FinalIncorrectHtlcAmount 63 , pattern ChannelDisabled 64 , pattern ExpiryTooFar 65 , pattern InvalidOnionPayload 66 , pattern MppTimeout 67 68 -- * Processing results 69 , ProcessResult(..) 70 , ForwardInfo(..) 71 , ReceiveInfo(..) 72 73 -- * Constants 74 , onionPacketSize 75 , hopPayloadsSize 76 , hmacSize 77 , pubkeySize 78 , versionByte 79 , maxPayloadSize 80 ) where 81 82 import Data.Bits ((.&.), (.|.)) 83 import qualified Data.ByteString as BS 84 import Data.Word (Word8, Word16, Word32, Word64) 85 import GHC.Generics (Generic) 86 import Lightning.Protocol.BOLT1.Prim 87 ( ShortChannelId(..), shortChannelId 88 , scidBlockHeight, scidTxIndex, scidOutputIndex, scidWord64 89 ) 90 import Lightning.Protocol.BOLT4.Prim (SharedSecret) 91 92 -- Fixed-size newtypes ------------------------------------------------------- 93 94 -- | 32-byte HMAC value. 95 newtype Hmac32 = Hmac32 BS.ByteString 96 deriving (Eq, Show, Generic) 97 98 -- | Construct an 'Hmac32' from a 32-byte 'BS.ByteString'. 99 -- 100 -- Returns 'Nothing' if the input is not exactly 32 bytes. 101 hmac32 :: BS.ByteString -> Maybe Hmac32 102 hmac32 !bs 103 | BS.length bs == 32 = Just (Hmac32 bs) 104 | otherwise = Nothing 105 {-# INLINE hmac32 #-} 106 107 -- | Extract the raw bytes from an 'Hmac32'. 108 unHmac32 :: Hmac32 -> BS.ByteString 109 unHmac32 (Hmac32 bs) = bs 110 {-# INLINE unHmac32 #-} 111 112 -- | 1300-byte hop payloads section. 113 newtype HopPayloads = HopPayloads BS.ByteString 114 deriving (Eq, Show, Generic) 115 116 -- | Construct a 'HopPayloads' from a 1300-byte 'BS.ByteString'. 117 -- 118 -- Returns 'Nothing' if the input is not exactly 1300 bytes. 119 hopPayloads :: BS.ByteString -> Maybe HopPayloads 120 hopPayloads !bs 121 | BS.length bs == hopPayloadsSize = Just (HopPayloads bs) 122 | otherwise = Nothing 123 {-# INLINE hopPayloads #-} 124 125 -- | Extract the raw bytes from 'HopPayloads'. 126 unHopPayloads :: HopPayloads -> BS.ByteString 127 unHopPayloads (HopPayloads bs) = bs 128 {-# INLINE unHopPayloads #-} 129 130 -- | 32-byte payment secret. 131 newtype PaymentSecret = PaymentSecret BS.ByteString 132 deriving (Eq, Show, Generic) 133 134 -- | Construct a 'PaymentSecret' from a 32-byte 'BS.ByteString'. 135 -- 136 -- Returns 'Nothing' if the input is not exactly 32 bytes. 137 paymentSecret :: BS.ByteString -> Maybe PaymentSecret 138 paymentSecret !bs 139 | BS.length bs == 32 = Just (PaymentSecret bs) 140 | otherwise = Nothing 141 {-# INLINE paymentSecret #-} 142 143 -- | Extract the raw bytes from a 'PaymentSecret'. 144 unPaymentSecret :: PaymentSecret -> BS.ByteString 145 unPaymentSecret (PaymentSecret bs) = bs 146 {-# INLINE unPaymentSecret #-} 147 148 -- Packet types ------------------------------------------------------------- 149 150 -- | Complete onion packet (1366 bytes). 151 data OnionPacket = OnionPacket 152 { opVersion :: {-# UNPACK #-} !Word8 153 , opEphemeralKey :: !BS.ByteString -- ^ 33 bytes, compressed pubkey 154 , opHopPayloads :: !HopPayloads -- ^ 1300 bytes 155 , opHmac :: !Hmac32 -- ^ 32 bytes 156 } deriving (Eq, Show, Generic) 157 158 -- | Parsed hop payload after decryption. 159 data HopPayload = HopPayload 160 { hpAmtToForward :: !(Maybe Word64) -- ^ TLV type 2 161 , hpOutgoingCltv :: !(Maybe Word32) -- ^ TLV type 4 162 , hpShortChannelId :: !(Maybe ShortChannelId) -- ^ TLV type 6 163 , hpPaymentData :: !(Maybe PaymentData) -- ^ TLV type 8 164 , hpEncryptedData :: !(Maybe BS.ByteString) -- ^ TLV type 10 165 , hpCurrentPathKey :: !(Maybe BS.ByteString) -- ^ TLV type 12 166 , hpUnknownTlvs :: ![TlvRecord] -- ^ Unknown types 167 } deriving (Eq, Show, Generic) 168 169 -- | Payment data for final hop (TLV type 8). 170 data PaymentData = PaymentData 171 { pdPaymentSecret :: !PaymentSecret -- ^ 32 bytes 172 , pdTotalMsat :: {-# UNPACK #-} !Word64 173 } deriving (Eq, Show, Generic) 174 175 -- | Generic TLV record for unknown/extension types. 176 data TlvRecord = TlvRecord 177 { tlvType :: {-# UNPACK #-} !Word64 178 , tlvValue :: !BS.ByteString 179 } deriving (Eq, Show, Generic) 180 181 -- Error types -------------------------------------------------------------- 182 183 -- | Failure message from intermediate or final node. 184 data FailureMessage = FailureMessage 185 { fmCode :: {-# UNPACK #-} !FailureCode 186 , fmData :: !BS.ByteString 187 , fmTlvs :: ![TlvRecord] 188 } deriving (Eq, Show, Generic) 189 190 -- | 2-byte failure code with flag bits. 191 newtype FailureCode = FailureCode Word16 192 deriving (Eq, Show) 193 194 -- Flag bits 195 196 -- | BADONION flag (0x8000): error was in parsing the onion. 197 pattern BADONION :: Word16 198 pattern BADONION = 0x8000 199 200 -- | PERM flag (0x4000): permanent failure, do not retry. 201 pattern PERM :: Word16 202 pattern PERM = 0x4000 203 204 -- | NODE flag (0x2000): node failure rather than channel. 205 pattern NODE :: Word16 206 pattern NODE = 0x2000 207 208 -- | UPDATE flag (0x1000): channel update is attached. 209 pattern UPDATE :: Word16 210 pattern UPDATE = 0x1000 211 212 -- Common failure codes 213 214 -- | Invalid realm byte in onion. 215 pattern InvalidRealm :: FailureCode 216 pattern InvalidRealm = FailureCode 0x4001 -- PERM .|. 1 217 218 -- | Temporary node failure. 219 pattern TemporaryNodeFailure :: FailureCode 220 pattern TemporaryNodeFailure = FailureCode 0x2002 -- NODE .|. 2 221 222 -- | Permanent node failure. 223 pattern PermanentNodeFailure :: FailureCode 224 pattern PermanentNodeFailure = FailureCode 0x6002 -- PERM .|. NODE .|. 2 225 226 -- | Required node feature missing. 227 pattern RequiredNodeFeatureMissing :: FailureCode 228 pattern RequiredNodeFeatureMissing = FailureCode 0x6003 -- PERM .|. NODE .|. 3 229 230 -- | Invalid onion version. 231 pattern InvalidOnionVersion :: FailureCode 232 pattern InvalidOnionVersion = FailureCode 0xC004 -- BADONION .|. PERM .|. 4 233 234 -- | Invalid HMAC in onion. 235 pattern InvalidOnionHmac :: FailureCode 236 pattern InvalidOnionHmac = FailureCode 0xC005 -- BADONION .|. PERM .|. 5 237 238 -- | Invalid ephemeral key in onion. 239 pattern InvalidOnionKey :: FailureCode 240 pattern InvalidOnionKey = FailureCode 0xC006 -- BADONION .|. PERM .|. 6 241 242 -- | Temporary channel failure. 243 pattern TemporaryChannelFailure :: FailureCode 244 pattern TemporaryChannelFailure = FailureCode 0x1007 -- UPDATE .|. 7 245 246 -- | Permanent channel failure. 247 pattern PermanentChannelFailure :: FailureCode 248 pattern PermanentChannelFailure = FailureCode 0x4008 -- PERM .|. 8 249 250 -- | Amount below minimum for channel. 251 pattern AmountBelowMinimum :: FailureCode 252 pattern AmountBelowMinimum = FailureCode 0x100B -- UPDATE .|. 11 253 254 -- | Fee insufficient. 255 pattern FeeInsufficient :: FailureCode 256 pattern FeeInsufficient = FailureCode 0x100C -- UPDATE .|. 12 257 258 -- | Incorrect CLTV expiry. 259 pattern IncorrectCltvExpiry :: FailureCode 260 pattern IncorrectCltvExpiry = FailureCode 0x100D -- UPDATE .|. 13 261 262 -- | Expiry too soon. 263 pattern ExpiryTooSoon :: FailureCode 264 pattern ExpiryTooSoon = FailureCode 0x100E -- UPDATE .|. 14 265 266 -- | Payment details incorrect or unknown. 267 pattern IncorrectOrUnknownPaymentDetails :: FailureCode 268 pattern IncorrectOrUnknownPaymentDetails = FailureCode 0x400F -- PERM .|. 15 269 270 -- | Final incorrect CLTV expiry. 271 pattern FinalIncorrectCltvExpiry :: FailureCode 272 pattern FinalIncorrectCltvExpiry = FailureCode 18 -- 0x12 273 274 -- | Final incorrect HTLC amount. 275 pattern FinalIncorrectHtlcAmount :: FailureCode 276 pattern FinalIncorrectHtlcAmount = FailureCode 19 -- 0x13 277 278 -- | Channel disabled. 279 pattern ChannelDisabled :: FailureCode 280 pattern ChannelDisabled = FailureCode 0x1014 -- UPDATE .|. 20 281 282 -- | Expiry too far. 283 pattern ExpiryTooFar :: FailureCode 284 pattern ExpiryTooFar = FailureCode 21 -- 0x15 285 286 -- | Invalid onion payload. 287 pattern InvalidOnionPayload :: FailureCode 288 pattern InvalidOnionPayload = FailureCode 0x4016 -- PERM .|. 22 289 290 -- | MPP timeout. 291 pattern MppTimeout :: FailureCode 292 pattern MppTimeout = FailureCode 23 -- 0x17 293 294 -- Processing results ------------------------------------------------------- 295 296 -- | Result of processing an onion packet. 297 data ProcessResult 298 = Forward !ForwardInfo -- ^ Forward to next hop 299 | Receive !ReceiveInfo -- ^ Final destination reached 300 deriving (Eq, Show, Generic) 301 302 -- | Information for forwarding to next hop. 303 data ForwardInfo = ForwardInfo 304 { fiNextPacket :: !OnionPacket 305 , fiPayload :: !HopPayload 306 , fiSharedSecret :: !SharedSecret -- ^ For error attribution 307 } deriving (Eq, Show, Generic) 308 309 -- | Information for receiving at final destination. 310 data ReceiveInfo = ReceiveInfo 311 { riPayload :: !HopPayload 312 , riSharedSecret :: !SharedSecret 313 } deriving (Eq, Show, Generic) 314 315 -- Constants ---------------------------------------------------------------- 316 317 -- | Total onion packet size (1366 bytes). 318 onionPacketSize :: Int 319 onionPacketSize = 1366 320 {-# INLINE onionPacketSize #-} 321 322 -- | Hop payloads section size (1300 bytes). 323 hopPayloadsSize :: Int 324 hopPayloadsSize = 1300 325 {-# INLINE hopPayloadsSize #-} 326 327 -- | HMAC size (32 bytes). 328 hmacSize :: Int 329 hmacSize = 32 330 {-# INLINE hmacSize #-} 331 332 -- | Compressed public key size (33 bytes). 333 pubkeySize :: Int 334 pubkeySize = 33 335 {-# INLINE pubkeySize #-} 336 337 -- | Version byte for onion packets. 338 versionByte :: Word8 339 versionByte = 0x00 340 {-# INLINE versionByte #-} 341 342 -- | Maximum payload size (1300 - 32 - 1 = 1267 bytes). 343 maxPayloadSize :: Int 344 maxPayloadSize = hopPayloadsSize - hmacSize - 1 345 {-# INLINE maxPayloadSize #-} 346 347 -- Silence unused import warning 348 _useBits :: Word16 349 _useBits = BADONION .&. PERM .|. NODE .|. UPDATE