bolt5

On-chain transaction handling for Lightning (docs.ppad.tech/bolt5).
git clone git://git.ppad.tech/bolt5.git
Log | Files | Refs | README | LICENSE

Types.hs (8759B)


      1 {-# OPTIONS_HADDOCK prune #-}
      2 {-# LANGUAGE BangPatterns #-}
      3 {-# LANGUAGE DeriveGeneric #-}
      4 
      5 -- |
      6 -- Module: Lightning.Protocol.BOLT5.Types
      7 -- Copyright: (c) 2025 Jared Tobin
      8 -- License: MIT
      9 -- Maintainer: Jared Tobin <jared@ppad.tech>
     10 --
     11 -- Types for BOLT #5 on-chain transaction handling.
     12 
     13 module Lightning.Protocol.BOLT5.Types (
     14     -- * Close identification
     15     CloseType(..)
     16 
     17     -- * Output classification
     18   , UnresolvedOutput(..)
     19   , OutputResolution(..)
     20 
     21     -- * HTLC output type
     22   , HTLCOutputType(..)
     23   , htlcOutputType
     24   , htlcOutputTypeWeight
     25 
     26     -- * Spending transactions
     27   , SpendingTx(..)
     28 
     29     -- * Penalty batching
     30   , RevokedOutput(..)
     31   , RevokedOutputType(..)
     32   , PenaltyContext(..)
     33   , revoked_output_weight
     34 
     35     -- * Weight constants (Appendix A)
     36   , to_local_penalty_witness_weight
     37   , offered_htlc_penalty_witness_weight
     38   , accepted_htlc_penalty_witness_weight
     39   , to_local_penalty_input_weight
     40   , offered_htlc_penalty_input_weight
     41   , accepted_htlc_penalty_input_weight
     42   , to_remote_input_weight
     43   , penalty_tx_base_weight
     44   , max_standard_weight
     45 
     46     -- * Fee calculation
     47   , spending_fee
     48   ) where
     49 
     50 import Bitcoin.Prim.Tx (Tx(..))
     51 import Bitcoin.Prim.Tx.Sighash (SighashType(..))
     52 import Data.List.NonEmpty (NonEmpty)
     53 import Data.Word (Word64)
     54 import GHC.Generics (Generic)
     55 import Lightning.Protocol.BOLT3.Types
     56 import Lightning.Protocol.BOLT3.Tx (
     57     CommitmentKeys(..)
     58   , OutputType(..)
     59   )
     60 
     61 -- close identification -----------------------------------------------
     62 
     63 -- | What kind of close was detected on chain.
     64 data CloseType
     65   = MutualClose
     66     -- ^ Cooperative closure agreed by both parties.
     67   | LocalCommitClose
     68     -- ^ Our commitment transaction was broadcast.
     69   | RemoteCommitClose
     70     -- ^ The remote party's commitment transaction was broadcast.
     71   | RevokedCommitClose
     72     -- ^ A revoked (outdated) commitment transaction was broadcast.
     73   deriving (Eq, Show, Generic)
     74 
     75 -- output classification ----------------------------------------------
     76 
     77 -- | An unresolved commitment transaction output.
     78 data UnresolvedOutput = UnresolvedOutput
     79   { uo_outpoint :: !OutPoint
     80   , uo_value    :: {-# UNPACK #-} !Satoshi
     81   , uo_type     :: !OutputResolution
     82   } deriving (Eq, Show, Generic)
     83 
     84 -- | How to resolve an output, per BOLT #5 rules.
     85 data OutputResolution
     86   = Resolved
     87     -- ^ Already resolved (e.g. to_remote on local commit).
     88   | SpendToLocal
     89       !ToSelfDelay !RevocationPubkey !LocalDelayedPubkey
     90     -- ^ Spend to_local after CSV delay.
     91   | SpendHTLCTimeout
     92       !HTLC !CommitmentKeys !ChannelFeatures
     93     -- ^ Spend via HTLC-timeout second-stage tx (local commit,
     94     --   local offer).
     95   | SpendHTLCSuccess
     96       !HTLC !CommitmentKeys !ChannelFeatures
     97     -- ^ Spend via HTLC-success second-stage tx (local commit,
     98     --   remote offer).
     99   | SpendHTLCTimeoutDirect !HTLC
    100     -- ^ Spend HTLC directly after timeout (remote commit,
    101     --   local offer).
    102   | SpendHTLCPreimageDirect !HTLC
    103     -- ^ Spend HTLC directly with preimage (remote commit,
    104     --   remote offer).
    105   | Revoke !RevocationPubkey
    106     -- ^ Spend revoked to_local with revocation key.
    107   | RevokeHTLC !RevocationPubkey !HTLCOutputType
    108     -- ^ Spend revoked HTLC output with revocation key.
    109   | AnchorSpend !FundingPubkey
    110     -- ^ Spend anchor output.
    111   deriving (Eq, Show, Generic)
    112 
    113 -- HTLC output type -------------------------------------------------
    114 
    115 -- | Type of HTLC output, restricted to only HTLC variants.
    116 --
    117 -- Unlike bolt3's 'OutputType' which includes all six output
    118 -- types, this ADT makes it impossible to confuse HTLC outputs
    119 -- with to_local, to_remote, or anchor outputs.
    120 data HTLCOutputType
    121   = HTLCOfferedOutput {-# UNPACK #-} !CltvExpiry
    122     -- ^ Offered HTLC output with CLTV expiry.
    123   | HTLCReceivedOutput {-# UNPACK #-} !CltvExpiry
    124     -- ^ Received HTLC output with CLTV expiry.
    125   deriving (Eq, Show, Generic)
    126 
    127 -- | Extract an 'HTLCOutputType' from a bolt3 'OutputType'.
    128 --
    129 -- Returns 'Nothing' for non-HTLC output types.
    130 --
    131 -- >>> htlcOutputType (OutputOfferedHTLC (CltvExpiry 500))
    132 -- Just (HTLCOfferedOutput (CltvExpiry ...))
    133 -- >>> htlcOutputType OutputToLocal
    134 -- Nothing
    135 htlcOutputType :: OutputType -> Maybe HTLCOutputType
    136 htlcOutputType (OutputOfferedHTLC e) =
    137   Just (HTLCOfferedOutput e)
    138 htlcOutputType (OutputReceivedHTLC e) =
    139   Just (HTLCReceivedOutput e)
    140 htlcOutputType _ = Nothing
    141 {-# INLINE htlcOutputType #-}
    142 
    143 -- | Penalty input weight for an HTLC output type.
    144 htlcOutputTypeWeight :: HTLCOutputType -> Word64
    145 htlcOutputTypeWeight (HTLCOfferedOutput _) =
    146   offered_htlc_penalty_input_weight
    147 htlcOutputTypeWeight (HTLCReceivedOutput _) =
    148   accepted_htlc_penalty_input_weight
    149 {-# INLINE htlcOutputTypeWeight #-}
    150 
    151 -- spending transactions ----------------------------------------------
    152 
    153 -- | Unsigned spending transaction, ready for caller to sign.
    154 --
    155 -- The caller uses bolt3 witness constructors to assemble the
    156 -- final witness after signing.
    157 data SpendingTx = SpendingTx
    158   { stx_tx           :: !Tx
    159     -- ^ The unsigned transaction.
    160   , stx_input_script :: !Script
    161     -- ^ Witness script for the input being spent.
    162   , stx_input_value  :: {-# UNPACK #-} !Satoshi
    163     -- ^ Value of the input being spent (for sighash).
    164   , stx_sighash_type :: !SighashType
    165     -- ^ Sighash type to use when signing.
    166   } deriving (Eq, Show, Generic)
    167 
    168 -- penalty batching ---------------------------------------------------
    169 
    170 -- | A revoked output that can be swept with a revocation key.
    171 --
    172 -- This type restricts penalty transaction inputs to only
    173 -- valid revocation targets: to_local outputs and HTLC outputs.
    174 -- Other output types (to_remote, anchors) cannot appear in
    175 -- penalty transactions.
    176 data RevokedOutput = RevokedOutput
    177   { ro_outpoint :: !OutPoint
    178   , ro_value    :: {-# UNPACK #-} !Satoshi
    179   , ro_type     :: !RevokedOutputType
    180   } deriving (Eq, Show, Generic)
    181 
    182 -- | What kind of revoked output is being swept.
    183 data RevokedOutputType
    184   = RevokedToLocal
    185     -- ^ Revoked to_local output.
    186   | RevokedHTLC !HTLCOutputType
    187     -- ^ Revoked HTLC output.
    188   deriving (Eq, Show, Generic)
    189 
    190 -- | Penalty input weight for a revoked output.
    191 revoked_output_weight :: RevokedOutput -> Word64
    192 revoked_output_weight !ro = case ro_type ro of
    193   RevokedToLocal ->
    194     to_local_penalty_input_weight
    195   RevokedHTLC !htype ->
    196     htlcOutputTypeWeight htype
    197 {-# INLINE revoked_output_weight #-}
    198 
    199 -- | Context for constructing batched penalty transactions.
    200 data PenaltyContext = PenaltyContext
    201   { pc_outputs        :: !(NonEmpty RevokedOutput)
    202     -- ^ Revoked outputs to sweep (must be non-empty).
    203   , pc_revocation_key :: !RevocationPubkey
    204     -- ^ Revocation pubkey for all outputs.
    205   , pc_destination    :: !Script
    206     -- ^ Destination scriptPubKey.
    207   , pc_feerate        :: !FeeratePerKw
    208     -- ^ Fee rate for the penalty transaction.
    209   } deriving (Eq, Show, Generic)
    210 
    211 -- weight constants (BOLT #5 Appendix A) ------------------------------
    212 
    213 -- | Expected weight of the to_local penalty transaction witness
    214 --   (160 bytes).
    215 to_local_penalty_witness_weight :: Word64
    216 to_local_penalty_witness_weight = 160
    217 
    218 -- | Expected weight of the offered_htlc penalty transaction
    219 --   witness (243 bytes).
    220 offered_htlc_penalty_witness_weight :: Word64
    221 offered_htlc_penalty_witness_weight = 243
    222 
    223 -- | Expected weight of the accepted_htlc penalty transaction
    224 --   witness (249 bytes).
    225 accepted_htlc_penalty_witness_weight :: Word64
    226 accepted_htlc_penalty_witness_weight = 249
    227 
    228 -- | Weight of a to_local penalty input (164 + 160 = 324 bytes).
    229 to_local_penalty_input_weight :: Word64
    230 to_local_penalty_input_weight = 324
    231 
    232 -- | Weight of an offered_htlc penalty input
    233 --   (164 + 243 = 407 bytes).
    234 offered_htlc_penalty_input_weight :: Word64
    235 offered_htlc_penalty_input_weight = 407
    236 
    237 -- | Weight of an accepted_htlc penalty input
    238 --   (164 + 249 = 413 bytes).
    239 accepted_htlc_penalty_input_weight :: Word64
    240 accepted_htlc_penalty_input_weight = 413
    241 
    242 -- | Weight of a to_remote P2WPKH input
    243 --   (108 + 164 = 272 bytes).
    244 to_remote_input_weight :: Word64
    245 to_remote_input_weight = 272
    246 
    247 -- | Base weight of a penalty transaction (4*53 + 2 = 214 bytes).
    248 --
    249 -- Non-witness: version(4) + input_count(1) + output_count(1) +
    250 -- value(8) + script_len(1) + p2wsh_script(34) + locktime(4) = 53
    251 -- Witness header: 2 bytes.
    252 penalty_tx_base_weight :: Word64
    253 penalty_tx_base_weight = 214
    254 
    255 -- | Maximum standard transaction weight (400,000 bytes).
    256 max_standard_weight :: Word64
    257 max_standard_weight = 400000
    258 
    259 -- fee calculation ----------------------------------------------------
    260 
    261 -- | Calculate the fee for a spending transaction given its weight.
    262 --
    263 -- @fee = feerate_per_kw * weight / 1000@
    264 spending_fee :: FeeratePerKw -> Word64 -> Satoshi
    265 spending_fee (FeeratePerKw !rate) !weight =
    266   Satoshi ((fromIntegral rate * weight) `div` 1000)
    267 {-# INLINE spending_fee #-}