README.md (5654B)
1 # ppad-bolt5 2 3 [](https://hackage.haskell.org/package/ppad-bolt5) 4  5 [](https://docs.ppad.tech/bolt5) 6 7 A pure Haskell implementation of parts of [BOLT #5][bolt5], the 8 Lightning Network's rules for handling channel closes on chain. 9 10 ## Status 11 12 **This library's scope is being redesigned, and it is not yet ready for 13 release.** Its API will change. 14 15 What it does: 16 17 * Identifies our local or the remote's current commitment on chain, by 18 txid. 19 * Classifies the outputs of local, remote and revoked commitment 20 transactions built by [ppad-bolt3][bolt3], reading each HTLC output's 21 HTLC from bolt3. 22 * Extracts payment preimages from the witnesses of remote preimage 23 claims and HTLC-success transactions, checking them against the 24 payment hash. 25 * Builds unsigned, single-input spending transactions: to_local sweeps 26 (delayed and revoked), HTLC-timeout and HTLC-success transactions 27 (via bolt3), direct HTLC spends from the remote commitment, revoked 28 HTLC sweeps, second-stage output sweeps and anchor spends. Sweeps 29 refuse to create outputs below the destination's dust threshold. 30 * Provides the BOLT #5 Appendix A weights and fee calculation. 31 32 What it doesn't do (known gaps): 33 34 * Per-input signing data. A spending transaction describes one input 35 and the local signature only; there is no batched penalty 36 transaction. 37 * Witness assembly. The caller signs and builds every witness with 38 bolt3's witness functions. 39 * Classification of raw on-chain transactions. The classifiers take the 40 bolt3 commitment transaction for the state in question, which the 41 caller must rebuild (often impossible for a revoked state). 42 * Revoked and mutual close detection. Only the current local and 43 remote commitments are recognised, and the resolutions for a revoked 44 commitment lack what's needed to build its spends (to_self_delay, 45 delayed pubkey, payment hashes). 46 * Fee bumping. Anchor spends and anchor-channel HTLC transactions pay 47 no fee and can't take fee inputs, and penalty sweeps don't signal 48 replace-by-fee. 49 * `zero_fee_commitments` (version 3 transactions and the shared P2A 50 anchor), and spending the anchor-channel to_remote output. 51 52 ## Usage 53 54 A sample GHCi session: 55 56 ``` 57 > :set -XOverloadedStrings 58 > import qualified Bitcoin.Prim.Tx as BT 59 > import qualified Crypto.Hash.SHA256 as SHA256 60 > import qualified Data.ByteString as BS 61 > import qualified Lightning.Protocol.BOLT1 as BOLT1 62 > import Lightning.Protocol.BOLT3 63 > import Lightning.Protocol.BOLT5 64 > 65 > -- fees from the BOLT #5 Appendix A weights 66 > let feerate = FeeratePerKw 5000 67 > let weight = to_local_penalty_input_weight + penalty_tx_base_weight 68 > spending_fee feerate weight 69 Satoshi 2690 70 > 71 > -- whether an HTLC has timed out at a given block height 72 > let Just amt = BOLT1.milli_satoshi 50000000 73 > let Just hash = BOLT1.payment_hash (BS.replicate 32 0xaa) 74 > let htlc = HTLC HTLCOffered amt hash (CltvExpiry 800000) 75 > htlc_timed_out 799999 htlc 76 False 77 > htlc_timed_out 800000 htlc 78 True 79 > 80 > -- an unsigned sweep of our to_local output, valid after the delay 81 > let key b = BOLT1.point (BS.cons 0x02 (BS.replicate 32 b)) 82 > let Just revpk = RevocationPubkey <$> key 0x01 83 > let Just delayedpk = LocalDelayedPubkey <$> key 0x02 84 > let Just txid = BT.mkTxId (BS.replicate 32 0x01) 85 > let Just value = BOLT1.satoshi 1000000 86 > let dest = Script ("\x00\x14" <> BS.replicate 20 0xcc) 87 > let delay = ToSelfDelay 144 88 > let op = BT.OutPoint txid 0 89 > let Just stx = spend_to_local op value revpk delay delayedpk dest feerate 90 > fmap BT.txout_value (BT.tx_outputs (stx_tx stx)) 91 997310 :| [] 92 > fmap BT.txin_sequence (BT.tx_inputs (stx_tx stx)) 93 144 :| [] 94 > stx_sighash_type stx 95 SIGHASH_ALL 96 > stx_input_script stx == to_local_script revpk delay delayedpk 97 True 98 > 99 > -- extract the preimage from the remote's claim of an offered HTLC 100 > let Just preimage = BOLT1.payment_preimage (BS.replicate 32 0xbb) 101 > let Just ph = BOLT1.payment_hash (SHA256.hash (BS.replicate 32 0xbb)) 102 > let sig = BS.replicate 71 0xcc 103 > let wit = offered_htlc_witness_preimage sig preimage (Script "") 104 > extract_preimage_offered ph wit 105 Just (PaymentPreimage <redacted>) 106 > fmap (== preimage) (extract_preimage_offered ph wit) 107 Just True 108 > extract_preimage_offered hash wit 109 Nothing 110 ``` 111 112 ## Documentation 113 114 Haddocks (API documentation, etc.) are hosted at 115 [docs.ppad.tech/bolt5](https://docs.ppad.tech/bolt5). 116 117 ## Specification 118 119 This library tracks BOLT #5 as of lightning/bolts commit 120 [1aadb719][spec] (2026-09-21); a copy lives in `etc/`. BOLT #5 121 publishes no test vectors beyond Appendix A's weights, which are 122 checked; the tests also check HTLC transactions and preimage extraction 123 against BOLT #3's Appendix C and F vectors. 124 125 See [Status](#status) for what isn't implemented. 126 127 ## Security 128 129 This library has received no security audit. It handles no secret 130 material: it builds unsigned transactions and reads public witnesses. 131 132 ## Development 133 134 You'll require [Nix][nixos] with [flake][flake] support enabled. Enter a 135 development shell with: 136 137 ``` 138 $ nix develop 139 ``` 140 141 Then do e.g.: 142 143 ``` 144 $ cabal repl ppad-bolt5 145 ``` 146 147 to get a REPL for the main library. 148 149 [bolt5]: https://github.com/lightning/bolts/blob/master/05-onchain.md 150 [bolt3]: https://git.ppad.tech/bolt3 151 [spec]: https://github.com/lightning/bolts/tree/1aadb719b4007c4cea0ba6e36b08c4fb53788dee 152 [nixos]: https://nixos.org/ 153 [flake]: https://nixos.org/manual/nix/unstable/command-ref/new-cli/nix3-flake.html