bolt2

Lightning peer protocol, per BOLT #2 (docs.ppad.tech/bolt2).
git clone git://git.ppad.tech/bolt2.git
Log | Files | Refs | README | LICENSE

Types.hs (6093B)


      1 {-# OPTIONS_HADDOCK hide #-}
      2 {-# LANGUAGE DeriveGeneric #-}
      3 
      4 -- |
      5 -- Module: Lightning.Protocol.BOLT2.Types
      6 -- Copyright: (c) 2025 Jared Tobin
      7 -- License: MIT
      8 -- Maintainer: Jared Tobin <jared@ppad.tech>
      9 --
     10 -- Field types specific to BOLT #2.
     11 
     12 module Lightning.Protocol.BOLT2.Types (
     13     HtlcId(..)
     14   , SerialId(..)
     15   , ScriptPubKey
     16   , script_pubkey
     17   , un_script_pubkey
     18   , Witness
     19   , witness
     20   , un_witness
     21   , OnionRoutingPacket
     22   , onion_routing_packet
     23   , un_onion_routing_packet
     24   , OnionHash
     25   , onion_hash
     26   , un_onion_hash
     27   , AttributionData
     28   , attribution_data
     29   , un_attribution_data
     30   , FeeRange(..)
     31   , NextFunding(..)
     32   ) where
     33 
     34 import Bitcoin.Prim.Tx (TxId)
     35 import Control.DeepSeq (NFData)
     36 import qualified Data.ByteString as BS
     37 import Data.Word (Word8, Word64)
     38 import GHC.Generics (Generic)
     39 import Lightning.Protocol.BOLT1 (Satoshi)
     40 
     41 -- | An HTLC identifier (the @id@ field of the HTLC messages). The
     42 --   offerer numbers its HTLCs from 0, incrementing by 1.
     43 newtype HtlcId = HtlcId Word64
     44   deriving (Eq, Ord, Show, Generic)
     45 
     46 instance NFData HtlcId
     47 
     48 -- | The @serial_id@ of an input or output in interactive transaction
     49 --   construction. The initiator sends even values, the non-initiator
     50 --   odd ones.
     51 newtype SerialId = SerialId Word64
     52   deriving (Eq, Ord, Show, Generic)
     53 
     54 instance NFData SerialId
     55 
     56 -- | A scriptPubKey, at most 65535 bytes (the most a u16 length prefix
     57 --   can describe).
     58 newtype ScriptPubKey = ScriptPubKey BS.ByteString
     59   deriving (Eq, Ord, Show, Generic)
     60 
     61 instance NFData ScriptPubKey
     62 
     63 -- | Construct a t'ScriptPubKey', failing above 65535 bytes. The script
     64 --   itself isn't checked; the forms acceptable in @shutdown@ depend on
     65 --   negotiated features.
     66 --
     67 --   >>> script_pubkey "\x51\x02\x4e\x73"
     68 --   Just (ScriptPubKey "Q\STXNs")
     69 --   >>> script_pubkey (BS.replicate 65536 0x00)
     70 --   Nothing
     71 script_pubkey :: BS.ByteString -> Maybe ScriptPubKey
     72 script_pubkey bs
     73   | BS.length bs <= 65535 = Just (ScriptPubKey bs)
     74   | otherwise             = Nothing
     75 {-# INLINE script_pubkey #-}
     76 
     77 -- | The bytes of a t'ScriptPubKey'.
     78 un_script_pubkey :: ScriptPubKey -> BS.ByteString
     79 un_script_pubkey (ScriptPubKey bs) = bs
     80 {-# INLINE un_script_pubkey #-}
     81 
     82 -- | The serialized witness of one input in @tx_signatures@ (encoded as
     83 --   in Bitcoin's wire protocol), at most 65535 bytes.
     84 newtype Witness = Witness BS.ByteString
     85   deriving (Eq, Ord, Show, Generic)
     86 
     87 instance NFData Witness
     88 
     89 -- | Construct a t'Witness', failing above 65535 bytes. The contents
     90 --   aren't checked.
     91 --
     92 --   >>> witness "\x01\x01\x2a"
     93 --   Just (Witness "\SOH\SOH*")
     94 witness :: BS.ByteString -> Maybe Witness
     95 witness bs
     96   | BS.length bs <= 65535 = Just (Witness bs)
     97   | otherwise             = Nothing
     98 {-# INLINE witness #-}
     99 
    100 -- | The bytes of a t'Witness'.
    101 un_witness :: Witness -> BS.ByteString
    102 un_witness (Witness bs) = bs
    103 {-# INLINE un_witness #-}
    104 
    105 -- | The 1366-byte @onion_routing_packet@ of @update_add_htlc@, kept
    106 --   opaque (BOLT #4 defines its structure).
    107 newtype OnionRoutingPacket = OnionRoutingPacket BS.ByteString
    108   deriving (Eq, Ord, Show, Generic)
    109 
    110 instance NFData OnionRoutingPacket
    111 
    112 -- | Construct an t'OnionRoutingPacket' from exactly 1366 bytes.
    113 --
    114 --   >>> let bs = BS.replicate 1366 0x00
    115 --   >>> fmap un_onion_routing_packet (onion_routing_packet bs) == Just bs
    116 --   True
    117 --   >>> onion_routing_packet (BS.take 1365 bs)
    118 --   Nothing
    119 onion_routing_packet :: BS.ByteString -> Maybe OnionRoutingPacket
    120 onion_routing_packet bs
    121   | BS.length bs == 1366 = Just (OnionRoutingPacket bs)
    122   | otherwise            = Nothing
    123 {-# INLINE onion_routing_packet #-}
    124 
    125 -- | The bytes of an t'OnionRoutingPacket'.
    126 un_onion_routing_packet :: OnionRoutingPacket -> BS.ByteString
    127 un_onion_routing_packet (OnionRoutingPacket bs) = bs
    128 {-# INLINE un_onion_routing_packet #-}
    129 
    130 -- | The SHA256 hash of an onion routing packet (the @sha256_of_onion@
    131 --   field of @update_fail_malformed_htlc@).
    132 newtype OnionHash = OnionHash BS.ByteString
    133   deriving (Eq, Ord, Show, Generic)
    134 
    135 instance NFData OnionHash
    136 
    137 -- | Construct an t'OnionHash' from exactly 32 bytes.
    138 --
    139 --   >>> onion_hash (BS.replicate 31 0x00)
    140 --   Nothing
    141 onion_hash :: BS.ByteString -> Maybe OnionHash
    142 onion_hash bs
    143   | BS.length bs == 32 = Just (OnionHash bs)
    144   | otherwise          = Nothing
    145 {-# INLINE onion_hash #-}
    146 
    147 -- | The bytes of an t'OnionHash'.
    148 un_onion_hash :: OnionHash -> BS.ByteString
    149 un_onion_hash (OnionHash bs) = bs
    150 {-# INLINE un_onion_hash #-}
    151 
    152 -- | The 920-byte @attribution_data@ of @update_fulfill_htlc@ and
    153 --   @update_fail_htlc@: twenty u32 HTLC hold times followed by 210
    154 --   four-byte truncated HMACs. Kept opaque (BOLT #4 defines its use).
    155 newtype AttributionData = AttributionData BS.ByteString
    156   deriving (Eq, Ord, Show, Generic)
    157 
    158 instance NFData AttributionData
    159 
    160 -- | Construct an t'AttributionData' from exactly 920 bytes.
    161 --
    162 --   >>> let bs = BS.replicate 920 0x00
    163 --   >>> fmap un_attribution_data (attribution_data bs) == Just bs
    164 --   True
    165 --   >>> attribution_data (BS.drop 1 bs)
    166 --   Nothing
    167 attribution_data :: BS.ByteString -> Maybe AttributionData
    168 attribution_data bs
    169   | BS.length bs == 920 = Just (AttributionData bs)
    170   | otherwise           = Nothing
    171 {-# INLINE attribution_data #-}
    172 
    173 -- | The bytes of an t'AttributionData'.
    174 un_attribution_data :: AttributionData -> BS.ByteString
    175 un_attribution_data (AttributionData bs) = bs
    176 {-# INLINE un_attribution_data #-}
    177 
    178 -- | The @fee_range@ of @closing_signed@: the fees the sender is
    179 --   prepared to pay for the closing transaction.
    180 data FeeRange = FeeRange
    181   { fee_range_min_fee_satoshis :: {-# UNPACK #-} !Satoshi
    182   , fee_range_max_fee_satoshis :: {-# UNPACK #-} !Satoshi
    183   } deriving (Eq, Show, Generic)
    184 
    185 instance NFData FeeRange
    186 
    187 -- | The @next_funding@ record of @channel_reestablish@: an interactive
    188 --   funding transaction whose signatures are still being exchanged.
    189 data NextFunding = NextFunding
    190   { next_funding_txid             :: !TxId
    191   , next_funding_retransmit_flags :: {-# UNPACK #-} !Word8
    192     -- ^ bit 0: the sender wants @commitment_signed@ retransmitted
    193   } deriving (Eq, Show, Generic)
    194 
    195 instance NFData NextFunding