Spend.hs (14064B)
1 {-# OPTIONS_HADDOCK hide #-} 2 {-# LANGUAGE BangPatterns #-} 3 4 -- | 5 -- Module: Lightning.Protocol.BOLT5.Spend 6 -- Copyright: (c) 2025 Jared Tobin 7 -- License: MIT 8 -- Maintainer: Jared Tobin <jared@ppad.tech> 9 -- 10 -- Spending transaction construction for BOLT #5 on-chain 11 -- transaction handling. 12 -- 13 -- All functions produce unsigned t'SpendingTx' values. The caller 14 -- signs (using the sighash metadata provided) and assembles the 15 -- witness with bolt3's witness functions. 16 17 module Lightning.Protocol.BOLT5.Spend ( 18 -- * Local commitment spends 19 spend_to_local 20 , spend_htlc_tx 21 , spend_htlc_output 22 23 -- * Remote commitment spends 24 , spend_remote_htlc_timeout 25 , spend_remote_htlc_preimage 26 27 -- * Revoked commitment spends 28 , spend_revoked_to_local 29 , spend_revoked_htlc 30 , spend_revoked_htlc_output 31 32 -- * Anchor spends 33 , spend_anchor_owner 34 , spend_anchor_anyone 35 ) where 36 37 import Bitcoin.Prim.Tx (OutPoint, Tx(..), TxIn(..), TxOut(..), Witness(..)) 38 import Bitcoin.Prim.Tx.Sighash (SighashType(..)) 39 import qualified Data.ByteString as BS 40 import Data.List.NonEmpty (NonEmpty(..)) 41 import Data.Word (Word32, Word64) 42 import Lightning.Protocol.BOLT1 (PaymentHash, Satoshi) 43 import qualified Lightning.Protocol.BOLT1 as BOLT1 44 import Lightning.Protocol.BOLT3 45 import Lightning.Protocol.BOLT5.Types 46 47 -- local commitment spends -------------------------------------------- 48 49 -- | Spend the to_local output of our local commitment tx. 50 -- 51 -- The input's nSequence is the to_self_delay, so the transaction 52 -- is valid only once the delay has passed. The caller signs with 53 -- the local delayed privkey and uses bolt3's 54 -- 'to_local_witness_spend'. 55 -- 56 -- Returns 'Nothing' if the fee would exceed the output value, or 57 -- leave an output below the destination's dust threshold. 58 spend_to_local 59 :: OutPoint 60 -- ^ Outpoint of the to_local output. 61 -> Satoshi 62 -- ^ Value of the to_local output. 63 -> RevocationPubkey 64 -> ToSelfDelay 65 -> LocalDelayedPubkey 66 -> Script 67 -- ^ Destination scriptPubKey. 68 -> FeeratePerKw 69 -> Maybe SpendingTx 70 spend_to_local !op !value !revpk delay@(ToSelfDelay d) !delayedpk 71 !dest !feerate = 72 sweep op value (to_local_script revpk delay delayedpk) 73 to_local_penalty_input_weight (fromIntegral d) 0 dest feerate 74 75 -- | Build the HTLC-timeout (for an offered HTLC) or HTLC-success 76 -- (for a received HTLC) transaction spending an HTLC output of 77 -- our local commitment, with bolt3's 'build_htlc_tx'. 78 -- 79 -- The sighash type is that of the local signature, which is 80 -- always @SIGHASH_ALL@. The remote's @htlc_signature@ uses bolt3's 81 -- 'remote_htlc_sighash' (@SIGHASH_SINGLE|SIGHASH_ANYONECANPAY@ 82 -- under 'Anchors'). The witness is bolt3's 'htlc_timeout_witness' 83 -- or 'htlc_success_witness'. 84 -- 85 -- Under 'Anchors' the transaction pays no fee; it must be 86 -- combined with other inputs before broadcast. 87 -- 88 -- Returns 'Nothing' if bolt3 can't build the transaction (the fee 89 -- exceeds the HTLC amount). 90 spend_htlc_tx 91 :: HTLCContext 92 -> CommitmentKeys 93 -- ^ Keys for our local commitment (for the witness script). 94 -> Maybe SpendingTx 95 spend_htlc_tx !ctx !keys = do 96 htx <- build_htlc_tx ctx 97 let !h = hc_htlc ctx 98 pure SpendingTx 99 { stx_tx = htlc_to_tx htx 100 , stx_input_script = htlc_script keys (hc_format ctx) h 101 , stx_input_value = BOLT1.msat_to_sat (htlc_amount_msat h) 102 , stx_sighash_type = SIGHASH_ALL 103 } 104 105 -- | Spend the output of an HTLC-timeout or HTLC-success 106 -- transaction after the CSV delay. 107 -- 108 -- The output uses the to_local script, so this is 109 -- 'spend_to_local'. The caller signs with the local delayed 110 -- privkey and uses bolt3's 'to_local_witness_spend'. 111 spend_htlc_output 112 :: OutPoint 113 -- ^ Outpoint of the second-stage output. 114 -> Satoshi 115 -- ^ Value of the second-stage output. 116 -> RevocationPubkey 117 -> ToSelfDelay 118 -> LocalDelayedPubkey 119 -> Script 120 -- ^ Destination scriptPubKey. 121 -> FeeratePerKw 122 -> Maybe SpendingTx 123 spend_htlc_output = spend_to_local 124 125 -- remote commitment spends ------------------------------------------- 126 127 -- | Spend an HTLC we offered directly, after it times out, from the 128 -- remote commitment (where it is a received HTLC). 129 -- 130 -- The locktime is the HTLC's CLTV expiry. The caller signs with 131 -- our HTLC privkey and uses bolt3's 132 -- 'received_htlc_witness_timeout'. 133 -- 134 -- Returns 'Nothing' if the fee would exceed the output value, or 135 -- leave an output below the destination's dust threshold. 136 spend_remote_htlc_timeout 137 :: OutPoint 138 -- ^ Outpoint of the HTLC output. 139 -> Satoshi 140 -- ^ Value of the HTLC output. 141 -> HTLC 142 -- ^ The HTLC being spent. 143 -> CommitmentKeys 144 -- ^ Keys for the remote commitment. 145 -> CommitmentFormat 146 -> Script 147 -- ^ Destination scriptPubKey. 148 -> FeeratePerKw 149 -> Maybe SpendingTx 150 spend_remote_htlc_timeout !op !value !htlc !keys !fmt !dest !feerate = 151 let expiry@(CltvExpiry e) = htlc_cltv_expiry htlc 152 !script = received_htlc_script (ck_revocation_pubkey keys) 153 (ck_remote_htlc keys) (ck_local_htlc keys) 154 (htlc_payment_hash htlc) expiry fmt 155 in sweep op value script 156 (htlc_output_type_weight fmt (HTLCReceivedOutput expiry)) 157 (remote_htlc_sequence fmt) e dest feerate 158 159 -- | Spend an HTLC we received directly with the preimage, from the 160 -- remote commitment (where it is an offered HTLC). 161 -- 162 -- The caller signs with our HTLC privkey and uses bolt3's 163 -- 'offered_htlc_witness_preimage'. 164 -- 165 -- Returns 'Nothing' if the fee would exceed the output value, or 166 -- leave an output below the destination's dust threshold. 167 spend_remote_htlc_preimage 168 :: OutPoint 169 -- ^ Outpoint of the HTLC output. 170 -> Satoshi 171 -- ^ Value of the HTLC output. 172 -> HTLC 173 -- ^ The HTLC being spent. 174 -> CommitmentKeys 175 -- ^ Keys for the remote commitment. 176 -> CommitmentFormat 177 -> Script 178 -- ^ Destination scriptPubKey. 179 -> FeeratePerKw 180 -> Maybe SpendingTx 181 spend_remote_htlc_preimage !op !value !htlc !keys !fmt !dest !feerate = 182 let !expiry = htlc_cltv_expiry htlc 183 !script = offered_htlc_script (ck_revocation_pubkey keys) 184 (ck_remote_htlc keys) (ck_local_htlc keys) 185 (htlc_payment_hash htlc) fmt 186 in sweep op value script 187 (htlc_output_type_weight fmt (HTLCOfferedOutput expiry)) 188 (remote_htlc_sequence fmt) 0 dest feerate 189 190 -- revoked commitment spends ------------------------------------------ 191 192 -- | Spend a revoked to_local output with the revocation key. 193 -- 194 -- The caller signs with the revocation privkey and uses bolt3's 195 -- 'to_local_witness_revoke'. 196 -- 197 -- Returns 'Nothing' if the fee would exceed the output value, or 198 -- leave an output below the destination's dust threshold. 199 spend_revoked_to_local 200 :: OutPoint 201 -- ^ Outpoint of the to_local output. 202 -> Satoshi 203 -- ^ Value of the to_local output. 204 -> RevocationPubkey 205 -> ToSelfDelay 206 -> LocalDelayedPubkey 207 -> Script 208 -- ^ Destination scriptPubKey. 209 -> FeeratePerKw 210 -> Maybe SpendingTx 211 spend_revoked_to_local !op !value !revpk !delay !delayedpk !dest 212 !feerate = 213 sweep op value (to_local_script revpk delay delayedpk) 214 to_local_penalty_input_weight 0xFFFFFFFF 0 dest feerate 215 216 -- | Spend a revoked HTLC output with the revocation key. 217 -- 218 -- The caller signs with the revocation privkey and uses bolt3's 219 -- 'offered_htlc_witness_revoke' or 'received_htlc_witness_revoke', 220 -- according to the output type. 221 -- 222 -- Returns 'Nothing' if the fee would exceed the output value, or 223 -- leave an output below the destination's dust threshold. 224 spend_revoked_htlc 225 :: OutPoint 226 -- ^ Outpoint of the HTLC output. 227 -> Satoshi 228 -- ^ Value of the HTLC output. 229 -> HTLCOutputType 230 -- ^ Whether offered or received HTLC. 231 -> RevocationPubkey 232 -> CommitmentKeys 233 -> CommitmentFormat 234 -> PaymentHash 235 -> Script 236 -- ^ Destination scriptPubKey. 237 -> FeeratePerKw 238 -> Maybe SpendingTx 239 spend_revoked_htlc !op !value !htype !revpk !keys !fmt !ph !dest 240 !feerate = 241 let !remote = ck_remote_htlc keys 242 !local = ck_local_htlc keys 243 !script = case htype of 244 HTLCOfferedOutput _ -> 245 offered_htlc_script revpk remote local ph fmt 246 HTLCReceivedOutput expiry -> 247 received_htlc_script revpk remote local ph expiry fmt 248 in sweep op value script (htlc_output_type_weight fmt htype) 249 0xFFFFFFFF 0 dest feerate 250 251 -- | Spend the output of a revoked HTLC-timeout or HTLC-success 252 -- transaction with the revocation key. 253 -- 254 -- The output uses the to_local script, so this is 255 -- 'spend_revoked_to_local'. The caller signs with the revocation 256 -- privkey and uses bolt3's 'to_local_witness_revoke'. 257 spend_revoked_htlc_output 258 :: OutPoint 259 -- ^ Outpoint of the second-stage output. 260 -> Satoshi 261 -- ^ Value of the second-stage output. 262 -> RevocationPubkey 263 -> ToSelfDelay 264 -> LocalDelayedPubkey 265 -> Script 266 -- ^ Destination scriptPubKey. 267 -> FeeratePerKw 268 -> Maybe SpendingTx 269 spend_revoked_htlc_output = spend_revoked_to_local 270 271 -- anchor spends ------------------------------------------------------ 272 273 -- | Spend an anchor output as its owner (immediately). 274 -- 275 -- The transaction pays no fee and has a single input: it must be 276 -- combined with other inputs before broadcast. The caller signs 277 -- with the funding privkey and uses bolt3's 278 -- 'anchor_witness_owner'. 279 spend_anchor_owner 280 :: OutPoint 281 -- ^ Outpoint of the anchor output. 282 -> Satoshi 283 -- ^ Value of the anchor output (330 sats). 284 -> FundingPubkey 285 -> Script 286 -- ^ Destination scriptPubKey. 287 -> SpendingTx 288 spend_anchor_owner !op !value !fundpk !dest = 289 SpendingTx (mk_spending_tx op 0xFFFFFFFE dest value 0) 290 (anchor_script fundpk) value SIGHASH_ALL 291 292 -- | Spend an anchor output as anyone (16 blocks after the 293 -- commitment confirms). 294 -- 295 -- As 'spend_anchor_owner', the transaction pays no fee. The 296 -- witness is bolt3's 'anchor_witness_anyone', which needs no 297 -- signature. 298 spend_anchor_anyone 299 :: OutPoint 300 -- ^ Outpoint of the anchor output. 301 -> Satoshi 302 -- ^ Value of the anchor output (330 sats). 303 -> FundingPubkey 304 -> Script 305 -- ^ Destination scriptPubKey. 306 -> SpendingTx 307 spend_anchor_anyone !op !value !fundpk !dest = 308 SpendingTx (mk_spending_tx op 16 dest value 0) 309 (anchor_script fundpk) value SIGHASH_ALL 310 311 -- internal helpers --------------------------------------------------- 312 313 -- | A single-input, single-output sweep paying the input value, less 314 -- the fee for the given input weight, to the destination. 315 sweep 316 :: OutPoint 317 -> Satoshi -- ^ input value 318 -> Script -- ^ input witness script 319 -> Word64 -- ^ input weight 320 -> Word32 -- ^ input nSequence 321 -> Word32 -- ^ locktime 322 -> Script -- ^ destination scriptPubKey 323 -> FeeratePerKw 324 -> Maybe SpendingTx 325 sweep !op !value !script !weight !sq !locktime !dest !feerate = do 326 let !fee = spending_fee feerate (weight + penalty_tx_base_weight) 327 out <- sweep_value value fee dest 328 pure (SpendingTx (mk_spending_tx op sq dest out locktime) script 329 value SIGHASH_ALL) 330 331 -- | Value of a sweep's single output: the input value less the fee. 332 -- 333 -- 'Nothing' if the fee exceeds the input value, or if the output 334 -- would be below the dust threshold of its script. 335 sweep_value :: Satoshi -> Satoshi -> Script -> Maybe Satoshi 336 sweep_value !value !fee (Script dest) = do 337 out <- BOLT1.sub_sat value fee 338 if BOLT1.un_satoshi out < dust_threshold dest 339 then Nothing 340 else Just out 341 342 -- | Dust threshold, in satoshis, for an output paying to a script. 343 -- 344 -- As Bitcoin Core computes it for spendable outputs at the default 345 -- dust relay feerate of 3 sat/vbyte: three times the size of the 346 -- output plus that of an input spending it (67 vbytes for a 347 -- witness program, 148 otherwise). This gives 546 sats for P2PKH, 348 -- 540 for P2SH, 294 for P2WPKH, and 330 for P2WSH and P2TR. 349 dust_threshold :: BS.ByteString -> Word64 350 dust_threshold s = 351 let !len = fromIntegral (BS.length s) :: Word64 352 !len_size 353 | len < 0xfd = 1 354 | len <= 0xffff = 3 355 | otherwise = 5 356 !spend_size = if is_witness_program s then 67 else 148 357 in 3 * (8 + len_size + len + spend_size) 358 359 -- | Whether a script is a segwit witness program: a version opcode 360 -- (OP_0 or OP_1 to OP_16) followed by a single 2-40 byte push. 361 is_witness_program :: BS.ByteString -> Bool 362 is_witness_program s = case BS.unpack (BS.take 2 s) of 363 [version, push_len] -> 364 (version == 0x00 || (version >= 0x51 && version <= 0x60)) 365 && push_len >= 2 && push_len <= 40 366 && fromIntegral push_len + 2 == BS.length s 367 _ -> False 368 369 -- | The nSequence of a direct HTLC spend from the remote commitment: 370 -- 1 under 'Anchors' (for the HTLC scripts' CSV), 0 otherwise. 371 remote_htlc_sequence :: CommitmentFormat -> Word32 372 remote_htlc_sequence fmt = case fmt of 373 StaticRemotekey -> 0 374 Anchors -> 1 375 376 -- | The witness script of an HTLC output of a commitment with the 377 -- given keys. 378 htlc_script :: CommitmentKeys -> CommitmentFormat -> HTLC -> Script 379 htlc_script !keys !fmt !h = 380 let !revpk = ck_revocation_pubkey keys 381 !remote = ck_remote_htlc keys 382 !local = ck_local_htlc keys 383 !ph = htlc_payment_hash h 384 in case htlc_direction h of 385 HTLCOffered -> offered_htlc_script revpk remote local ph fmt 386 HTLCReceived -> 387 received_htlc_script revpk remote local ph 388 (htlc_cltv_expiry h) fmt 389 390 -- | Build a version 2, single-input, single-output transaction. 391 mk_spending_tx 392 :: OutPoint -- ^ input outpoint 393 -> Word32 -- ^ input nSequence 394 -> Script -- ^ output scriptPubKey 395 -> Satoshi -- ^ output value 396 -> Word32 -- ^ locktime 397 -> Tx 398 mk_spending_tx !op !sq (Script dest) !value !locktime = Tx 399 { tx_version = 2 400 , tx_inputs = TxIn 401 { txin_prevout = op 402 , txin_script_sig = BS.empty 403 , txin_sequence = sq 404 , txin_witness = Witness [] 405 } :| [] 406 , tx_outputs = TxOut 407 { txout_value = BOLT1.un_satoshi value 408 , txout_script_pubkey = dest 409 } :| [] 410 , tx_locktime = locktime 411 }