bolt3

Lightning transaction and script formats, per BOLT #3 (docs.ppad.tech/bolt3).
git clone git://git.ppad.tech/bolt3.git
Log | Files | Refs | README | LICENSE

Types.hs (11505B)


      1 {-# OPTIONS_HADDOCK hide #-}
      2 {-# LANGUAGE BangPatterns #-}
      3 {-# LANGUAGE DeriveGeneric #-}
      4 
      5 -- |
      6 -- Module: Lightning.Protocol.BOLT3.Types
      7 -- Copyright: (c) 2025 Jared Tobin
      8 -- License: MIT
      9 -- Maintainer: Jared Tobin <jared@ppad.tech>
     10 --
     11 -- Types for BOLT #3 transaction and script formats.
     12 
     13 module Lightning.Protocol.BOLT3.Types (
     14     -- * Points and keys
     15     PerCommitmentPoint(..)
     16   , RevocationBasepoint(..)
     17   , PaymentBasepoint(..)
     18   , DelayedPaymentBasepoint(..)
     19   , HtlcBasepoint(..)
     20   , Basepoints(..)
     21   , RevocationPubkey(..)
     22   , LocalDelayedPubkey(..)
     23   , LocalHtlcPubkey(..)
     24   , RemoteHtlcPubkey(..)
     25   , RemotePubkey(..)
     26   , FundingPubkey(..)
     27   , Seckey(..)
     28   , seckey
     29   , un_seckey
     30 
     31     -- * Per-commitment secrets
     32   , Seed(..)
     33   , seed
     34   , un_seed
     35   , SecretIndex(..)
     36   , secret_index
     37   , un_secret_index
     38   , commitment_secret_index
     39 
     40     -- * Channel parameters
     41   , CommitmentNumber(..)
     42   , commitment_number
     43   , un_commitment_number
     44   , next_commitment_number
     45   , ToSelfDelay(..)
     46   , CltvExpiry(..)
     47   , DustLimit(..)
     48   , FeeratePerKw(..)
     49   , Locktime(..)
     50   , Sequence(..)
     51   , CommitmentFormat(..)
     52 
     53     -- * HTLCs
     54   , HTLC(..)
     55   , HTLCDirection(..)
     56 
     57     -- * Scripts
     58   , Script(..)
     59 
     60     -- * Dust thresholds
     61   , dust_p2pkh
     62   , dust_p2sh
     63   , dust_p2wpkh
     64   , dust_p2wsh
     65   , anchor_output_value
     66 
     67     -- * Internal
     68   , sat
     69   , internal_error
     70   ) where
     71 
     72 import Control.DeepSeq (NFData(..))
     73 import qualified Crypto.Curve.Secp256k1 as S
     74 import qualified Data.ByteString as BS
     75 import Data.Word (Word16, Word32, Word64)
     76 import GHC.Generics (Generic)
     77 import Lightning.Protocol.BOLT1 (Point, Satoshi, MilliSatoshi, PaymentHash)
     78 import qualified Lightning.Protocol.BOLT1 as BOLT1
     79 
     80 -- internal ------------------------------------------------------------------
     81 
     82 -- Abort on a state that the surrounding code rules out.
     83 internal_error :: a
     84 internal_error = error "ppad-bolt3: internal error, please report a bug!"
     85 {-# NOINLINE internal_error #-}
     86 
     87 -- A 'Satoshi' amount known to be at most 21 million BTC (a constant,
     88 -- or a value bounded by construction).
     89 sat :: Word64 -> Satoshi
     90 sat w = case BOLT1.satoshi w of
     91   Just s  -> s
     92   Nothing -> internal_error
     93 {-# INLINE sat #-}
     94 
     95 -- points and keys ------------------------------------------------------------
     96 
     97 -- | A per-commitment point, from which a commitment's keys are
     98 --   derived.
     99 newtype PerCommitmentPoint = PerCommitmentPoint Point
    100   deriving (Eq, Ord, Show, Generic)
    101 
    102 instance NFData PerCommitmentPoint
    103 
    104 -- | A @revocation_basepoint@.
    105 newtype RevocationBasepoint = RevocationBasepoint Point
    106   deriving (Eq, Ord, Show, Generic)
    107 
    108 instance NFData RevocationBasepoint
    109 
    110 -- | A @payment_basepoint@.
    111 newtype PaymentBasepoint = PaymentBasepoint Point
    112   deriving (Eq, Ord, Show, Generic)
    113 
    114 instance NFData PaymentBasepoint
    115 
    116 -- | A @delayed_payment_basepoint@.
    117 newtype DelayedPaymentBasepoint = DelayedPaymentBasepoint Point
    118   deriving (Eq, Ord, Show, Generic)
    119 
    120 instance NFData DelayedPaymentBasepoint
    121 
    122 -- | An @htlc_basepoint@.
    123 newtype HtlcBasepoint = HtlcBasepoint Point
    124   deriving (Eq, Ord, Show, Generic)
    125 
    126 instance NFData HtlcBasepoint
    127 
    128 -- | The four basepoints a party announces in @open_channel@ or
    129 --   @accept_channel@.
    130 data Basepoints = Basepoints
    131   { bp_revocation      :: !RevocationBasepoint
    132   , bp_payment         :: !PaymentBasepoint
    133   , bp_delayed_payment :: !DelayedPaymentBasepoint
    134   , bp_htlc            :: !HtlcBasepoint
    135   } deriving (Eq, Show, Generic)
    136 
    137 instance NFData Basepoints
    138 
    139 -- | A commitment's @revocationpubkey@.
    140 newtype RevocationPubkey = RevocationPubkey Point
    141   deriving (Eq, Ord, Show, Generic)
    142 
    143 instance NFData RevocationPubkey
    144 
    145 -- | A commitment's @local_delayedpubkey@: the owner's key for its
    146 --   delayed outputs.
    147 newtype LocalDelayedPubkey = LocalDelayedPubkey Point
    148   deriving (Eq, Ord, Show, Generic)
    149 
    150 instance NFData LocalDelayedPubkey
    151 
    152 -- | A commitment's @local_htlcpubkey@: the owner's HTLC key.
    153 newtype LocalHtlcPubkey = LocalHtlcPubkey Point
    154   deriving (Eq, Ord, Show, Generic)
    155 
    156 instance NFData LocalHtlcPubkey
    157 
    158 -- | A commitment's @remote_htlcpubkey@: the other party's HTLC key.
    159 newtype RemoteHtlcPubkey = RemoteHtlcPubkey Point
    160   deriving (Eq, Ord, Show, Generic)
    161 
    162 instance NFData RemoteHtlcPubkey
    163 
    164 -- | A commitment's @remotepubkey@: the other party's
    165 --   @payment_basepoint@, which its @to_remote@ output pays.
    166 newtype RemotePubkey = RemotePubkey Point
    167   deriving (Eq, Ord, Show, Generic)
    168 
    169 instance NFData RemotePubkey
    170 
    171 -- | A @funding_pubkey@.
    172 newtype FundingPubkey = FundingPubkey Point
    173   deriving (Eq, Ord, Show, Generic)
    174 
    175 instance NFData FundingPubkey
    176 
    177 -- | A secp256k1 secret key: 32 bytes encoding an integer in
    178 --   [1, n), for n the group order.
    179 --
    180 --   This is secret material: its 'Show' instance is redacted, and it
    181 --   has no 'Eq' instance.
    182 newtype Seckey = Seckey BS.ByteString
    183 
    184 instance Show Seckey where
    185   showsPrec d _ = showParen (d > 10) $ showString "Seckey <redacted>"
    186 
    187 instance NFData Seckey where
    188   rnf (Seckey bs) = rnf bs
    189 
    190 -- | Construct a 'Seckey' from 32 big-endian bytes. Fails unless the
    191 --   bytes encode an integer in [1, n).
    192 --
    193 --   >>> fmap (BS.length . un_seckey) (seckey (BS.replicate 32 0x01))
    194 --   Just 32
    195 --   >>> seckey (BS.replicate 32 0x00)
    196 --   Nothing
    197 --   >>> seckey (BS.replicate 32 0xff)
    198 --   Nothing
    199 seckey :: BS.ByteString -> Maybe Seckey
    200 seckey bs = do
    201   w <- S.parse_int256 bs
    202   if   S.ge w
    203   then Just (Seckey bs)
    204   else Nothing
    205 
    206 -- | The bytes of a 'Seckey'.
    207 un_seckey :: Seckey -> BS.ByteString
    208 un_seckey (Seckey bs) = bs
    209 {-# INLINE un_seckey #-}
    210 
    211 -- per-commitment secrets -----------------------------------------------------
    212 
    213 -- | The 32-byte seed from which a party generates its per-commitment
    214 --   secrets.
    215 --
    216 --   This is secret material: its 'Show' instance is redacted, and it
    217 --   has no 'Eq' instance.
    218 newtype Seed = Seed BS.ByteString
    219 
    220 instance Show Seed where
    221   showsPrec d _ = showParen (d > 10) $ showString "Seed <redacted>"
    222 
    223 instance NFData Seed where
    224   rnf (Seed bs) = rnf bs
    225 
    226 -- | Construct a 'Seed' from exactly 32 bytes.
    227 --
    228 --   >>> fmap (BS.length . un_seed) (seed (BS.replicate 32 0xff))
    229 --   Just 32
    230 --   >>> seed (BS.replicate 31 0xff)
    231 --   Nothing
    232 seed :: BS.ByteString -> Maybe Seed
    233 seed bs
    234   | BS.length bs == 32 = Just (Seed bs)
    235   | otherwise          = Nothing
    236 {-# INLINE seed #-}
    237 
    238 -- | The bytes of a 'Seed'.
    239 un_seed :: Seed -> BS.ByteString
    240 un_seed (Seed bs) = bs
    241 {-# INLINE un_seed #-}
    242 
    243 -- | The 48-bit index /I/ of a per-commitment secret. Secrets are
    244 --   used from index 2^48 - 1 downwards.
    245 newtype SecretIndex = SecretIndex Word64
    246   deriving (Eq, Ord, Show, Generic)
    247 
    248 instance NFData SecretIndex
    249 
    250 -- | Construct a 'SecretIndex'. Fails at or above 2^48.
    251 --
    252 --   >>> secret_index 281474976710655
    253 --   Just (SecretIndex 281474976710655)
    254 --   >>> secret_index 281474976710656
    255 --   Nothing
    256 secret_index :: Word64 -> Maybe SecretIndex
    257 secret_index w
    258   | w <= 0xFFFFFFFFFFFF = Just (SecretIndex w)
    259   | otherwise           = Nothing
    260 {-# INLINE secret_index #-}
    261 
    262 -- | The value of a 'SecretIndex'.
    263 un_secret_index :: SecretIndex -> Word64
    264 un_secret_index (SecretIndex w) = w
    265 {-# INLINE un_secret_index #-}
    266 
    267 -- | The index of the per-commitment secret for a commitment number:
    268 --   2^48 - 1 - n.
    269 --
    270 --   >>> fmap commitment_secret_index (commitment_number 0)
    271 --   Just (SecretIndex 281474976710655)
    272 commitment_secret_index :: CommitmentNumber -> SecretIndex
    273 commitment_secret_index (CommitmentNumber n) = SecretIndex (0xFFFFFFFFFFFF - n)
    274 {-# INLINE commitment_secret_index #-}
    275 
    276 -- channel parameters ---------------------------------------------------------
    277 
    278 -- | A 48-bit commitment number.
    279 newtype CommitmentNumber = CommitmentNumber Word64
    280   deriving (Eq, Ord, Show, Generic)
    281 
    282 instance NFData CommitmentNumber
    283 
    284 -- | Construct a 'CommitmentNumber'. Fails at or above 2^48.
    285 --
    286 --   >>> commitment_number 42
    287 --   Just (CommitmentNumber 42)
    288 --   >>> commitment_number 281474976710656
    289 --   Nothing
    290 commitment_number :: Word64 -> Maybe CommitmentNumber
    291 commitment_number n
    292   | n <= 0xFFFFFFFFFFFF = Just (CommitmentNumber n)
    293   | otherwise           = Nothing
    294 {-# INLINE commitment_number #-}
    295 
    296 -- | The value of a 'CommitmentNumber'.
    297 un_commitment_number :: CommitmentNumber -> Word64
    298 un_commitment_number (CommitmentNumber n) = n
    299 {-# INLINE un_commitment_number #-}
    300 
    301 -- | The next commitment number. Fails past 2^48 - 1.
    302 --
    303 --   >>> commitment_number 0 >>= next_commitment_number
    304 --   Just (CommitmentNumber 1)
    305 --   >>> commitment_number 281474976710655 >>= next_commitment_number
    306 --   Nothing
    307 next_commitment_number :: CommitmentNumber -> Maybe CommitmentNumber
    308 next_commitment_number (CommitmentNumber n)
    309   | n < 0xFFFFFFFFFFFF = Just (CommitmentNumber (n + 1))
    310   | otherwise          = Nothing
    311 {-# INLINE next_commitment_number #-}
    312 
    313 -- | The CSV delay (@to_self_delay@) on a commitment owner's outputs.
    314 newtype ToSelfDelay = ToSelfDelay Word16
    315   deriving (Eq, Ord, Show, Generic)
    316 
    317 instance NFData ToSelfDelay
    318 
    319 -- | An HTLC's absolute CLTV expiry.
    320 newtype CltvExpiry = CltvExpiry Word32
    321   deriving (Eq, Ord, Show, Generic)
    322 
    323 instance NFData CltvExpiry
    324 
    325 -- | A @dust_limit_satoshis@ threshold.
    326 newtype DustLimit = DustLimit Satoshi
    327   deriving (Eq, Ord, Show, Generic)
    328 
    329 instance NFData DustLimit
    330 
    331 -- | A fee rate, in satoshis per 1000 weight units.
    332 newtype FeeratePerKw = FeeratePerKw Word32
    333   deriving (Eq, Ord, Show, Generic)
    334 
    335 instance NFData FeeratePerKw
    336 
    337 -- | A transaction locktime.
    338 newtype Locktime = Locktime Word32
    339   deriving (Eq, Ord, Show, Generic)
    340 
    341 instance NFData Locktime
    342 
    343 -- | A transaction input's sequence number.
    344 newtype Sequence = Sequence Word32
    345   deriving (Eq, Ord, Show, Generic)
    346 
    347 instance NFData Sequence
    348 
    349 -- | The commitment format a channel uses, as fixed by its
    350 --   @channel_type@.
    351 data CommitmentFormat
    352   = StaticRemotekey
    353     -- ^ @option_static_remotekey@ without anchors: @to_remote@ is
    354     --   P2WPKH and HTLC transactions pay their own fees.
    355   | Anchors
    356     -- ^ @option_anchors@: two anchor outputs, a CSV-locked
    357     --   @to_remote@, and zero-fee HTLC transactions.
    358   deriving (Eq, Ord, Show, Generic)
    359 
    360 instance NFData CommitmentFormat
    361 
    362 -- HTLCs ----------------------------------------------------------------------
    363 
    364 -- | The direction of an HTLC, from the commitment owner's point of
    365 --   view.
    366 data HTLCDirection
    367   = HTLCOffered   -- ^ offered by the owner
    368   | HTLCReceived  -- ^ received by the owner
    369   deriving (Eq, Ord, Show, Generic)
    370 
    371 instance NFData HTLCDirection
    372 
    373 -- | An HTLC committed to a commitment transaction.
    374 data HTLC = HTLC
    375   { htlc_direction    :: !HTLCDirection
    376   , htlc_amount_msat  :: {-# UNPACK #-} !MilliSatoshi
    377   , htlc_payment_hash :: !PaymentHash
    378   , htlc_cltv_expiry  :: {-# UNPACK #-} !CltvExpiry
    379   } deriving (Eq, Show, Generic)
    380 
    381 instance NFData HTLC
    382 
    383 -- scripts --------------------------------------------------------------------
    384 
    385 -- | A serialized Bitcoin script.
    386 newtype Script = Script BS.ByteString
    387   deriving (Eq, Ord, Show, Generic)
    388 
    389 instance NFData Script
    390 
    391 -- dust thresholds ------------------------------------------------------------
    392 
    393 -- | Bitcoin Core's P2PKH dust threshold (546 satoshis).
    394 dust_p2pkh :: Satoshi
    395 dust_p2pkh = sat 546
    396 
    397 -- | Bitcoin Core's P2SH dust threshold (540 satoshis).
    398 dust_p2sh :: Satoshi
    399 dust_p2sh = sat 540
    400 
    401 -- | Bitcoin Core's P2WPKH dust threshold (294 satoshis).
    402 dust_p2wpkh :: Satoshi
    403 dust_p2wpkh = sat 294
    404 
    405 -- | Bitcoin Core's P2WSH dust threshold (330 satoshis).
    406 dust_p2wsh :: Satoshi
    407 dust_p2wsh = sat 330
    408 
    409 -- | The value of each anchor output (330 satoshis).
    410 anchor_output_value :: Satoshi
    411 anchor_output_value = sat 330