Encode.hs (3100B)
1 {-# OPTIONS_HADDOCK prune #-} 2 {-# LANGUAGE BangPatterns #-} 3 4 -- | 5 -- Module: Lightning.Protocol.BOLT3.Encode 6 -- Copyright: (c) 2025 Jared Tobin 7 -- License: MIT 8 -- Maintainer: Jared Tobin <jared@ppad.tech> 9 -- 10 -- Serialization for BOLT #3 transactions and scripts. 11 -- 12 -- Delegates to ppad-tx for transaction encoding. 13 14 module Lightning.Protocol.BOLT3.Encode ( 15 -- * Transaction serialization 16 encode_tx 17 , encode_htlc_tx 18 , encode_closing_tx 19 , encode_tx_for_signing 20 21 -- * Witness serialization 22 , encode_witness 23 , encode_funding_witness 24 ) where 25 26 import qualified Bitcoin.Prim.Tx as BT 27 import qualified Data.ByteString as BS 28 import qualified Data.ByteString.Builder as BSB 29 import Data.Word (Word64) 30 import Lightning.Protocol.BOLT3.Types 31 import Lightning.Protocol.BOLT3.Tx 32 33 -- transaction encoding -------------------------------------------------------- 34 35 -- | Encode a commitment transaction (SegWit format). 36 -- 37 -- Returns 'Nothing' if the transaction has no outputs. 38 encode_tx :: CommitmentTx -> Maybe BS.ByteString 39 encode_tx = fmap BT.to_bytes . commitment_to_tx 40 41 -- | Encode an HTLC transaction (SegWit format). 42 encode_htlc_tx :: HTLCTx -> BS.ByteString 43 encode_htlc_tx = BT.to_bytes . htlc_to_tx 44 45 -- | Encode a closing transaction (SegWit format). 46 -- 47 -- Returns 'Nothing' if the transaction has no outputs. 48 encode_closing_tx :: ClosingTx -> Maybe BS.ByteString 49 encode_closing_tx = fmap BT.to_bytes . closing_to_tx 50 51 -- | Encode a commitment transaction for signing (stripped 52 -- format, no witness). 53 -- 54 -- Returns 'Nothing' if the transaction has no outputs. 55 encode_tx_for_signing 56 :: CommitmentTx -> Maybe BS.ByteString 57 encode_tx_for_signing = 58 fmap BT.to_bytes_legacy . commitment_to_tx 59 60 -- witness encoding ------------------------------------------------------------ 61 62 -- | Encode a witness stack. 63 -- 64 -- Format: varint item count, then for each item: 65 -- varint length followed by item data. 66 encode_witness :: Witness -> BS.ByteString 67 encode_witness (Witness !items) = 68 BT.to_strict $ 69 put_varint (fromIntegral (length items)) 70 <> foldMap put_item items 71 where 72 put_item :: BS.ByteString -> BSB.Builder 73 put_item !bs = 74 put_varint (fromIntegral (BS.length bs)) 75 <> BSB.byteString bs 76 77 -- | Encode a varint to a 'BSB.Builder'. 78 put_varint :: Word64 -> BSB.Builder 79 put_varint !n 80 | n < 0xFD = BSB.word8 (fromIntegral n) 81 | n <= 0xFFFF = 82 BSB.word8 0xFD <> BSB.word16LE (fromIntegral n) 83 | n <= 0xFFFFFFFF = 84 BSB.word8 0xFE <> BSB.word32LE (fromIntegral n) 85 | otherwise = 86 BSB.word8 0xFF <> BSB.word64LE n 87 {-# INLINE put_varint #-} 88 89 -- | Encode a funding witness (2-of-2 multisig). 90 -- 91 -- The witness stack is: @0 <sig1> <sig2> <witnessScript>@ 92 -- 93 -- Signatures must be ordered to match pubkey order in the 94 -- funding script. 95 encode_funding_witness 96 :: BS.ByteString -- ^ Signature for lesser pubkey 97 -> BS.ByteString -- ^ Signature for greater pubkey 98 -> Script -- ^ The funding witness script 99 -> BS.ByteString 100 encode_funding_witness !sig1 !sig2 (Script !ws) = 101 encode_witness 102 (Witness [BS.empty, sig1, sig2, ws])