commit 6f295dd9af0ea3a78db14f5020744bef902a55a1
parent 0d587f9d1d42c2fdb26cfe0e6c96136faba4ee67
Author: Jared Tobin <jared@jtobin.io>
Date: Sat, 10 Oct 2026 14:05:29 +0400
lib: port to ppad-bolt1 0.1.0 with typed TLVs
Rewrites the library against the ppad-bolt1 0.1.0 API.
* Exposes Lightning.Protocol.BOLT2 alone, with snake_case names and
per-message field prefixes (open_channel_chain_hash, ...).
* Every payload decoder consumes its whole input; the bytes after the
fixed fields are the message's TLV stream, decoded with the
message's known types. Unknown even types fail, unknown odd records
are kept in the _tlvs field, and known records get typed fields
(upfront_shutdown_script, channel_type as a bolt9 FeatureVector,
require_confirmed_inputs, funding_output_contribution, short_channel_id
alias, closing signatures, fee_range, blinded_path, attribution_data,
fulfillment_payload, commitment_signed funding_txid, next_funding).
* Known TLV values are length-checked; points, amounts and the stfu
initiator byte are validated.
* Amounts use bolt1's bounded Satoshi/MilliSatoshi, except
max_htlc_value_in_flight_msat, which stays Word64.
* Encoders return Either EncodeError only where they can fail.
* Adds a Message dispatcher (message_type, encode_message,
decode_message) framed by bolt1's envelope codec.
* Removes FeatureBits, Initiator, MsgType and the bolt1/ppad-tx
re-exports; renames OnionPacket to OnionRoutingPacket; adds
OnionHash and AttributionData; bounds ScriptPubKey and Witness at
65535 bytes.
* Catches up with the spec: channel_reestablish next_funding at type 1,
update_fulfill_htlc fulfillment_payload, TLV streams on
commitment_signed, tx_add_input and tx_signatures.
Diffstat:
5 files changed, 2104 insertions(+), 2065 deletions(-)
diff --git a/lib/Lightning/Protocol/BOLT2.hs b/lib/Lightning/Protocol/BOLT2.hs
@@ -6,128 +6,187 @@
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
--- Peer protocol for the Lightning Network, per
--- [BOLT #2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md).
+-- The peer protocol of the Lightning Network, per
+-- [BOLT #2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md):
+-- the messages for channel establishment (v1 and v2), interactive
+-- transaction construction, quiescence, channel close, normal operation
+-- and message retransmission.
+--
+-- Fundamental types (channel ids, points, signatures, amounts, TLV
+-- streams) come from ppad-bolt1, transaction ids from ppad-tx, and
+-- feature vectors from ppad-bolt9.
+--
+-- Each message has a payload codec, @encode_\<msg\>@ and
+-- @decode_\<msg\>@; 'encode_message' and 'decode_message' handle
+-- complete messages, including the type. Decoders consume the whole
+-- payload: bytes after the fixed fields are the message's TLV stream.
+-- Known TLV records are decoded into typed fields, an unknown even
+-- record fails the decode, and unknown odd records are kept in the
+-- message's @_tlvs@ field, so re-encoding a decoded message reproduces
+-- its bytes.
+--
+-- The examples below assume:
+--
+-- >>> :set -XOverloadedStrings
+-- >>> import qualified Data.ByteString as BS
+-- >>> import qualified Lightning.Protocol.BOLT1 as BOLT1
+-- >>> import Lightning.Protocol.BOLT2
+-- >>> let Just cid = BOLT1.channel_id (BS.replicate 32 0xab)
+--
+-- Encode a message, and decode it again:
+--
+-- >>> let fee = UpdateFee cid 2500 BOLT1.empty_tlv_stream
+-- >>> let Right wire = encode_message (MsgUpdateFee fee)
+-- >>> BS.length wire
+-- 38
+-- >>> decode_message wire == Right (MsgUpdateFee fee)
+-- True
+--
+-- Unknown odd TLV records are preserved, and unknown even ones
+-- rejected:
+--
+-- >>> let payload = encode_update_fee fee
+-- >>> fmap update_fee_tlvs (decode_update_fee (payload <> "\x05\x01\x2a"))
+-- Right (TlvStream [TlvRecord {tlv_type = 5, tlv_value = "*"}])
+-- >>> decode_update_fee (payload <> "\x04\x01\x2a")
+-- Left (DecodeTlvError (TlvUnknownEvenType 4))
module Lightning.Protocol.BOLT2 (
- -- * Core types
- -- | Re-exported from "Lightning.Protocol.BOLT2.Types".
- module Lightning.Protocol.BOLT2.Types
-
- -- * Message types
- -- | Re-exported from "Lightning.Protocol.BOLT2.Messages".
- , module Lightning.Protocol.BOLT2.Messages
-
- -- * Codec functions
- -- | Re-exported from "Lightning.Protocol.BOLT2.Codec".
- , module Lightning.Protocol.BOLT2.Codec
-
- -- $messagetypes
-
- -- ** Channel establishment (v1)
- -- $v1establishment
-
- -- ** Channel establishment (v2)
- -- $v2establishment
+ -- * Messages
+ Message(..)
+ , message_type
+
+ -- ** Channel establishment v1
+ , OpenChannel(..)
+ , AcceptChannel(..)
+ , FundingCreated(..)
+ , FundingSigned(..)
+ , ChannelReady(..)
+
+ -- ** Channel establishment v2
+ , OpenChannel2(..)
+ , AcceptChannel2(..)
+
+ -- ** Interactive transaction construction
+ , TxAddInput(..)
+ , TxAddOutput(..)
+ , TxRemoveInput(..)
+ , TxRemoveOutput(..)
+ , TxComplete(..)
+ , TxSignatures(..)
+ , TxInitRbf(..)
+ , TxAckRbf(..)
+ , TxAbort(..)
+
+ -- ** Channel quiescence
+ , Stfu(..)
-- ** Channel close
- -- $close
+ , Shutdown(..)
+ , ClosingComplete(..)
+ , ClosingSig(..)
+ , ClosingSigned(..)
-- ** Normal operation
- -- $normal
-
- -- ** Message reestablishment
- -- $reestablish
+ , UpdateAddHtlc(..)
+ , UpdateFulfillHtlc(..)
+ , UpdateFailHtlc(..)
+ , UpdateFailMalformedHtlc(..)
+ , CommitmentSigned(..)
+ , RevokeAndAck(..)
+ , UpdateFee(..)
+
+ -- ** Message retransmission
+ , ChannelReestablish(..)
+
+ -- * Field types
+ , HtlcId(..)
+ , SerialId(..)
+ , ScriptPubKey
+ , script_pubkey
+ , un_script_pubkey
+ , Witness
+ , witness
+ , un_witness
+ , OnionRoutingPacket
+ , onion_routing_packet
+ , un_onion_routing_packet
+ , OnionHash
+ , onion_hash
+ , un_onion_hash
+ , AttributionData
+ , attribution_data
+ , un_attribution_data
+ , FeeRange(..)
+ , NextFunding(..)
+
+ -- * Encoding and decoding messages
+ , encode_message
+ , decode_message
+ , EncodeError(..)
+ , DecodeError(..)
+
+ -- ** Payloads
+ , encode_open_channel
+ , decode_open_channel
+ , encode_accept_channel
+ , decode_accept_channel
+ , encode_funding_created
+ , decode_funding_created
+ , encode_funding_signed
+ , decode_funding_signed
+ , encode_channel_ready
+ , decode_channel_ready
+ , encode_open_channel2
+ , decode_open_channel2
+ , encode_accept_channel2
+ , decode_accept_channel2
+ , encode_tx_add_input
+ , decode_tx_add_input
+ , encode_tx_add_output
+ , decode_tx_add_output
+ , encode_tx_remove_input
+ , decode_tx_remove_input
+ , encode_tx_remove_output
+ , decode_tx_remove_output
+ , encode_tx_complete
+ , decode_tx_complete
+ , encode_tx_signatures
+ , decode_tx_signatures
+ , encode_tx_init_rbf
+ , decode_tx_init_rbf
+ , encode_tx_ack_rbf
+ , decode_tx_ack_rbf
+ , encode_tx_abort
+ , decode_tx_abort
+ , encode_stfu
+ , decode_stfu
+ , encode_shutdown
+ , decode_shutdown
+ , encode_closing_complete
+ , decode_closing_complete
+ , encode_closing_sig
+ , decode_closing_sig
+ , encode_closing_signed
+ , decode_closing_signed
+ , encode_update_add_htlc
+ , decode_update_add_htlc
+ , encode_update_fulfill_htlc
+ , decode_update_fulfill_htlc
+ , encode_update_fail_htlc
+ , decode_update_fail_htlc
+ , encode_update_fail_malformed_htlc
+ , decode_update_fail_malformed_htlc
+ , encode_commitment_signed
+ , decode_commitment_signed
+ , encode_revoke_and_ack
+ , decode_revoke_and_ack
+ , encode_update_fee
+ , decode_update_fee
+ , encode_channel_reestablish
+ , decode_channel_reestablish
) where
import Lightning.Protocol.BOLT2.Codec
import Lightning.Protocol.BOLT2.Messages
import Lightning.Protocol.BOLT2.Types
-
--- $messagetypes
---
--- BOLT #2 defines the following message types:
---
--- * 2: stfu
--- * 32: open_channel
--- * 33: accept_channel
--- * 34: funding_created
--- * 35: funding_signed
--- * 36: channel_ready
--- * 38: shutdown
--- * 39: closing_signed
--- * 40: closing_complete
--- * 41: closing_sig
--- * 64: open_channel2
--- * 65: accept_channel2
--- * 66: tx_add_input
--- * 67: tx_add_output
--- * 68: tx_remove_input
--- * 69: tx_remove_output
--- * 70: tx_complete
--- * 71: tx_signatures
--- * 72: tx_init_rbf
--- * 73: tx_ack_rbf
--- * 74: tx_abort
--- * 128: update_add_htlc
--- * 130: update_fulfill_htlc
--- * 131: update_fail_htlc
--- * 132: commitment_signed
--- * 133: revoke_and_ack
--- * 134: update_fee
--- * 135: update_fail_malformed_htlc
--- * 136: channel_reestablish
-
--- $v1establishment
---
--- Channel establishment v1 messages:
---
--- * open_channel (32)
--- * accept_channel (33)
--- * funding_created (34)
--- * funding_signed (35)
--- * channel_ready (36)
-
--- $v2establishment
---
--- Channel establishment v2 (interactive-tx) messages:
---
--- * open_channel2 (64)
--- * accept_channel2 (65)
--- * tx_add_input (66)
--- * tx_add_output (67)
--- * tx_remove_input (68)
--- * tx_remove_output (69)
--- * tx_complete (70)
--- * tx_signatures (71)
--- * tx_init_rbf (72)
--- * tx_ack_rbf (73)
--- * tx_abort (74)
-
--- $close
---
--- Channel close messages:
---
--- * stfu (2)
--- * shutdown (38)
--- * closing_signed (39)
--- * closing_complete (40)
--- * closing_sig (41)
-
--- $normal
---
--- Normal operation messages:
---
--- * update_add_htlc (128)
--- * update_fulfill_htlc (130)
--- * update_fail_htlc (131)
--- * commitment_signed (132)
--- * revoke_and_ack (133)
--- * update_fee (134)
--- * update_fail_malformed_htlc (135)
-
--- $reestablish
---
--- Message reestablishment:
---
--- * channel_reestablish (136)
diff --git a/lib/Lightning/Protocol/BOLT2/Codec.hs b/lib/Lightning/Protocol/BOLT2/Codec.hs
@@ -1,7 +1,6 @@
-{-# OPTIONS_HADDOCK prune #-}
+{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE DerivingStrategies #-}
-- |
-- Module: Lightning.Protocol.BOLT2.Codec
@@ -9,1348 +8,1381 @@
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
--- Encode/decode functions for BOLT #2 messages.
+-- Encoding and decoding of BOLT #2 messages.
module Lightning.Protocol.BOLT2.Codec (
- -- * Error types
EncodeError(..)
, DecodeError(..)
- -- * Channel establishment v1
- , encodeOpenChannel
- , decodeOpenChannel
- , encodeAcceptChannel
- , decodeAcceptChannel
- , encodeFundingCreated
- , decodeFundingCreated
- , encodeFundingSigned
- , decodeFundingSigned
- , encodeChannelReady
- , decodeChannelReady
-
- -- * Channel establishment v2 (interactive-tx)
- , encodeOpenChannel2
- , decodeOpenChannel2
- , encodeAcceptChannel2
- , decodeAcceptChannel2
- , encodeTxAddInput
- , decodeTxAddInput
- , encodeTxAddOutput
- , decodeTxAddOutput
- , encodeTxRemoveInput
- , decodeTxRemoveInput
- , encodeTxRemoveOutput
- , decodeTxRemoveOutput
- , encodeTxComplete
- , decodeTxComplete
- , encodeTxSignatures
- , decodeTxSignatures
- , encodeTxInitRbf
- , decodeTxInitRbf
- , encodeTxAckRbf
- , decodeTxAckRbf
- , encodeTxAbort
- , decodeTxAbort
-
- -- * Channel close
- , encodeStfu
- , decodeStfu
- , encodeShutdown
- , decodeShutdown
- , encodeClosingSigned
- , decodeClosingSigned
- , encodeClosingComplete
- , decodeClosingComplete
- , encodeClosingSig
- , decodeClosingSig
-
- -- * Normal operation
- , encodeUpdateAddHtlc
- , decodeUpdateAddHtlc
- , encodeUpdateFulfillHtlc
- , decodeUpdateFulfillHtlc
- , encodeUpdateFailHtlc
- , decodeUpdateFailHtlc
- , encodeUpdateFailMalformedHtlc
- , decodeUpdateFailMalformedHtlc
- , encodeCommitmentSigned
- , decodeCommitmentSigned
- , encodeRevokeAndAck
- , decodeRevokeAndAck
- , encodeUpdateFee
- , decodeUpdateFee
-
- -- * Channel reestablishment
- , encodeChannelReestablish
- , decodeChannelReestablish
+ , encode_message
+ , decode_message
+
+ , encode_open_channel
+ , decode_open_channel
+ , encode_accept_channel
+ , decode_accept_channel
+ , encode_funding_created
+ , decode_funding_created
+ , encode_funding_signed
+ , decode_funding_signed
+ , encode_channel_ready
+ , decode_channel_ready
+
+ , encode_open_channel2
+ , decode_open_channel2
+ , encode_accept_channel2
+ , decode_accept_channel2
+ , encode_tx_add_input
+ , decode_tx_add_input
+ , encode_tx_add_output
+ , decode_tx_add_output
+ , encode_tx_remove_input
+ , decode_tx_remove_input
+ , encode_tx_remove_output
+ , decode_tx_remove_output
+ , encode_tx_complete
+ , decode_tx_complete
+ , encode_tx_signatures
+ , decode_tx_signatures
+ , encode_tx_init_rbf
+ , decode_tx_init_rbf
+ , encode_tx_ack_rbf
+ , decode_tx_ack_rbf
+ , encode_tx_abort
+ , decode_tx_abort
+
+ , encode_stfu
+ , decode_stfu
+
+ , encode_shutdown
+ , decode_shutdown
+ , encode_closing_complete
+ , decode_closing_complete
+ , encode_closing_sig
+ , decode_closing_sig
+ , encode_closing_signed
+ , decode_closing_signed
+
+ , encode_update_add_htlc
+ , decode_update_add_htlc
+ , encode_update_fulfill_htlc
+ , decode_update_fulfill_htlc
+ , encode_update_fail_htlc
+ , decode_update_fail_htlc
+ , encode_update_fail_malformed_htlc
+ , decode_update_fail_malformed_htlc
+ , encode_commitment_signed
+ , decode_commitment_signed
+ , encode_revoke_and_ack
+ , decode_revoke_and_ack
+ , encode_update_fee
+ , decode_update_fee
+
+ , encode_channel_reestablish
+ , decode_channel_reestablish
) where
+import Bitcoin.Prim.Tx (TxId(..), mkTxId)
import Control.DeepSeq (NFData)
-import Control.Monad (unless)
import qualified Data.ByteString as BS
-import Data.Word (Word8, Word16, Word32)
+import qualified Data.ByteString.Unsafe as BU
+import Data.Int (Int64)
+import Data.Word (Word8, Word16, Word32, Word64)
import GHC.Generics (Generic)
+import qualified Lightning.Protocol.BOLT1 as BOLT1
import Lightning.Protocol.BOLT1
- ( TlvStream
- , unsafeTlvStream
- , TlvError
- , encodeU16
- , encodeU32
- , encodeU64
- , decodeU16
- , decodeU32
- , decodeU64
- , encodeTlvStream
- , decodeTlvStreamRaw
- )
-import Lightning.Protocol.BOLT2.Types
+ ( ChannelId, Signature, Point, TlvRecord(..), TlvStream, TlvError )
+import qualified Lightning.Protocol.BOLT9 as BOLT9
import Lightning.Protocol.BOLT2.Messages
+import Lightning.Protocol.BOLT2.Types
--- Error types -----------------------------------------------------------------
+-- errors ---------------------------------------------------------------------
--- | Encoding errors.
+-- | Why a message failed to encode.
data EncodeError
- = EncodeLengthOverflow -- ^ Payload exceeds u16 max (65535 bytes)
- deriving stock (Eq, Show, Generic)
+ = EncodeLengthOverflow
+ -- ^ a length-prefixed field or a counted list exceeds 65535
+ | EncodeInvalidTlvs
+ -- ^ a @_tlvs@ field contains a record of a type the message knows
+ | EncodeMessageTooLarge
+ -- ^ the message (type and payload) exceeds 65535 bytes
+ deriving (Eq, Show, Generic)
instance NFData EncodeError
--- | Decoding errors.
+-- | Why a message failed to decode.
data DecodeError
= DecodeInsufficientBytes
- | DecodeInvalidLength
- | DecodeInvalidChannelId
- | DecodeInvalidChainHash
- | DecodeInvalidSignature
+ -- ^ the input ended before a field did
| DecodeInvalidPoint
- | DecodeInvalidTxId
- | DecodeInvalidPaymentHash
- | DecodeInvalidPaymentPreimage
- | DecodeInvalidOnionPacket
- | DecodeInvalidSecret
+ -- ^ a point lacks a compressed-encoding prefix
+ | DecodeInvalidAmount
+ -- ^ an amount exceeds 21 million BTC
| DecodeInvalidInitiator
+ -- ^ the @initiator@ byte of @stfu@ is neither 0 nor 1
| DecodeTlvError !TlvError
- deriving stock (Eq, Show, Generic)
+ -- ^ the message's TLV stream is malformed, or has an unknown even
+ -- type
+ | DecodeInvalidTlvValue !Word64
+ -- ^ a known TLV record (of the given type) has a malformed value
+ | DecodeUnknownEvenType !Word16
+ -- ^ a message type that BOLT #2 doesn't define (even)
+ | DecodeUnknownOddType !Word16
+ -- ^ a message type that BOLT #2 doesn't define (odd)
+ deriving (Eq, Show, Generic)
instance NFData DecodeError
--- Helpers ---------------------------------------------------------------------
-
--- | Decode a single byte.
-decodeU8 :: BS.ByteString -> Maybe (Word8, BS.ByteString)
-decodeU8 !bs
- | BS.null bs = Nothing
- | otherwise = Just (BS.index bs 0, BS.drop 1 bs)
-{-# INLINE decodeU8 #-}
-
--- | Decode fixed-size bytes.
-decodeBytes :: Int -> BS.ByteString -> Maybe (BS.ByteString, BS.ByteString)
-decodeBytes !n !bs
- | BS.length bs < n = Nothing
- | otherwise = Just (BS.take n bs, BS.drop n bs)
-{-# INLINE decodeBytes #-}
-
--- | Decode a ChannelId (32 bytes).
-decodeChannelIdBytes
- :: BS.ByteString -> Either DecodeError (ChannelId, BS.ByteString)
-decodeChannelIdBytes !bs = do
- (raw, rest) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeBytes channelIdLen bs)
- cid <- maybe (Left DecodeInvalidChannelId) Right (channelId raw)
- Right (cid, rest)
-{-# INLINE decodeChannelIdBytes #-}
-
--- | Decode a ChainHash (32 bytes).
-decodeChainHashBytes
- :: BS.ByteString -> Either DecodeError (ChainHash, BS.ByteString)
-decodeChainHashBytes !bs = do
- (raw, rest) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeBytes chainHashLen bs)
- ch <- maybe (Left DecodeInvalidChainHash) Right (chainHash raw)
- Right (ch, rest)
-{-# INLINE decodeChainHashBytes #-}
-
--- | Decode a Signature (64 bytes).
-decodeSignatureBytes
- :: BS.ByteString -> Either DecodeError (Signature, BS.ByteString)
-decodeSignatureBytes !bs = do
- (raw, rest) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeBytes signatureLen bs)
- sig <- maybe (Left DecodeInvalidSignature) Right (signature raw)
- Right (sig, rest)
-{-# INLINE decodeSignatureBytes #-}
-
--- | Decode a Point (33 bytes).
-decodePointBytes
- :: BS.ByteString -> Either DecodeError (Point, BS.ByteString)
-decodePointBytes !bs = do
- (raw, rest) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeBytes pointLen bs)
- pt <- maybe (Left DecodeInvalidPoint) Right (point raw)
- Right (pt, rest)
-{-# INLINE decodePointBytes #-}
-
--- | Decode a TxId (32 bytes).
-decodeTxIdBytes
- :: BS.ByteString -> Either DecodeError (TxId, BS.ByteString)
-decodeTxIdBytes !bs = do
- (raw, rest) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeBytes 32 bs)
- tid <- maybe (Left DecodeInvalidTxId) Right (mkTxId raw)
- Right (tid, rest)
-{-# INLINE decodeTxIdBytes #-}
-
--- | Decode a u16 with error handling.
-decodeU16E :: BS.ByteString -> Either DecodeError (Word16, BS.ByteString)
-decodeU16E !bs = maybe (Left DecodeInsufficientBytes) Right (decodeU16 bs)
-{-# INLINE decodeU16E #-}
-
--- | Decode a u32 with error handling.
-decodeU32E :: BS.ByteString -> Either DecodeError (Word32, BS.ByteString)
-decodeU32E !bs = maybe (Left DecodeInsufficientBytes) Right (decodeU32 bs)
-{-# INLINE decodeU32E #-}
-
--- | Decode a u64 as Satoshi.
-decodeSatoshi
- :: BS.ByteString -> Either DecodeError (Satoshi, BS.ByteString)
-decodeSatoshi !bs = do
- (val, rest) <- maybe (Left DecodeInsufficientBytes) Right (decodeU64 bs)
- Right (Satoshi val, rest)
-{-# INLINE decodeSatoshi #-}
-
--- | Decode a u64 as MilliSatoshi.
-decodeMilliSatoshi
- :: BS.ByteString -> Either DecodeError (MilliSatoshi, BS.ByteString)
-decodeMilliSatoshi !bs = do
- (val, rest) <- maybe (Left DecodeInsufficientBytes) Right (decodeU64 bs)
- Right (MilliSatoshi val, rest)
-{-# INLINE decodeMilliSatoshi #-}
-
--- | Decode optional TLV stream from remaining bytes.
-decodeTlvs :: BS.ByteString -> Either DecodeError TlvStream
-decodeTlvs !bs
- | BS.null bs = Right (unsafeTlvStream [])
- | otherwise = either (Left . DecodeTlvError) Right (decodeTlvStreamRaw bs)
-{-# INLINE decodeTlvs #-}
-
--- | Decode a length-prefixed script (u16 length prefix).
-decodeScriptPubKey
- :: BS.ByteString -> Either DecodeError (ScriptPubKey, BS.ByteString)
-decodeScriptPubKey !bs = do
- (len, rest1) <- decodeU16E bs
- let !scriptLen = fromIntegral len
- unless (BS.length rest1 >= scriptLen) $ Left DecodeInsufficientBytes
- let !script = BS.take scriptLen rest1
- !rest2 = BS.drop scriptLen rest1
- Right (scriptPubKey script, rest2)
-{-# INLINE decodeScriptPubKey #-}
-
--- | Decode a PaymentHash (32 bytes).
-decodePaymentHashBytes
- :: BS.ByteString -> Either DecodeError (PaymentHash, BS.ByteString)
-decodePaymentHashBytes !bs = do
- (raw, rest) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeBytes paymentHashLen bs)
- ph <- maybe (Left DecodeInvalidPaymentHash) Right (paymentHash raw)
- Right (ph, rest)
-{-# INLINE decodePaymentHashBytes #-}
-
--- | Decode a PaymentPreimage (32 bytes).
-decodePaymentPreimageBytes
- :: BS.ByteString -> Either DecodeError (PaymentPreimage, BS.ByteString)
-decodePaymentPreimageBytes !bs = do
- (raw, rest) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeBytes paymentPreimageLen bs)
- pp <- maybe (Left DecodeInvalidPaymentPreimage) Right (paymentPreimage raw)
- Right (pp, rest)
-{-# INLINE decodePaymentPreimageBytes #-}
-
--- | Decode an OnionPacket (1366 bytes).
-decodeOnionPacketBytes
- :: BS.ByteString -> Either DecodeError (OnionPacket, BS.ByteString)
-decodeOnionPacketBytes !bs = do
- (raw, rest) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeBytes onionPacketLen bs)
- op <- maybe (Left DecodeInvalidOnionPacket) Right (onionPacket raw)
- Right (op, rest)
-{-# INLINE decodeOnionPacketBytes #-}
-
--- | Decode a PerCommitmentSecret (32 bytes).
-decodePerCommitmentSecretBytes
- :: BS.ByteString
- -> Either DecodeError (PerCommitmentSecret, BS.ByteString)
-decodePerCommitmentSecretBytes !bs = do
- (raw, rest) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeBytes perCommitmentSecretLen bs)
- sec <- maybe (Left DecodeInvalidSecret) Right
- (perCommitmentSecret raw)
- Right (sec, rest)
-{-# INLINE decodePerCommitmentSecretBytes #-}
-
--- | Encode a u16-prefixed byte string with bounds checking.
-encodeU16BytesE :: BS.ByteString -> Either EncodeError BS.ByteString
-encodeU16BytesE !bs
- | BS.length bs > 65535 = Left EncodeLengthOverflow
- | otherwise = Right $! encodeU16 (fromIntegral (BS.length bs)) <> bs
-{-# INLINE encodeU16BytesE #-}
-
--- | Check that a list count fits in u16.
-checkListCountU16 :: Int -> Either EncodeError Word16
-checkListCountU16 !n
+-- parsing --------------------------------------------------------------------
+
+newtype Parser a = Parser
+ { run_parser :: BS.ByteString -> Either DecodeError (a, BS.ByteString) }
+
+instance Functor Parser where
+ fmap f (Parser p) = Parser $ \bs -> case p bs of
+ Left e -> Left e
+ Right (a, r) -> Right (f a, r)
+ {-# INLINE fmap #-}
+
+instance Applicative Parser where
+ pure a = Parser $ \bs -> Right (a, bs)
+ {-# INLINE pure #-}
+ Parser pf <*> Parser pa = Parser $ \bs -> case pf bs of
+ Left e -> Left e
+ Right (f, r) -> case pa r of
+ Left e -> Left e
+ Right (a, r') -> Right (f a, r')
+ {-# INLINE (<*>) #-}
+
+instance Monad Parser where
+ Parser p >>= k = Parser $ \bs -> case p bs of
+ Left e -> Left e
+ Right (a, r) -> run_parser (k a) r
+ {-# INLINE (>>=) #-}
+
+-- run a parser whose last step consumes the remaining input
+parse :: Parser a -> BS.ByteString -> Either DecodeError a
+parse p bs = fmap fst (run_parser p bs)
+{-# INLINE parse #-}
+
+failure :: DecodeError -> Parser a
+failure e = Parser $ \_ -> Left e
+{-# INLINE failure #-}
+
+-- lift a bolt1 field decoder, whose only failure is truncation
+field :: (BS.ByteString -> Maybe (a, BS.ByteString)) -> Parser a
+field f = Parser $ \bs -> case f bs of
+ Nothing -> Left DecodeInsufficientBytes
+ Just r -> Right r
+{-# INLINE field #-}
+
+bytes :: Int -> Parser BS.ByteString
+bytes n = Parser $ \bs ->
+ if BS.length bs < n
+ then Left DecodeInsufficientBytes
+ else Right (BU.unsafeTake n bs, BU.unsafeDrop n bs)
+{-# INLINE bytes #-}
+
+-- a fixed-size field whose constructor checks only the length
+sized :: Int -> (BS.ByteString -> Maybe a) -> Parser a
+sized n f = do
+ b <- bytes n
+ maybe (failure DecodeInsufficientBytes) pure (f b)
+{-# INLINE sized #-}
+
+u8 :: Parser Word8
+u8 = Parser $ \bs -> case BS.uncons bs of
+ Nothing -> Left DecodeInsufficientBytes
+ Just r -> Right r
+{-# INLINE u8 #-}
+
+u16 :: Parser Word16
+u16 = field BOLT1.decode_u16
+{-# INLINE u16 #-}
+
+u32 :: Parser Word32
+u32 = field BOLT1.decode_u32
+{-# INLINE u32 #-}
+
+u64 :: Parser Word64
+u64 = field BOLT1.decode_u64
+{-# INLINE u64 #-}
+
+chain_hash :: Parser BOLT1.ChainHash
+chain_hash = field BOLT1.decode_chain_hash
+{-# INLINE chain_hash #-}
+
+channel_id :: Parser ChannelId
+channel_id = field BOLT1.decode_channel_id
+{-# INLINE channel_id #-}
+
+signature :: Parser Signature
+signature = field BOLT1.decode_signature
+{-# INLINE signature #-}
+
+payment_hash :: Parser BOLT1.PaymentHash
+payment_hash = field BOLT1.decode_payment_hash
+{-# INLINE payment_hash #-}
+
+payment_preimage :: Parser BOLT1.PaymentPreimage
+payment_preimage = field BOLT1.decode_payment_preimage
+{-# INLINE payment_preimage #-}
+
+per_commitment_secret :: Parser BOLT1.PerCommitmentSecret
+per_commitment_secret = field BOLT1.decode_per_commitment_secret
+{-# INLINE per_commitment_secret #-}
+
+point :: Parser Point
+point = do
+ b <- bytes 33
+ maybe (failure DecodeInvalidPoint) pure (BOLT1.point b)
+{-# INLINE point #-}
+
+satoshi :: Parser BOLT1.Satoshi
+satoshi = do
+ w <- u64
+ maybe (failure DecodeInvalidAmount) pure (BOLT1.satoshi w)
+{-# INLINE satoshi #-}
+
+milli_satoshi :: Parser BOLT1.MilliSatoshi
+milli_satoshi = do
+ w <- u64
+ maybe (failure DecodeInvalidAmount) pure (BOLT1.milli_satoshi w)
+{-# INLINE milli_satoshi #-}
+
+txid :: Parser TxId
+txid = sized 32 mkTxId
+{-# INLINE txid #-}
+
+htlc_id :: Parser HtlcId
+htlc_id = fmap HtlcId u64
+{-# INLINE htlc_id #-}
+
+serial_id :: Parser SerialId
+serial_id = fmap SerialId u64
+{-# INLINE serial_id #-}
+
+prefixed :: Parser BS.ByteString
+prefixed = field BOLT1.decode_u16_prefixed
+{-# INLINE prefixed #-}
+
+script :: Parser ScriptPubKey
+script = do
+ b <- prefixed
+ maybe (failure DecodeInsufficientBytes) pure (script_pubkey b)
+{-# INLINE script #-}
+
+-- n items, each parsed by p
+count :: Int -> Parser a -> Parser [a]
+count n0 p = go n0 []
+ where
+ go !n !acc
+ | n <= 0 = pure (reverse acc)
+ | otherwise = p >>= \a -> go (n - 1) (a : acc)
+{-# INLINE count #-}
+
+-- the TLV stream occupying the rest of the payload, given the message's
+-- known types
+tlvs :: [Word64] -> Parser TlvStream
+tlvs known = Parser $ \bs ->
+ case BOLT1.decode_tlv_stream (`elem` known) bs of
+ Left e -> Left (DecodeTlvError e)
+ Right s -> Right (s, BS.empty)
+{-# INLINE tlvs #-}
+
+-- the unknown records of a stream
+unknown :: [Word64] -> TlvStream -> TlvStream
+unknown known = BOLT1.filter_tlv_stream (`notElem` known)
+{-# INLINE unknown #-}
+
+-- the typed value of a known record, if present
+record :: Word64 -> (BS.ByteString -> Maybe a) -> TlvStream -> Parser (Maybe a)
+record t f s = case BOLT1.lookup_tlv t s of
+ Nothing -> pure Nothing
+ Just v -> maybe (failure (DecodeInvalidTlvValue t)) (pure . Just) (f v)
+{-# INLINE record #-}
+
+-- whether a known record with an empty value is present
+flag :: Word64 -> TlvStream -> Parser Bool
+flag t s = fmap (maybe False (const True)) (record t empty_value s)
+ where
+ empty_value v
+ | BS.null v = Just ()
+ | otherwise = Nothing
+{-# INLINE flag #-}
+
+-- TLV values -----------------------------------------------------------------
+
+-- run a field decoder over a whole TLV value
+whole :: (BS.ByteString -> Maybe (a, BS.ByteString)) -> BS.ByteString
+ -> Maybe a
+whole f v = case f v of
+ Just (a, r) | BS.null r -> Just a
+ _ -> Nothing
+{-# INLINE whole #-}
+
+tlv_point :: BS.ByteString -> Maybe Point
+tlv_point v
+ | BS.length v == 33 = BOLT1.point v
+ | otherwise = Nothing
+
+tlv_s64 :: BS.ByteString -> Maybe Int64
+tlv_s64 = whole BOLT1.decode_s64
+
+tlv_fee_range :: BS.ByteString -> Maybe FeeRange
+tlv_fee_range v = do
+ (lo, r0) <- BOLT1.decode_satoshi v
+ hi <- whole BOLT1.decode_satoshi r0
+ pure (FeeRange lo hi)
+
+tlv_next_funding :: BS.ByteString -> Maybe NextFunding
+tlv_next_funding v
+ | BS.length v == 33 = do
+ t <- mkTxId (BU.unsafeTake 32 v)
+ pure (NextFunding t (BU.unsafeIndex v 32))
+ | otherwise = Nothing
+
+-- encoding -------------------------------------------------------------------
+
+u16_prefixed :: BS.ByteString -> Either EncodeError BS.ByteString
+u16_prefixed bs = maybe (Left EncodeLengthOverflow) Right
+ (BOLT1.encode_u16_prefixed bs)
+{-# INLINE u16_prefixed #-}
+
+-- scripts are bounded, so their prefix can't overflow
+script_bytes :: ScriptPubKey -> BS.ByteString
+script_bytes s =
+ let !b = un_script_pubkey s
+ in BOLT1.encode_u16 (fromIntegral (BS.length b)) <> b
+{-# INLINE script_bytes #-}
+
+count_prefix :: [a] -> Either EncodeError BS.ByteString
+count_prefix xs
| n > 65535 = Left EncodeLengthOverflow
- | otherwise = Right $! fromIntegral n
-{-# INLINE checkListCountU16 #-}
-
--- | Decode a u16-prefixed byte string.
-decodeU16Bytes
- :: BS.ByteString -> Either DecodeError (BS.ByteString, BS.ByteString)
-decodeU16Bytes !bs = do
- (len, rest1) <- decodeU16E bs
- let !n = fromIntegral len
- unless (BS.length rest1 >= n) $ Left DecodeInsufficientBytes
- Right (BS.take n rest1, BS.drop n rest1)
-{-# INLINE decodeU16Bytes #-}
-
--- | Decode optional trailing TLV stream.
-decodeOptionalTlvs
- :: BS.ByteString -> Either DecodeError (TlvStream, BS.ByteString)
-decodeOptionalTlvs !bs
- | BS.null bs = Right (unsafeTlvStream [], BS.empty)
- | otherwise = case decodeTlvStreamRaw bs of
- Left e -> Left (DecodeTlvError e)
- Right t -> Right (t, BS.empty)
-{-# INLINE decodeOptionalTlvs #-}
-
--- Channel establishment v1 ----------------------------------------------------
-
--- | Encode an OpenChannel message (type 32).
---
--- Wire format:
--- - chain_hash: 32 bytes
--- - temporary_channel_id: 32 bytes
--- - funding_satoshis: u64
--- - push_msat: u64
--- - dust_limit_satoshis: u64
--- - max_htlc_value_in_flight_msat: u64
--- - channel_reserve_satoshis: u64
--- - htlc_minimum_msat: u64
--- - feerate_per_kw: u32
--- - to_self_delay: u16
--- - max_accepted_htlcs: u16
--- - funding_pubkey: 33 bytes
--- - revocation_basepoint: 33 bytes
--- - payment_basepoint: 33 bytes
--- - delayed_payment_basepoint: 33 bytes
--- - htlc_basepoint: 33 bytes
--- - first_per_commitment_point: 33 bytes
--- - channel_flags: 1 byte
--- - tlvs: TLV stream
-encodeOpenChannel :: OpenChannel -> BS.ByteString
-encodeOpenChannel !msg = mconcat
- [ unChainHash (openChannelChainHash msg)
- , unChannelId (openChannelTempChannelId msg)
- , encodeU64 (unSatoshi (openChannelFundingSatoshi msg))
- , encodeU64 (unMilliSatoshi (openChannelPushMsat msg))
- , encodeU64 (unSatoshi (openChannelDustLimitSatoshi msg))
- , encodeU64 (unMilliSatoshi (openChannelMaxHtlcValueInFlight msg))
- , encodeU64 (unSatoshi (openChannelChannelReserveSat msg))
- , encodeU64 (unMilliSatoshi (openChannelHtlcMinimumMsat msg))
- , encodeU32 (openChannelFeeratePerKw msg)
- , encodeU16 (openChannelToSelfDelay msg)
- , encodeU16 (openChannelMaxAcceptedHtlcs msg)
- , unPoint (openChannelFundingPubkey msg)
- , unPoint (openChannelRevocationBasepoint msg)
- , unPoint (openChannelPaymentBasepoint msg)
- , unPoint (openChannelDelayedPaymentBase msg)
- , unPoint (openChannelHtlcBasepoint msg)
- , unPoint (openChannelFirstPerCommitPoint msg)
- , BS.singleton (openChannelChannelFlags msg)
- , encodeTlvStream (openChannelTlvs msg)
- ]
+ | otherwise = Right (BOLT1.encode_u16 (fromIntegral n))
+ where
+ !n = length xs
+{-# INLINE count_prefix #-}
+
+txid_bytes :: TxId -> BS.ByteString
+txid_bytes (TxId b) = b
+{-# INLINE txid_bytes #-}
+
+word8 :: Word8 -> BS.ByteString
+word8 = BS.singleton
+{-# INLINE word8 #-}
+
+-- encode a message's TLV stream: its typed records plus the unknown
+-- ones, which mustn't use a known type
+encode_tlvs
+ :: [Word64] -> [TlvRecord] -> TlvStream -> Either EncodeError BS.ByteString
+encode_tlvs known recs extra
+ | any ((`elem` known) . tlv_type) others = Left EncodeInvalidTlvs
+ | otherwise = case BOLT1.tlv_stream (recs <> others) of
+ Nothing -> Left EncodeInvalidTlvs
+ Just s -> Right (BOLT1.encode_tlv_stream s)
+ where
+ others = BOLT1.un_tlv_stream extra
+{-# INLINE encode_tlvs #-}
--- | Decode an OpenChannel message (type 32).
-decodeOpenChannel
- :: BS.ByteString -> Either DecodeError (OpenChannel, BS.ByteString)
-decodeOpenChannel !bs = do
- (chainHash', rest1) <- decodeChainHashBytes bs
- (tempChanId, rest2) <- decodeChannelIdBytes rest1
- (fundingSats, rest3) <- decodeSatoshi rest2
- (pushMsat, rest4) <- decodeMilliSatoshi rest3
- (dustLimit, rest5) <- decodeSatoshi rest4
- (maxHtlcVal, rest6) <- decodeMilliSatoshi rest5
- (chanReserve, rest7) <- decodeSatoshi rest6
- (htlcMin, rest8) <- decodeMilliSatoshi rest7
- (feerate, rest9) <- decodeU32E rest8
- (toSelfDelay, rest10) <- decodeU16E rest9
- (maxHtlcs, rest11) <- decodeU16E rest10
- (fundingPk, rest12) <- decodePointBytes rest11
- (revocBase, rest13) <- decodePointBytes rest12
- (paymentBase, rest14) <- decodePointBytes rest13
- (delayedBase, rest15) <- decodePointBytes rest14
- (htlcBase, rest16) <- decodePointBytes rest15
- (firstCommit, rest17) <- decodePointBytes rest16
- (flags, rest18) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU8 rest17)
- tlvs <- decodeTlvs rest18
- let !msg = OpenChannel
- { openChannelChainHash = chainHash'
- , openChannelTempChannelId = tempChanId
- , openChannelFundingSatoshi = fundingSats
- , openChannelPushMsat = pushMsat
- , openChannelDustLimitSatoshi = dustLimit
- , openChannelMaxHtlcValueInFlight = maxHtlcVal
- , openChannelChannelReserveSat = chanReserve
- , openChannelHtlcMinimumMsat = htlcMin
- , openChannelFeeratePerKw = feerate
- , openChannelToSelfDelay = toSelfDelay
- , openChannelMaxAcceptedHtlcs = maxHtlcs
- , openChannelFundingPubkey = fundingPk
- , openChannelRevocationBasepoint = revocBase
- , openChannelPaymentBasepoint = paymentBase
- , openChannelDelayedPaymentBase = delayedBase
- , openChannelHtlcBasepoint = htlcBase
- , openChannelFirstPerCommitPoint = firstCommit
- , openChannelChannelFlags = flags
- , openChannelTlvs = tlvs
- }
- Right (msg, BS.empty)
-
--- | Encode an AcceptChannel message (type 33).
---
--- Wire format:
--- - temporary_channel_id: 32 bytes
--- - dust_limit_satoshis: u64
--- - max_htlc_value_in_flight_msat: u64
--- - channel_reserve_satoshis: u64
--- - htlc_minimum_msat: u64
--- - minimum_depth: u32
--- - to_self_delay: u16
--- - max_accepted_htlcs: u16
--- - funding_pubkey: 33 bytes
--- - revocation_basepoint: 33 bytes
--- - payment_basepoint: 33 bytes
--- - delayed_payment_basepoint: 33 bytes
--- - htlc_basepoint: 33 bytes
--- - first_per_commitment_point: 33 bytes
--- - tlvs: TLV stream
-encodeAcceptChannel :: AcceptChannel -> BS.ByteString
-encodeAcceptChannel !msg = mconcat
- [ unChannelId (acceptChannelTempChannelId msg)
- , encodeU64 (unSatoshi (acceptChannelDustLimitSatoshi msg))
- , encodeU64 (unMilliSatoshi (acceptChannelMaxHtlcValueInFlight msg))
- , encodeU64 (unSatoshi (acceptChannelChannelReserveSat msg))
- , encodeU64 (unMilliSatoshi (acceptChannelHtlcMinimumMsat msg))
- , encodeU32 (acceptChannelMinimumDepth msg)
- , encodeU16 (acceptChannelToSelfDelay msg)
- , encodeU16 (acceptChannelMaxAcceptedHtlcs msg)
- , unPoint (acceptChannelFundingPubkey msg)
- , unPoint (acceptChannelRevocationBasepoint msg)
- , unPoint (acceptChannelPaymentBasepoint msg)
- , unPoint (acceptChannelDelayedPaymentBase msg)
- , unPoint (acceptChannelHtlcBasepoint msg)
- , unPoint (acceptChannelFirstPerCommitPoint msg)
- , encodeTlvStream (acceptChannelTlvs msg)
- ]
+opt :: Word64 -> (a -> BS.ByteString) -> Maybe a -> [TlvRecord]
+opt t f = maybe [] (\a -> [TlvRecord t (f a)])
+{-# INLINE opt #-}
--- | Decode an AcceptChannel message (type 33).
-decodeAcceptChannel
- :: BS.ByteString -> Either DecodeError (AcceptChannel, BS.ByteString)
-decodeAcceptChannel !bs = do
- (tempChanId, rest1) <- decodeChannelIdBytes bs
- (dustLimit, rest2) <- decodeSatoshi rest1
- (maxHtlcVal, rest3) <- decodeMilliSatoshi rest2
- (chanReserve, rest4) <- decodeSatoshi rest3
- (htlcMin, rest5) <- decodeMilliSatoshi rest4
- (minDepth, rest6) <- decodeU32E rest5
- (toSelfDelay, rest7) <- decodeU16E rest6
- (maxHtlcs, rest8) <- decodeU16E rest7
- (fundingPk, rest9) <- decodePointBytes rest8
- (revocBase, rest10) <- decodePointBytes rest9
- (paymentBase, rest11) <- decodePointBytes rest10
- (delayedBase, rest12) <- decodePointBytes rest11
- (htlcBase, rest13) <- decodePointBytes rest12
- (firstCommit, rest14) <- decodePointBytes rest13
- tlvs <- decodeTlvs rest14
- let !msg = AcceptChannel
- { acceptChannelTempChannelId = tempChanId
- , acceptChannelDustLimitSatoshi = dustLimit
- , acceptChannelMaxHtlcValueInFlight = maxHtlcVal
- , acceptChannelChannelReserveSat = chanReserve
- , acceptChannelHtlcMinimumMsat = htlcMin
- , acceptChannelMinimumDepth = minDepth
- , acceptChannelToSelfDelay = toSelfDelay
- , acceptChannelMaxAcceptedHtlcs = maxHtlcs
- , acceptChannelFundingPubkey = fundingPk
- , acceptChannelRevocationBasepoint = revocBase
- , acceptChannelPaymentBasepoint = paymentBase
- , acceptChannelDelayedPaymentBase = delayedBase
- , acceptChannelHtlcBasepoint = htlcBase
- , acceptChannelFirstPerCommitPoint = firstCommit
- , acceptChannelTlvs = tlvs
- }
- Right (msg, BS.empty)
-
--- | Encode a FundingCreated message (type 34).
---
--- Wire format:
--- - temporary_channel_id: 32 bytes
--- - funding_txid: 32 bytes
--- - funding_output_index: u16
--- - signature: 64 bytes
-encodeFundingCreated :: FundingCreated -> BS.ByteString
-encodeFundingCreated !msg = mconcat
- [ unChannelId (fundingCreatedTempChannelId msg)
- , let (TxId bs) = fundingCreatedFundingTxid msg in bs
- , encodeU16 (fundingCreatedFundingOutIdx msg)
- , unSignature (fundingCreatedSignature msg)
- ]
+opt_flag :: Word64 -> Bool -> [TlvRecord]
+opt_flag t b = if b then [TlvRecord t BS.empty] else []
+{-# INLINE opt_flag #-}
--- | Decode a FundingCreated message (type 34).
-decodeFundingCreated
- :: BS.ByteString -> Either DecodeError (FundingCreated, BS.ByteString)
-decodeFundingCreated !bs = do
- (tempChanId, rest1) <- decodeChannelIdBytes bs
- (fundingTxid, rest2) <- decodeTxIdBytes rest1
- (outIdx, rest3) <- decodeU16E rest2
- (sig, rest4) <- decodeSignatureBytes rest3
- let !msg = FundingCreated
- { fundingCreatedTempChannelId = tempChanId
- , fundingCreatedFundingTxid = fundingTxid
- , fundingCreatedFundingOutIdx = outIdx
- , fundingCreatedSignature = sig
- }
- Right (msg, rest4)
-
--- | Encode a FundingSigned message (type 35).
---
--- Wire format:
--- - channel_id: 32 bytes
--- - signature: 64 bytes
-encodeFundingSigned :: FundingSigned -> BS.ByteString
-encodeFundingSigned !msg = mconcat
- [ unChannelId (fundingSignedChannelId msg)
- , unSignature (fundingSignedSignature msg)
- ]
+fee_range_bytes :: FeeRange -> BS.ByteString
+fee_range_bytes (FeeRange lo hi) =
+ BOLT1.encode_satoshi lo <> BOLT1.encode_satoshi hi
--- | Decode a FundingSigned message (type 35).
-decodeFundingSigned
- :: BS.ByteString -> Either DecodeError (FundingSigned, BS.ByteString)
-decodeFundingSigned !bs = do
- (chanId, rest1) <- decodeChannelIdBytes bs
- (sig, rest2) <- decodeSignatureBytes rest1
- let !msg = FundingSigned
- { fundingSignedChannelId = chanId
- , fundingSignedSignature = sig
- }
- Right (msg, rest2)
-
--- | Encode a ChannelReady message (type 36).
---
--- Wire format:
--- - channel_id: 32 bytes
--- - second_per_commitment_point: 33 bytes
--- - tlvs: TLV stream
-encodeChannelReady :: ChannelReady -> BS.ByteString
-encodeChannelReady !msg = mconcat
- [ unChannelId (channelReadyChannelId msg)
- , unPoint (channelReadySecondPerCommitPoint msg)
- , encodeTlvStream (channelReadyTlvs msg)
- ]
+next_funding_bytes :: NextFunding -> BS.ByteString
+next_funding_bytes (NextFunding t f) = txid_bytes t <> word8 f
--- | Decode a ChannelReady message (type 36).
-decodeChannelReady
- :: BS.ByteString -> Either DecodeError (ChannelReady, BS.ByteString)
-decodeChannelReady !bs = do
- (chanId, rest1) <- decodeChannelIdBytes bs
- (secondCommit, rest2) <- decodePointBytes rest1
- tlvs <- decodeTlvs rest2
- let !msg = ChannelReady
- { channelReadyChannelId = chanId
- , channelReadySecondPerCommitPoint = secondCommit
- , channelReadyTlvs = tlvs
- }
- Right (msg, BS.empty)
-
--- Channel close ---------------------------------------------------------------
-
--- | Encode a Stfu message (type 2).
---
--- Wire format:
--- - channel_id: 32 bytes
--- - initiator: 1 byte
-encodeStfu :: Stfu -> BS.ByteString
-encodeStfu !msg = mconcat
- [ unChannelId (stfuChannelId msg)
- , BS.singleton $! case stfuInitiator msg of
- IsInitiator -> 1
- NotInitiator -> 0
- ]
+-- messages -------------------------------------------------------------------
--- | Decode a Stfu message (type 2).
-decodeStfu :: BS.ByteString -> Either DecodeError (Stfu, BS.ByteString)
-decodeStfu !bs = do
- (chanId, rest1) <- decodeChannelIdBytes bs
- (raw, rest2) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU8 rest1)
- ini <- case raw of
- 1 -> Right IsInitiator
- 0 -> Right NotInitiator
- _ -> Left DecodeInvalidInitiator
- let !msg = Stfu
- { stfuChannelId = chanId
- , stfuInitiator = ini
- }
- Right (msg, rest2)
-
--- | Encode a Shutdown message (type 38).
---
--- Wire format:
--- - channel_id: 32 bytes
--- - len: u16
--- - scriptpubkey: len bytes
-encodeShutdown :: Shutdown -> Either EncodeError BS.ByteString
-encodeShutdown !msg = do
- let !script = unScriptPubKey (shutdownScriptPubkey msg)
- !scriptLen = BS.length script
- if scriptLen > 65535
- then Left EncodeLengthOverflow
- else Right $ mconcat
- [ unChannelId (shutdownChannelId msg)
- , encodeU16 (fromIntegral scriptLen)
- , script
- ]
-
--- | Decode a Shutdown message (type 38).
-decodeShutdown
- :: BS.ByteString -> Either DecodeError (Shutdown, BS.ByteString)
-decodeShutdown !bs = do
- (chanId, rest1) <- decodeChannelIdBytes bs
- (script, rest2) <- decodeScriptPubKey rest1
- let !msg = Shutdown
- { shutdownChannelId = chanId
- , shutdownScriptPubkey = script
- }
- Right (msg, rest2)
-
--- | Encode a ClosingSigned message (type 39).
+-- | Encode a BOLT #2 message, including its type. Fails if a field
+-- can't be encoded or the result exceeds 65535 bytes.
--
--- Wire format:
--- - channel_id: 32 bytes
--- - fee_satoshis: u64
--- - signature: 64 bytes
--- - tlvs: TLV stream
-encodeClosingSigned :: ClosingSigned -> BS.ByteString
-encodeClosingSigned !msg = mconcat
- [ unChannelId (closingSignedChannelId msg)
- , encodeU64 (unSatoshi (closingSignedFeeSatoshi msg))
- , unSignature (closingSignedSignature msg)
- , encodeTlvStream (closingSignedTlvs msg)
- ]
-
--- | Decode a ClosingSigned message (type 39).
-decodeClosingSigned
- :: BS.ByteString -> Either DecodeError (ClosingSigned, BS.ByteString)
-decodeClosingSigned !bs = do
- (chanId, rest1) <- decodeChannelIdBytes bs
- (feeSats, rest2) <- decodeSatoshi rest1
- (sig, rest3) <- decodeSignatureBytes rest2
- tlvs <- decodeTlvs rest3
- let !msg = ClosingSigned
- { closingSignedChannelId = chanId
- , closingSignedFeeSatoshi = feeSats
- , closingSignedSignature = sig
- , closingSignedTlvs = tlvs
- }
- Right (msg, BS.empty)
-
--- | Encode a ClosingComplete message (type 40).
+-- >>> let stfu = Stfu cid True BOLT1.empty_tlv_stream
+-- >>> fmap BS.length (encode_message (MsgStfu stfu))
+-- Right 35
+encode_message :: Message -> Either EncodeError BS.ByteString
+encode_message m = do
+ payload <- case m of
+ MsgOpenChannel a -> encode_open_channel a
+ MsgAcceptChannel a -> encode_accept_channel a
+ MsgFundingCreated a -> Right (encode_funding_created a)
+ MsgFundingSigned a -> Right (encode_funding_signed a)
+ MsgChannelReady a -> encode_channel_ready a
+ MsgOpenChannel2 a -> encode_open_channel2 a
+ MsgAcceptChannel2 a -> encode_accept_channel2 a
+ MsgTxAddInput a -> encode_tx_add_input a
+ MsgTxAddOutput a -> Right (encode_tx_add_output a)
+ MsgTxRemoveInput a -> Right (encode_tx_remove_input a)
+ MsgTxRemoveOutput a -> Right (encode_tx_remove_output a)
+ MsgTxComplete a -> Right (encode_tx_complete a)
+ MsgTxSignatures a -> encode_tx_signatures a
+ MsgTxInitRbf a -> encode_tx_init_rbf a
+ MsgTxAckRbf a -> encode_tx_ack_rbf a
+ MsgTxAbort a -> encode_tx_abort a
+ MsgStfu a -> Right (encode_stfu a)
+ MsgShutdown a -> Right (encode_shutdown a)
+ MsgClosingComplete a -> encode_closing_complete a
+ MsgClosingSig a -> encode_closing_sig a
+ MsgClosingSigned a -> encode_closing_signed a
+ MsgUpdateAddHtlc a -> encode_update_add_htlc a
+ MsgUpdateFulfillHtlc a -> encode_update_fulfill_htlc a
+ MsgUpdateFailHtlc a -> encode_update_fail_htlc a
+ MsgUpdateFailMalformedHtlc a ->
+ Right (encode_update_fail_malformed_htlc a)
+ MsgCommitmentSigned a -> encode_commitment_signed a
+ MsgRevokeAndAck a -> Right (encode_revoke_and_ack a)
+ MsgUpdateFee a -> Right (encode_update_fee a)
+ MsgChannelReestablish a -> encode_channel_reestablish a
+ case BOLT1.encode_envelope (message_type m) payload of
+ Left _ -> Left EncodeMessageTooLarge
+ Right w -> Right w
+
+-- | Decode a BOLT #2 message, including its type.
--
--- Wire format:
--- - channel_id: 32 bytes
--- - len: u16 (closer script length)
--- - closer_script: len bytes
--- - len: u16 (closee script length)
--- - closee_script: len bytes
--- - fee_satoshis: u64
--- - locktime: u32
--- - tlvs: TLV stream
-encodeClosingComplete :: ClosingComplete -> Either EncodeError BS.ByteString
-encodeClosingComplete !msg = do
- let !closerScript = unScriptPubKey (closingCompleteCloserScript msg)
- !closeeScript = unScriptPubKey (closingCompleteCloseeScript msg)
- !closerLen = BS.length closerScript
- !closeeLen = BS.length closeeScript
- if closerLen > 65535 || closeeLen > 65535
- then Left EncodeLengthOverflow
- else Right $ mconcat
- [ unChannelId (closingCompleteChannelId msg)
- , encodeU16 (fromIntegral closerLen)
- , closerScript
- , encodeU16 (fromIntegral closeeLen)
- , closeeScript
- , encodeU64 (unSatoshi (closingCompleteFeeSatoshi msg))
- , encodeU32 (closingCompleteLocktime msg)
- , encodeTlvStream (closingCompleteTlvs msg)
- ]
-
--- | Decode a ClosingComplete message (type 40).
-decodeClosingComplete
- :: BS.ByteString -> Either DecodeError (ClosingComplete, BS.ByteString)
-decodeClosingComplete !bs = do
- (chanId, rest1) <- decodeChannelIdBytes bs
- (closerScript, rest2) <- decodeScriptPubKey rest1
- (closeeScript, rest3) <- decodeScriptPubKey rest2
- (feeSats, rest4) <- decodeSatoshi rest3
- (locktime, rest5) <- decodeU32E rest4
- tlvs <- decodeTlvs rest5
- let !msg = ClosingComplete
- { closingCompleteChannelId = chanId
- , closingCompleteCloserScript = closerScript
- , closingCompleteCloseeScript = closeeScript
- , closingCompleteFeeSatoshi = feeSats
- , closingCompleteLocktime = locktime
- , closingCompleteTlvs = tlvs
- }
- Right (msg, BS.empty)
-
--- | Encode a ClosingSig message (type 41).
+-- A type that BOLT #2 doesn't define (including the splicing
+-- messages, which this library doesn't implement) yields
+-- 'DecodeUnknownEvenType' or 'DecodeUnknownOddType'.
--
--- Wire format:
--- - channel_id: 32 bytes
--- - len: u16 (closer script length)
--- - closer_script: len bytes
--- - len: u16 (closee script length)
--- - closee_script: len bytes
--- - fee_satoshis: u64
--- - locktime: u32
--- - tlvs: TLV stream
-encodeClosingSig :: ClosingSig -> Either EncodeError BS.ByteString
-encodeClosingSig !msg = do
- let !closerScript = unScriptPubKey (closingSigCloserScript msg)
- !closeeScript = unScriptPubKey (closingSigCloseeScript msg)
- !closerLen = BS.length closerScript
- !closeeLen = BS.length closeeScript
- if closerLen > 65535 || closeeLen > 65535
- then Left EncodeLengthOverflow
- else Right $ mconcat
- [ unChannelId (closingSigChannelId msg)
- , encodeU16 (fromIntegral closerLen)
- , closerScript
- , encodeU16 (fromIntegral closeeLen)
- , closeeScript
- , encodeU64 (unSatoshi (closingSigFeeSatoshi msg))
- , encodeU32 (closingSigLocktime msg)
- , encodeTlvStream (closingSigTlvs msg)
- ]
-
--- | Decode a ClosingSig message (type 41).
-decodeClosingSig
- :: BS.ByteString -> Either DecodeError (ClosingSig, BS.ByteString)
-decodeClosingSig !bs = do
- (chanId, rest1) <- decodeChannelIdBytes bs
- (closerScript, rest2) <- decodeScriptPubKey rest1
- (closeeScript, rest3) <- decodeScriptPubKey rest2
- (feeSats, rest4) <- decodeSatoshi rest3
- (locktime, rest5) <- decodeU32E rest4
- tlvs <- decodeTlvs rest5
- let !msg = ClosingSig
- { closingSigChannelId = chanId
- , closingSigCloserScript = closerScript
- , closingSigCloseeScript = closeeScript
- , closingSigFeeSatoshi = feeSats
- , closingSigLocktime = locktime
- , closingSigTlvs = tlvs
- }
- Right (msg, BS.empty)
-
--- Channel establishment v2 (interactive-tx) -----------------------------------
-
--- | Encode an OpenChannel2 message (type 64).
-encodeOpenChannel2 :: OpenChannel2 -> BS.ByteString
-encodeOpenChannel2 !msg = mconcat
- [ unChainHash (openChannel2ChainHash msg)
- , unChannelId (openChannel2TempChannelId msg)
- , encodeU32 (openChannel2FundingFeeratePerkw msg)
- , encodeU32 (openChannel2CommitFeeratePerkw msg)
- , encodeU64 (unSatoshi (openChannel2FundingSatoshi msg))
- , encodeU64 (unSatoshi (openChannel2DustLimitSatoshi msg))
- , encodeU64 (unMilliSatoshi (openChannel2MaxHtlcValueInFlight msg))
- , encodeU64 (unMilliSatoshi (openChannel2HtlcMinimumMsat msg))
- , encodeU16 (openChannel2ToSelfDelay msg)
- , encodeU16 (openChannel2MaxAcceptedHtlcs msg)
- , encodeU32 (openChannel2Locktime msg)
- , unPoint (openChannel2FundingPubkey msg)
- , unPoint (openChannel2RevocationBasepoint msg)
- , unPoint (openChannel2PaymentBasepoint msg)
- , unPoint (openChannel2DelayedPaymentBase msg)
- , unPoint (openChannel2HtlcBasepoint msg)
- , unPoint (openChannel2FirstPerCommitPoint msg)
- , unPoint (openChannel2SecondPerCommitPoint msg)
- , BS.singleton (openChannel2ChannelFlags msg)
- , encodeTlvStream (openChannel2Tlvs msg)
+-- >>> let wire = "\x00\x02" <> BS.replicate 32 0xab <> "\x01"
+-- >>> fmap message_type (decode_message wire)
+-- Right 2
+-- >>> decode_message "\x00\x50"
+-- Left (DecodeUnknownEvenType 80)
+decode_message :: BS.ByteString -> Either DecodeError Message
+decode_message bs = do
+ (t, payload) <- case BOLT1.decode_envelope bs of
+ Left _ -> Left DecodeInsufficientBytes
+ Right r -> Right r
+ case t of
+ 32 -> MsgOpenChannel <$> decode_open_channel payload
+ 33 -> MsgAcceptChannel <$> decode_accept_channel payload
+ 34 -> MsgFundingCreated <$> decode_funding_created payload
+ 35 -> MsgFundingSigned <$> decode_funding_signed payload
+ 36 -> MsgChannelReady <$> decode_channel_ready payload
+ 64 -> MsgOpenChannel2 <$> decode_open_channel2 payload
+ 65 -> MsgAcceptChannel2 <$> decode_accept_channel2 payload
+ 66 -> MsgTxAddInput <$> decode_tx_add_input payload
+ 67 -> MsgTxAddOutput <$> decode_tx_add_output payload
+ 68 -> MsgTxRemoveInput <$> decode_tx_remove_input payload
+ 69 -> MsgTxRemoveOutput <$> decode_tx_remove_output payload
+ 70 -> MsgTxComplete <$> decode_tx_complete payload
+ 71 -> MsgTxSignatures <$> decode_tx_signatures payload
+ 72 -> MsgTxInitRbf <$> decode_tx_init_rbf payload
+ 73 -> MsgTxAckRbf <$> decode_tx_ack_rbf payload
+ 74 -> MsgTxAbort <$> decode_tx_abort payload
+ 2 -> MsgStfu <$> decode_stfu payload
+ 38 -> MsgShutdown <$> decode_shutdown payload
+ 40 -> MsgClosingComplete <$> decode_closing_complete payload
+ 41 -> MsgClosingSig <$> decode_closing_sig payload
+ 39 -> MsgClosingSigned <$> decode_closing_signed payload
+ 128 -> MsgUpdateAddHtlc <$> decode_update_add_htlc payload
+ 130 -> MsgUpdateFulfillHtlc <$> decode_update_fulfill_htlc payload
+ 131 -> MsgUpdateFailHtlc <$> decode_update_fail_htlc payload
+ 135 -> MsgUpdateFailMalformedHtlc <$>
+ decode_update_fail_malformed_htlc payload
+ 132 -> MsgCommitmentSigned <$> decode_commitment_signed payload
+ 133 -> MsgRevokeAndAck <$> decode_revoke_and_ack payload
+ 134 -> MsgUpdateFee <$> decode_update_fee payload
+ 136 -> MsgChannelReestablish <$> decode_channel_reestablish payload
+ _ | even t -> Left (DecodeUnknownEvenType t)
+ | otherwise -> Left (DecodeUnknownOddType t)
+
+-- open_channel ---------------------------------------------------------------
+
+open_channel_known :: [Word64]
+open_channel_known = [0, 1]
+
+-- | Encode an 'OpenChannel' payload.
+encode_open_channel :: OpenChannel -> Either EncodeError BS.ByteString
+encode_open_channel m = do
+ ts <- encode_tlvs open_channel_known
+ ( opt 0 un_script_pubkey (open_channel_upfront_shutdown_script m)
+ <> opt 1 BOLT9.render (open_channel_channel_type m) )
+ (open_channel_tlvs m)
+ pure $ mconcat [
+ BOLT1.un_chain_hash (open_channel_chain_hash m)
+ , BOLT1.un_channel_id (open_channel_temporary_channel_id m)
+ , BOLT1.encode_satoshi (open_channel_funding_satoshis m)
+ , BOLT1.encode_milli_satoshi (open_channel_push_msat m)
+ , BOLT1.encode_satoshi (open_channel_dust_limit_satoshis m)
+ , BOLT1.encode_u64 (open_channel_max_htlc_value_in_flight_msat m)
+ , BOLT1.encode_satoshi (open_channel_channel_reserve_satoshis m)
+ , BOLT1.encode_milli_satoshi (open_channel_htlc_minimum_msat m)
+ , BOLT1.encode_u32 (open_channel_feerate_per_kw m)
+ , BOLT1.encode_u16 (open_channel_to_self_delay m)
+ , BOLT1.encode_u16 (open_channel_max_accepted_htlcs m)
+ , BOLT1.un_point (open_channel_funding_pubkey m)
+ , BOLT1.un_point (open_channel_revocation_basepoint m)
+ , BOLT1.un_point (open_channel_payment_basepoint m)
+ , BOLT1.un_point (open_channel_delayed_payment_basepoint m)
+ , BOLT1.un_point (open_channel_htlc_basepoint m)
+ , BOLT1.un_point (open_channel_first_per_commitment_point m)
+ , word8 (open_channel_channel_flags m)
+ , ts
+ ]
+
+-- | Decode an 'OpenChannel' payload.
+decode_open_channel :: BS.ByteString -> Either DecodeError OpenChannel
+decode_open_channel = parse $ do
+ ch <- chain_hash
+ tcid <- channel_id
+ fund <- satoshi
+ push <- milli_satoshi
+ dust <- satoshi
+ maxv <- u64
+ res <- satoshi
+ hmin <- milli_satoshi
+ fee <- u32
+ delay <- u16
+ maxa <- u16
+ fpk <- point
+ rev <- point
+ pay <- point
+ del <- point
+ htlc <- point
+ pcp <- point
+ flags <- u8
+ s <- tlvs open_channel_known
+ shut <- record 0 script_pubkey s
+ ctype <- record 1 (Just . BOLT9.parse) s
+ pure OpenChannel {
+ open_channel_chain_hash = ch
+ , open_channel_temporary_channel_id = tcid
+ , open_channel_funding_satoshis = fund
+ , open_channel_push_msat = push
+ , open_channel_dust_limit_satoshis = dust
+ , open_channel_max_htlc_value_in_flight_msat = maxv
+ , open_channel_channel_reserve_satoshis = res
+ , open_channel_htlc_minimum_msat = hmin
+ , open_channel_feerate_per_kw = fee
+ , open_channel_to_self_delay = delay
+ , open_channel_max_accepted_htlcs = maxa
+ , open_channel_funding_pubkey = fpk
+ , open_channel_revocation_basepoint = rev
+ , open_channel_payment_basepoint = pay
+ , open_channel_delayed_payment_basepoint = del
+ , open_channel_htlc_basepoint = htlc
+ , open_channel_first_per_commitment_point = pcp
+ , open_channel_channel_flags = flags
+ , open_channel_upfront_shutdown_script = shut
+ , open_channel_channel_type = ctype
+ , open_channel_tlvs = unknown open_channel_known s
+ }
+
+-- accept_channel -------------------------------------------------------------
+
+accept_channel_known :: [Word64]
+accept_channel_known = [0, 1]
+
+-- | Encode an 'AcceptChannel' payload.
+encode_accept_channel :: AcceptChannel -> Either EncodeError BS.ByteString
+encode_accept_channel m = do
+ ts <- encode_tlvs accept_channel_known
+ ( opt 0 un_script_pubkey (accept_channel_upfront_shutdown_script m)
+ <> opt 1 BOLT9.render (accept_channel_channel_type m) )
+ (accept_channel_tlvs m)
+ pure $ mconcat [
+ BOLT1.un_channel_id (accept_channel_temporary_channel_id m)
+ , BOLT1.encode_satoshi (accept_channel_dust_limit_satoshis m)
+ , BOLT1.encode_u64 (accept_channel_max_htlc_value_in_flight_msat m)
+ , BOLT1.encode_satoshi (accept_channel_channel_reserve_satoshis m)
+ , BOLT1.encode_milli_satoshi (accept_channel_htlc_minimum_msat m)
+ , BOLT1.encode_u32 (accept_channel_minimum_depth m)
+ , BOLT1.encode_u16 (accept_channel_to_self_delay m)
+ , BOLT1.encode_u16 (accept_channel_max_accepted_htlcs m)
+ , BOLT1.un_point (accept_channel_funding_pubkey m)
+ , BOLT1.un_point (accept_channel_revocation_basepoint m)
+ , BOLT1.un_point (accept_channel_payment_basepoint m)
+ , BOLT1.un_point (accept_channel_delayed_payment_basepoint m)
+ , BOLT1.un_point (accept_channel_htlc_basepoint m)
+ , BOLT1.un_point (accept_channel_first_per_commitment_point m)
+ , ts
+ ]
+
+-- | Decode an 'AcceptChannel' payload.
+decode_accept_channel :: BS.ByteString -> Either DecodeError AcceptChannel
+decode_accept_channel = parse $ do
+ tcid <- channel_id
+ dust <- satoshi
+ maxv <- u64
+ res <- satoshi
+ hmin <- milli_satoshi
+ depth <- u32
+ delay <- u16
+ maxa <- u16
+ fpk <- point
+ rev <- point
+ pay <- point
+ del <- point
+ htlc <- point
+ pcp <- point
+ s <- tlvs accept_channel_known
+ shut <- record 0 script_pubkey s
+ ctype <- record 1 (Just . BOLT9.parse) s
+ pure AcceptChannel {
+ accept_channel_temporary_channel_id = tcid
+ , accept_channel_dust_limit_satoshis = dust
+ , accept_channel_max_htlc_value_in_flight_msat = maxv
+ , accept_channel_channel_reserve_satoshis = res
+ , accept_channel_htlc_minimum_msat = hmin
+ , accept_channel_minimum_depth = depth
+ , accept_channel_to_self_delay = delay
+ , accept_channel_max_accepted_htlcs = maxa
+ , accept_channel_funding_pubkey = fpk
+ , accept_channel_revocation_basepoint = rev
+ , accept_channel_payment_basepoint = pay
+ , accept_channel_delayed_payment_basepoint = del
+ , accept_channel_htlc_basepoint = htlc
+ , accept_channel_first_per_commitment_point = pcp
+ , accept_channel_upfront_shutdown_script = shut
+ , accept_channel_channel_type = ctype
+ , accept_channel_tlvs = unknown accept_channel_known s
+ }
+
+-- funding_created, funding_signed --------------------------------------------
+
+-- | Encode a 'FundingCreated' payload.
+encode_funding_created :: FundingCreated -> BS.ByteString
+encode_funding_created m = mconcat [
+ BOLT1.un_channel_id (funding_created_temporary_channel_id m)
+ , txid_bytes (funding_created_funding_txid m)
+ , BOLT1.encode_u16 (funding_created_funding_output_index m)
+ , BOLT1.un_signature (funding_created_signature m)
+ , BOLT1.encode_tlv_stream (funding_created_tlvs m)
]
--- | Decode an OpenChannel2 message (type 64).
-decodeOpenChannel2
- :: BS.ByteString -> Either DecodeError (OpenChannel2, BS.ByteString)
-decodeOpenChannel2 !bs = do
- (ch, rest1) <- decodeChainHashBytes bs
- (tempCid, rest2) <- decodeChannelIdBytes rest1
- (fundingFeerate, rest3) <- decodeU32E rest2
- (commitFeerate, rest4) <- decodeU32E rest3
- (fundingSats, rest5) <- decodeSatoshi rest4
- (dustLimit, rest6) <- decodeSatoshi rest5
- (maxHtlcVal, rest7) <- decodeMilliSatoshi rest6
- (htlcMin, rest8) <- decodeMilliSatoshi rest7
- (toSelfDelay, rest9) <- decodeU16E rest8
- (maxHtlcs, rest10) <- decodeU16E rest9
- (locktime, rest11) <- decodeU32E rest10
- (fundingPk, rest12) <- decodePointBytes rest11
- (revBase, rest13) <- decodePointBytes rest12
- (payBase, rest14) <- decodePointBytes rest13
- (delayBase, rest15) <- decodePointBytes rest14
- (htlcBase, rest16) <- decodePointBytes rest15
- (firstPt, rest17) <- decodePointBytes rest16
- (secondPt, rest18) <- decodePointBytes rest17
- (flags, rest19) <- maybe (Left DecodeInsufficientBytes) Right (decodeU8 rest18)
- tlvs <- decodeTlvs rest19
- let !msg = OpenChannel2
- { openChannel2ChainHash = ch
- , openChannel2TempChannelId = tempCid
- , openChannel2FundingFeeratePerkw = fundingFeerate
- , openChannel2CommitFeeratePerkw = commitFeerate
- , openChannel2FundingSatoshi = fundingSats
- , openChannel2DustLimitSatoshi = dustLimit
- , openChannel2MaxHtlcValueInFlight = maxHtlcVal
- , openChannel2HtlcMinimumMsat = htlcMin
- , openChannel2ToSelfDelay = toSelfDelay
- , openChannel2MaxAcceptedHtlcs = maxHtlcs
- , openChannel2Locktime = locktime
- , openChannel2FundingPubkey = fundingPk
- , openChannel2RevocationBasepoint = revBase
- , openChannel2PaymentBasepoint = payBase
- , openChannel2DelayedPaymentBase = delayBase
- , openChannel2HtlcBasepoint = htlcBase
- , openChannel2FirstPerCommitPoint = firstPt
- , openChannel2SecondPerCommitPoint = secondPt
- , openChannel2ChannelFlags = flags
- , openChannel2Tlvs = tlvs
- }
- Right (msg, BS.empty)
-
--- | Encode an AcceptChannel2 message (type 65).
-encodeAcceptChannel2 :: AcceptChannel2 -> BS.ByteString
-encodeAcceptChannel2 !msg = mconcat
- [ unChannelId (acceptChannel2TempChannelId msg)
- , encodeU64 (unSatoshi (acceptChannel2FundingSatoshi msg))
- , encodeU64 (unSatoshi (acceptChannel2DustLimitSatoshi msg))
- , encodeU64 (unMilliSatoshi (acceptChannel2MaxHtlcValueInFlight msg))
- , encodeU64 (unMilliSatoshi (acceptChannel2HtlcMinimumMsat msg))
- , encodeU32 (acceptChannel2MinimumDepth msg)
- , encodeU16 (acceptChannel2ToSelfDelay msg)
- , encodeU16 (acceptChannel2MaxAcceptedHtlcs msg)
- , unPoint (acceptChannel2FundingPubkey msg)
- , unPoint (acceptChannel2RevocationBasepoint msg)
- , unPoint (acceptChannel2PaymentBasepoint msg)
- , unPoint (acceptChannel2DelayedPaymentBase msg)
- , unPoint (acceptChannel2HtlcBasepoint msg)
- , unPoint (acceptChannel2FirstPerCommitPoint msg)
- , unPoint (acceptChannel2SecondPerCommitPoint msg)
- , encodeTlvStream (acceptChannel2Tlvs msg)
+-- | Decode a 'FundingCreated' payload.
+decode_funding_created :: BS.ByteString -> Either DecodeError FundingCreated
+decode_funding_created = parse $
+ FundingCreated <$> channel_id <*> txid <*> u16 <*> signature <*> tlvs []
+
+-- | Encode a 'FundingSigned' payload.
+encode_funding_signed :: FundingSigned -> BS.ByteString
+encode_funding_signed m = mconcat [
+ BOLT1.un_channel_id (funding_signed_channel_id m)
+ , BOLT1.un_signature (funding_signed_signature m)
+ , BOLT1.encode_tlv_stream (funding_signed_tlvs m)
]
--- | Decode an AcceptChannel2 message (type 65).
-decodeAcceptChannel2
- :: BS.ByteString -> Either DecodeError (AcceptChannel2, BS.ByteString)
-decodeAcceptChannel2 !bs = do
- (tempCid, rest1) <- decodeChannelIdBytes bs
- (fundingSats, rest2) <- decodeSatoshi rest1
- (dustLimit, rest3) <- decodeSatoshi rest2
- (maxHtlcVal, rest4) <- decodeMilliSatoshi rest3
- (htlcMin, rest5) <- decodeMilliSatoshi rest4
- (minDepth, rest6) <- decodeU32E rest5
- (toSelfDelay, rest7) <- decodeU16E rest6
- (maxHtlcs, rest8) <- decodeU16E rest7
- (fundingPk, rest9) <- decodePointBytes rest8
- (revBase, rest10) <- decodePointBytes rest9
- (payBase, rest11) <- decodePointBytes rest10
- (delayBase, rest12) <- decodePointBytes rest11
- (htlcBase, rest13) <- decodePointBytes rest12
- (firstPt, rest14) <- decodePointBytes rest13
- (secondPt, rest15) <- decodePointBytes rest14
- tlvs <- decodeTlvs rest15
- let !msg = AcceptChannel2
- { acceptChannel2TempChannelId = tempCid
- , acceptChannel2FundingSatoshi = fundingSats
- , acceptChannel2DustLimitSatoshi = dustLimit
- , acceptChannel2MaxHtlcValueInFlight = maxHtlcVal
- , acceptChannel2HtlcMinimumMsat = htlcMin
- , acceptChannel2MinimumDepth = minDepth
- , acceptChannel2ToSelfDelay = toSelfDelay
- , acceptChannel2MaxAcceptedHtlcs = maxHtlcs
- , acceptChannel2FundingPubkey = fundingPk
- , acceptChannel2RevocationBasepoint = revBase
- , acceptChannel2PaymentBasepoint = payBase
- , acceptChannel2DelayedPaymentBase = delayBase
- , acceptChannel2HtlcBasepoint = htlcBase
- , acceptChannel2FirstPerCommitPoint = firstPt
- , acceptChannel2SecondPerCommitPoint = secondPt
- , acceptChannel2Tlvs = tlvs
- }
- Right (msg, BS.empty)
-
--- | Encode a TxAddInput message (type 66).
-encodeTxAddInput :: TxAddInput -> Either EncodeError BS.ByteString
-encodeTxAddInput !msg = do
- prevTxEnc <- encodeU16BytesE (txAddInputPrevTx msg)
- Right $! mconcat
- [ unChannelId (txAddInputChannelId msg)
- , encodeU64 (unSerialId (txAddInputSerialId msg))
- , prevTxEnc
- , encodeU32 (txAddInputPrevVout msg)
- , encodeU32 (txAddInputSequence msg)
+-- | Decode a 'FundingSigned' payload.
+decode_funding_signed :: BS.ByteString -> Either DecodeError FundingSigned
+decode_funding_signed = parse $
+ FundingSigned <$> channel_id <*> signature <*> tlvs []
+
+-- channel_ready --------------------------------------------------------------
+
+channel_ready_known :: [Word64]
+channel_ready_known = [1]
+
+-- | Encode a 'ChannelReady' payload.
+encode_channel_ready :: ChannelReady -> Either EncodeError BS.ByteString
+encode_channel_ready m = do
+ ts <- encode_tlvs channel_ready_known
+ (opt 1 BOLT1.encode_short_channel_id (channel_ready_alias m))
+ (channel_ready_tlvs m)
+ pure $ mconcat [
+ BOLT1.un_channel_id (channel_ready_channel_id m)
+ , BOLT1.un_point (channel_ready_second_per_commitment_point m)
+ , ts
]
--- | Decode a TxAddInput message (type 66).
-decodeTxAddInput
- :: BS.ByteString -> Either DecodeError (TxAddInput, BS.ByteString)
-decodeTxAddInput !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (sid, rest2) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU64 rest1)
- (prevTx, rest3) <- decodeU16Bytes rest2
- (prevVout, rest4) <- decodeU32E rest3
- (seqNum, rest5) <- decodeU32E rest4
- let !msg = TxAddInput
- { txAddInputChannelId = cid
- , txAddInputSerialId = serialId sid
- , txAddInputPrevTx = prevTx
- , txAddInputPrevVout = prevVout
- , txAddInputSequence = seqNum
- }
- Right (msg, rest5)
-
--- | Encode a TxAddOutput message (type 67).
-encodeTxAddOutput :: TxAddOutput -> Either EncodeError BS.ByteString
-encodeTxAddOutput !msg = do
- scriptEnc <- encodeU16BytesE (unScriptPubKey (txAddOutputScript msg))
- Right $! mconcat
- [ unChannelId (txAddOutputChannelId msg)
- , encodeU64 (unSerialId (txAddOutputSerialId msg))
- , encodeU64 (unSatoshi (txAddOutputSats msg))
- , scriptEnc
+-- | Decode a 'ChannelReady' payload.
+decode_channel_ready :: BS.ByteString -> Either DecodeError ChannelReady
+decode_channel_ready = parse $ do
+ cid <- channel_id
+ pcp <- point
+ s <- tlvs channel_ready_known
+ alias <- record 1 (whole BOLT1.decode_short_channel_id) s
+ pure (ChannelReady cid pcp alias (unknown channel_ready_known s))
+
+-- open_channel2 --------------------------------------------------------------
+
+opening_known :: [Word64]
+opening_known = [0, 1, 2]
+
+-- | Encode an 'OpenChannel2' payload.
+encode_open_channel2 :: OpenChannel2 -> Either EncodeError BS.ByteString
+encode_open_channel2 m = do
+ ts <- encode_tlvs opening_known
+ ( opt 0 un_script_pubkey (open_channel2_upfront_shutdown_script m)
+ <> opt 1 BOLT9.render (open_channel2_channel_type m)
+ <> opt_flag 2 (open_channel2_require_confirmed_inputs m) )
+ (open_channel2_tlvs m)
+ pure $ mconcat [
+ BOLT1.un_chain_hash (open_channel2_chain_hash m)
+ , BOLT1.un_channel_id (open_channel2_temporary_channel_id m)
+ , BOLT1.encode_u32 (open_channel2_funding_feerate_perkw m)
+ , BOLT1.encode_u32 (open_channel2_commitment_feerate_perkw m)
+ , BOLT1.encode_satoshi (open_channel2_funding_satoshis m)
+ , BOLT1.encode_satoshi (open_channel2_dust_limit_satoshis m)
+ , BOLT1.encode_u64 (open_channel2_max_htlc_value_in_flight_msat m)
+ , BOLT1.encode_milli_satoshi (open_channel2_htlc_minimum_msat m)
+ , BOLT1.encode_u16 (open_channel2_to_self_delay m)
+ , BOLT1.encode_u16 (open_channel2_max_accepted_htlcs m)
+ , BOLT1.encode_u32 (open_channel2_locktime m)
+ , BOLT1.un_point (open_channel2_funding_pubkey m)
+ , BOLT1.un_point (open_channel2_revocation_basepoint m)
+ , BOLT1.un_point (open_channel2_payment_basepoint m)
+ , BOLT1.un_point (open_channel2_delayed_payment_basepoint m)
+ , BOLT1.un_point (open_channel2_htlc_basepoint m)
+ , BOLT1.un_point (open_channel2_first_per_commitment_point m)
+ , BOLT1.un_point (open_channel2_second_per_commitment_point m)
+ , word8 (open_channel2_channel_flags m)
+ , ts
]
--- | Decode a TxAddOutput message (type 67).
-decodeTxAddOutput
- :: BS.ByteString -> Either DecodeError (TxAddOutput, BS.ByteString)
-decodeTxAddOutput !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (sid, rest2) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU64 rest1)
- (sats, rest3) <- decodeSatoshi rest2
- (scriptBs, rest4) <- decodeU16Bytes rest3
- let !msg = TxAddOutput
- { txAddOutputChannelId = cid
- , txAddOutputSerialId = serialId sid
- , txAddOutputSats = sats
- , txAddOutputScript = scriptPubKey scriptBs
- }
- Right (msg, rest4)
-
--- | Encode a TxRemoveInput message (type 68).
-encodeTxRemoveInput :: TxRemoveInput -> BS.ByteString
-encodeTxRemoveInput !msg = mconcat
- [ unChannelId (txRemoveInputChannelId msg)
- , encodeU64 (unSerialId (txRemoveInputSerialId msg))
+-- | Decode an 'OpenChannel2' payload.
+decode_open_channel2 :: BS.ByteString -> Either DecodeError OpenChannel2
+decode_open_channel2 = parse $ do
+ ch <- chain_hash
+ tcid <- channel_id
+ ffee <- u32
+ cfee <- u32
+ fund <- satoshi
+ dust <- satoshi
+ maxv <- u64
+ hmin <- milli_satoshi
+ delay <- u16
+ maxa <- u16
+ lock <- u32
+ fpk <- point
+ rev <- point
+ pay <- point
+ del <- point
+ htlc <- point
+ pcp1 <- point
+ pcp2 <- point
+ flags <- u8
+ s <- tlvs opening_known
+ shut <- record 0 script_pubkey s
+ ctype <- record 1 (Just . BOLT9.parse) s
+ conf <- flag 2 s
+ pure OpenChannel2 {
+ open_channel2_chain_hash = ch
+ , open_channel2_temporary_channel_id = tcid
+ , open_channel2_funding_feerate_perkw = ffee
+ , open_channel2_commitment_feerate_perkw = cfee
+ , open_channel2_funding_satoshis = fund
+ , open_channel2_dust_limit_satoshis = dust
+ , open_channel2_max_htlc_value_in_flight_msat = maxv
+ , open_channel2_htlc_minimum_msat = hmin
+ , open_channel2_to_self_delay = delay
+ , open_channel2_max_accepted_htlcs = maxa
+ , open_channel2_locktime = lock
+ , open_channel2_funding_pubkey = fpk
+ , open_channel2_revocation_basepoint = rev
+ , open_channel2_payment_basepoint = pay
+ , open_channel2_delayed_payment_basepoint = del
+ , open_channel2_htlc_basepoint = htlc
+ , open_channel2_first_per_commitment_point = pcp1
+ , open_channel2_second_per_commitment_point = pcp2
+ , open_channel2_channel_flags = flags
+ , open_channel2_upfront_shutdown_script = shut
+ , open_channel2_channel_type = ctype
+ , open_channel2_require_confirmed_inputs = conf
+ , open_channel2_tlvs = unknown opening_known s
+ }
+
+-- accept_channel2 ------------------------------------------------------------
+
+-- | Encode an 'AcceptChannel2' payload.
+encode_accept_channel2 :: AcceptChannel2 -> Either EncodeError BS.ByteString
+encode_accept_channel2 m = do
+ ts <- encode_tlvs opening_known
+ ( opt 0 un_script_pubkey (accept_channel2_upfront_shutdown_script m)
+ <> opt 1 BOLT9.render (accept_channel2_channel_type m)
+ <> opt_flag 2 (accept_channel2_require_confirmed_inputs m) )
+ (accept_channel2_tlvs m)
+ pure $ mconcat [
+ BOLT1.un_channel_id (accept_channel2_temporary_channel_id m)
+ , BOLT1.encode_satoshi (accept_channel2_funding_satoshis m)
+ , BOLT1.encode_satoshi (accept_channel2_dust_limit_satoshis m)
+ , BOLT1.encode_u64 (accept_channel2_max_htlc_value_in_flight_msat m)
+ , BOLT1.encode_milli_satoshi (accept_channel2_htlc_minimum_msat m)
+ , BOLT1.encode_u32 (accept_channel2_minimum_depth m)
+ , BOLT1.encode_u16 (accept_channel2_to_self_delay m)
+ , BOLT1.encode_u16 (accept_channel2_max_accepted_htlcs m)
+ , BOLT1.un_point (accept_channel2_funding_pubkey m)
+ , BOLT1.un_point (accept_channel2_revocation_basepoint m)
+ , BOLT1.un_point (accept_channel2_payment_basepoint m)
+ , BOLT1.un_point (accept_channel2_delayed_payment_basepoint m)
+ , BOLT1.un_point (accept_channel2_htlc_basepoint m)
+ , BOLT1.un_point (accept_channel2_first_per_commitment_point m)
+ , BOLT1.un_point (accept_channel2_second_per_commitment_point m)
+ , ts
+ ]
+
+-- | Decode an 'AcceptChannel2' payload.
+decode_accept_channel2 :: BS.ByteString -> Either DecodeError AcceptChannel2
+decode_accept_channel2 = parse $ do
+ tcid <- channel_id
+ fund <- satoshi
+ dust <- satoshi
+ maxv <- u64
+ hmin <- milli_satoshi
+ depth <- u32
+ delay <- u16
+ maxa <- u16
+ fpk <- point
+ rev <- point
+ pay <- point
+ del <- point
+ htlc <- point
+ pcp1 <- point
+ pcp2 <- point
+ s <- tlvs opening_known
+ shut <- record 0 script_pubkey s
+ ctype <- record 1 (Just . BOLT9.parse) s
+ conf <- flag 2 s
+ pure AcceptChannel2 {
+ accept_channel2_temporary_channel_id = tcid
+ , accept_channel2_funding_satoshis = fund
+ , accept_channel2_dust_limit_satoshis = dust
+ , accept_channel2_max_htlc_value_in_flight_msat = maxv
+ , accept_channel2_htlc_minimum_msat = hmin
+ , accept_channel2_minimum_depth = depth
+ , accept_channel2_to_self_delay = delay
+ , accept_channel2_max_accepted_htlcs = maxa
+ , accept_channel2_funding_pubkey = fpk
+ , accept_channel2_revocation_basepoint = rev
+ , accept_channel2_payment_basepoint = pay
+ , accept_channel2_delayed_payment_basepoint = del
+ , accept_channel2_htlc_basepoint = htlc
+ , accept_channel2_first_per_commitment_point = pcp1
+ , accept_channel2_second_per_commitment_point = pcp2
+ , accept_channel2_upfront_shutdown_script = shut
+ , accept_channel2_channel_type = ctype
+ , accept_channel2_require_confirmed_inputs = conf
+ , accept_channel2_tlvs = unknown opening_known s
+ }
+
+-- interactive transaction construction ---------------------------------------
+
+-- | Encode a 'TxAddInput' payload. Fails if @prevtx@ exceeds 65535
+-- bytes.
+encode_tx_add_input :: TxAddInput -> Either EncodeError BS.ByteString
+encode_tx_add_input m = do
+ prev <- u16_prefixed (tx_add_input_prevtx m)
+ let SerialId sid = tx_add_input_serial_id m
+ pure $ mconcat [
+ BOLT1.un_channel_id (tx_add_input_channel_id m)
+ , BOLT1.encode_u64 sid
+ , prev
+ , BOLT1.encode_u32 (tx_add_input_prevtx_vout m)
+ , BOLT1.encode_u32 (tx_add_input_sequence m)
+ , BOLT1.encode_tlv_stream (tx_add_input_tlvs m)
+ ]
+
+-- | Decode a 'TxAddInput' payload.
+decode_tx_add_input :: BS.ByteString -> Either DecodeError TxAddInput
+decode_tx_add_input = parse $
+ TxAddInput <$> channel_id <*> serial_id <*> prefixed <*> u32 <*> u32
+ <*> tlvs []
+
+-- | Encode a 'TxAddOutput' payload.
+encode_tx_add_output :: TxAddOutput -> BS.ByteString
+encode_tx_add_output m =
+ let SerialId sid = tx_add_output_serial_id m
+ in mconcat [
+ BOLT1.un_channel_id (tx_add_output_channel_id m)
+ , BOLT1.encode_u64 sid
+ , BOLT1.encode_satoshi (tx_add_output_sats m)
+ , script_bytes (tx_add_output_script m)
+ , BOLT1.encode_tlv_stream (tx_add_output_tlvs m)
+ ]
+
+-- | Decode a 'TxAddOutput' payload.
+decode_tx_add_output :: BS.ByteString -> Either DecodeError TxAddOutput
+decode_tx_add_output = parse $
+ TxAddOutput <$> channel_id <*> serial_id <*> satoshi <*> script
+ <*> tlvs []
+
+-- | Encode a 'TxRemoveInput' payload.
+encode_tx_remove_input :: TxRemoveInput -> BS.ByteString
+encode_tx_remove_input (TxRemoveInput cid (SerialId sid) ts) = mconcat [
+ BOLT1.un_channel_id cid
+ , BOLT1.encode_u64 sid
+ , BOLT1.encode_tlv_stream ts
]
--- | Decode a TxRemoveInput message (type 68).
-decodeTxRemoveInput
- :: BS.ByteString -> Either DecodeError (TxRemoveInput, BS.ByteString)
-decodeTxRemoveInput !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (sid, rest2) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU64 rest1)
- let !msg = TxRemoveInput
- { txRemoveInputChannelId = cid
- , txRemoveInputSerialId = serialId sid
- }
- Right (msg, rest2)
-
--- | Encode a TxRemoveOutput message (type 69).
-encodeTxRemoveOutput :: TxRemoveOutput -> BS.ByteString
-encodeTxRemoveOutput !msg = mconcat
- [ unChannelId (txRemoveOutputChannelId msg)
- , encodeU64 (unSerialId (txRemoveOutputSerialId msg))
+-- | Decode a 'TxRemoveInput' payload.
+decode_tx_remove_input :: BS.ByteString -> Either DecodeError TxRemoveInput
+decode_tx_remove_input = parse $
+ TxRemoveInput <$> channel_id <*> serial_id <*> tlvs []
+
+-- | Encode a 'TxRemoveOutput' payload.
+encode_tx_remove_output :: TxRemoveOutput -> BS.ByteString
+encode_tx_remove_output (TxRemoveOutput cid (SerialId sid) ts) = mconcat [
+ BOLT1.un_channel_id cid
+ , BOLT1.encode_u64 sid
+ , BOLT1.encode_tlv_stream ts
]
--- | Decode a TxRemoveOutput message (type 69).
-decodeTxRemoveOutput
- :: BS.ByteString -> Either DecodeError (TxRemoveOutput, BS.ByteString)
-decodeTxRemoveOutput !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (sid, rest2) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU64 rest1)
- let !msg = TxRemoveOutput
- { txRemoveOutputChannelId = cid
- , txRemoveOutputSerialId = serialId sid
- }
- Right (msg, rest2)
-
--- | Encode a TxComplete message (type 70).
-encodeTxComplete :: TxComplete -> BS.ByteString
-encodeTxComplete !msg = unChannelId (txCompleteChannelId msg)
-
--- | Decode a TxComplete message (type 70).
-decodeTxComplete
- :: BS.ByteString -> Either DecodeError (TxComplete, BS.ByteString)
-decodeTxComplete !bs = do
- (cid, rest) <- decodeChannelIdBytes bs
- let !msg = TxComplete { txCompleteChannelId = cid }
- Right (msg, rest)
-
--- | Encode a single witness with bounds checking.
-encodeWitnessE :: Witness -> Either EncodeError BS.ByteString
-encodeWitnessE (Witness !wdata) = encodeU16BytesE wdata
-
--- | Decode a single witness.
-decodeWitness :: BS.ByteString -> Either DecodeError (Witness, BS.ByteString)
-decodeWitness !bs = do
- (wdata, rest) <- decodeU16Bytes bs
- Right (Witness wdata, rest)
-
--- | Encode a TxSignatures message (type 71).
-encodeTxSignatures :: TxSignatures -> Either EncodeError BS.ByteString
-encodeTxSignatures !msg = do
- let !witnesses = txSignaturesWitnesses msg
- numWit <- checkListCountU16 (length witnesses)
- encodedWits <- traverse encodeWitnessE witnesses
- Right $! mconcat $
- [ unChannelId (txSignaturesChannelId msg)
- , let (TxId bs) = txSignaturesTxid msg in bs
- , encodeU16 numWit
- ] ++ encodedWits
-
--- | Decode a TxSignatures message (type 71).
-decodeTxSignatures
- :: BS.ByteString -> Either DecodeError (TxSignatures, BS.ByteString)
-decodeTxSignatures !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (tid, rest2) <- decodeTxIdBytes rest1
- (numWit, rest3) <- decodeU16E rest2
- (witnesses, rest4) <- decodeWitnesses (fromIntegral numWit) rest3
- let !msg = TxSignatures
- { txSignaturesChannelId = cid
- , txSignaturesTxid = tid
- , txSignaturesWitnesses = witnesses
- }
- Right (msg, rest4)
+-- | Decode a 'TxRemoveOutput' payload.
+decode_tx_remove_output
+ :: BS.ByteString -> Either DecodeError TxRemoveOutput
+decode_tx_remove_output = parse $
+ TxRemoveOutput <$> channel_id <*> serial_id <*> tlvs []
+
+-- | Encode a 'TxComplete' payload.
+encode_tx_complete :: TxComplete -> BS.ByteString
+encode_tx_complete (TxComplete cid ts) =
+ BOLT1.un_channel_id cid <> BOLT1.encode_tlv_stream ts
+
+-- | Decode a 'TxComplete' payload.
+decode_tx_complete :: BS.ByteString -> Either DecodeError TxComplete
+decode_tx_complete = parse $ TxComplete <$> channel_id <*> tlvs []
+
+-- | Encode a 'TxSignatures' payload. Fails if there are more than 65535
+-- witnesses.
+encode_tx_signatures :: TxSignatures -> Either EncodeError BS.ByteString
+encode_tx_signatures m = do
+ let ws = tx_signatures_witnesses m
+ n <- count_prefix ws
+ pure $ mconcat [
+ BOLT1.un_channel_id (tx_signatures_channel_id m)
+ , txid_bytes (tx_signatures_txid m)
+ , n
+ , mconcat [ BOLT1.encode_u16 (fromIntegral (BS.length w)) <> w
+ | w <- map un_witness ws ]
+ , BOLT1.encode_tlv_stream (tx_signatures_tlvs m)
+ ]
+
+-- | Decode a 'TxSignatures' payload.
+decode_tx_signatures :: BS.ByteString -> Either DecodeError TxSignatures
+decode_tx_signatures = parse $ do
+ cid <- channel_id
+ t <- txid
+ n <- u16
+ ws <- count (fromIntegral n) wit
+ TxSignatures cid t ws <$> tlvs []
where
- decodeWitnesses :: Int -> BS.ByteString
- -> Either DecodeError ([Witness], BS.ByteString)
- decodeWitnesses 0 !rest = Right ([], rest)
- decodeWitnesses !n !rest = do
- (w, rest') <- decodeWitness rest
- (ws, rest'') <- decodeWitnesses (n - 1) rest'
- Right (w : ws, rest'')
-
--- | Encode a TxInitRbf message (type 72).
-encodeTxInitRbf :: TxInitRbf -> BS.ByteString
-encodeTxInitRbf !msg = mconcat
- [ unChannelId (txInitRbfChannelId msg)
- , encodeU32 (txInitRbfLocktime msg)
- , encodeU32 (txInitRbfFeerate msg)
- , encodeTlvStream (txInitRbfTlvs msg)
+ wit = do
+ b <- prefixed
+ maybe (failure DecodeInsufficientBytes) pure (witness b)
+
+rbf_known :: [Word64]
+rbf_known = [0, 2]
+
+-- | Encode a 'TxInitRbf' payload.
+encode_tx_init_rbf :: TxInitRbf -> Either EncodeError BS.ByteString
+encode_tx_init_rbf m = do
+ ts <- encode_tlvs rbf_known
+ ( opt 0 BOLT1.encode_s64 (tx_init_rbf_funding_output_contribution m)
+ <> opt_flag 2 (tx_init_rbf_require_confirmed_inputs m) )
+ (tx_init_rbf_tlvs m)
+ pure $ mconcat [
+ BOLT1.un_channel_id (tx_init_rbf_channel_id m)
+ , BOLT1.encode_u32 (tx_init_rbf_locktime m)
+ , BOLT1.encode_u32 (tx_init_rbf_feerate m)
+ , ts
+ ]
+
+-- | Decode a 'TxInitRbf' payload.
+decode_tx_init_rbf :: BS.ByteString -> Either DecodeError TxInitRbf
+decode_tx_init_rbf = parse $ do
+ cid <- channel_id
+ lock <- u32
+ fee <- u32
+ s <- tlvs rbf_known
+ contrib <- record 0 tlv_s64 s
+ conf <- flag 2 s
+ pure (TxInitRbf cid lock fee contrib conf (unknown rbf_known s))
+
+-- | Encode a 'TxAckRbf' payload.
+encode_tx_ack_rbf :: TxAckRbf -> Either EncodeError BS.ByteString
+encode_tx_ack_rbf m = do
+ ts <- encode_tlvs rbf_known
+ ( opt 0 BOLT1.encode_s64 (tx_ack_rbf_funding_output_contribution m)
+ <> opt_flag 2 (tx_ack_rbf_require_confirmed_inputs m) )
+ (tx_ack_rbf_tlvs m)
+ pure (BOLT1.un_channel_id (tx_ack_rbf_channel_id m) <> ts)
+
+-- | Decode a 'TxAckRbf' payload.
+decode_tx_ack_rbf :: BS.ByteString -> Either DecodeError TxAckRbf
+decode_tx_ack_rbf = parse $ do
+ cid <- channel_id
+ s <- tlvs rbf_known
+ contrib <- record 0 tlv_s64 s
+ conf <- flag 2 s
+ pure (TxAckRbf cid contrib conf (unknown rbf_known s))
+
+-- | Encode a 'TxAbort' payload. Fails if @data@ exceeds 65535 bytes.
+encode_tx_abort :: TxAbort -> Either EncodeError BS.ByteString
+encode_tx_abort (TxAbort cid dat ts) = do
+ dat' <- u16_prefixed dat
+ pure (BOLT1.un_channel_id cid <> dat' <> BOLT1.encode_tlv_stream ts)
+
+-- | Decode a 'TxAbort' payload.
+decode_tx_abort :: BS.ByteString -> Either DecodeError TxAbort
+decode_tx_abort = parse $ TxAbort <$> channel_id <*> prefixed <*> tlvs []
+
+-- stfu -----------------------------------------------------------------------
+
+-- | Encode a 'Stfu' payload.
+encode_stfu :: Stfu -> BS.ByteString
+encode_stfu (Stfu cid ini ts) = mconcat [
+ BOLT1.un_channel_id cid
+ , word8 (if ini then 1 else 0)
+ , BOLT1.encode_tlv_stream ts
]
--- | Decode a TxInitRbf message (type 72).
-decodeTxInitRbf
- :: BS.ByteString -> Either DecodeError (TxInitRbf, BS.ByteString)
-decodeTxInitRbf !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (locktime, rest2) <- decodeU32E rest1
- (feerate, rest3) <- decodeU32E rest2
- tlvs <- decodeTlvs rest3
- let !msg = TxInitRbf
- { txInitRbfChannelId = cid
- , txInitRbfLocktime = locktime
- , txInitRbfFeerate = feerate
- , txInitRbfTlvs = tlvs
- }
- Right (msg, BS.empty)
-
--- | Encode a TxAckRbf message (type 73).
-encodeTxAckRbf :: TxAckRbf -> BS.ByteString
-encodeTxAckRbf !msg = mconcat
- [ unChannelId (txAckRbfChannelId msg)
- , encodeTlvStream (txAckRbfTlvs msg)
+-- | Decode a 'Stfu' payload. The @initiator@ byte must be 0 or 1.
+decode_stfu :: BS.ByteString -> Either DecodeError Stfu
+decode_stfu = parse $ do
+ cid <- channel_id
+ b <- u8
+ ini <- case b of
+ 0 -> pure False
+ 1 -> pure True
+ _ -> failure DecodeInvalidInitiator
+ Stfu cid ini <$> tlvs []
+
+-- shutdown -------------------------------------------------------------------
+
+-- | Encode a 'Shutdown' payload.
+encode_shutdown :: Shutdown -> BS.ByteString
+encode_shutdown (Shutdown cid spk ts) = mconcat [
+ BOLT1.un_channel_id cid
+ , script_bytes spk
+ , BOLT1.encode_tlv_stream ts
]
--- | Decode a TxAckRbf message (type 73).
-decodeTxAckRbf
- :: BS.ByteString -> Either DecodeError (TxAckRbf, BS.ByteString)
-decodeTxAckRbf !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- tlvs <- decodeTlvs rest1
- let !msg = TxAckRbf
- { txAckRbfChannelId = cid
- , txAckRbfTlvs = tlvs
- }
- Right (msg, BS.empty)
-
--- | Encode a TxAbort message (type 74).
-encodeTxAbort :: TxAbort -> Either EncodeError BS.ByteString
-encodeTxAbort !msg = do
- dataEnc <- encodeU16BytesE (txAbortData msg)
- Right $! mconcat
- [ unChannelId (txAbortChannelId msg)
- , dataEnc
+-- | Decode a 'Shutdown' payload.
+decode_shutdown :: BS.ByteString -> Either DecodeError Shutdown
+decode_shutdown = parse $ Shutdown <$> channel_id <*> script <*> tlvs []
+
+-- closing_complete, closing_sig ----------------------------------------------
+
+closing_known :: [Word64]
+closing_known = [1, 2, 3]
+
+closing_records
+ :: Maybe Signature -> Maybe Signature -> Maybe Signature -> [TlvRecord]
+closing_records a b c =
+ opt 1 BOLT1.un_signature a
+ <> opt 2 BOLT1.un_signature b
+ <> opt 3 BOLT1.un_signature c
+
+-- | Encode a 'ClosingComplete' payload.
+encode_closing_complete :: ClosingComplete -> Either EncodeError BS.ByteString
+encode_closing_complete m = do
+ ts <- encode_tlvs closing_known
+ (closing_records
+ (closing_complete_closer_output_only m)
+ (closing_complete_closee_output_only m)
+ (closing_complete_closer_and_closee_outputs m))
+ (closing_complete_tlvs m)
+ pure $ mconcat [
+ BOLT1.un_channel_id (closing_complete_channel_id m)
+ , script_bytes (closing_complete_closer_scriptpubkey m)
+ , script_bytes (closing_complete_closee_scriptpubkey m)
+ , BOLT1.encode_satoshi (closing_complete_fee_satoshis m)
+ , BOLT1.encode_u32 (closing_complete_locktime m)
+ , ts
]
--- | Decode a TxAbort message (type 74).
-decodeTxAbort
- :: BS.ByteString -> Either DecodeError (TxAbort, BS.ByteString)
-decodeTxAbort !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (dat, rest2) <- decodeU16Bytes rest1
- let !msg = TxAbort
- { txAbortChannelId = cid
- , txAbortData = dat
- }
- Right (msg, rest2)
-
--- Normal operation ------------------------------------------------------------
-
--- | Encode an UpdateAddHtlc message (type 128).
-encodeUpdateAddHtlc :: UpdateAddHtlc -> BS.ByteString
-encodeUpdateAddHtlc !m = mconcat
- [ unChannelId (updateAddHtlcChannelId m)
- , encodeU64 (unHtlcId (updateAddHtlcId m))
- , encodeU64 (unMilliSatoshi (updateAddHtlcAmountMsat m))
- , unPaymentHash (updateAddHtlcPaymentHash m)
- , encodeU32 (updateAddHtlcCltvExpiry m)
- , unOnionPacket (updateAddHtlcOnionPacket m)
- , encodeTlvStream (updateAddHtlcTlvs m)
- ]
-{-# INLINABLE encodeUpdateAddHtlc #-}
-
--- | Decode an UpdateAddHtlc message (type 128).
-decodeUpdateAddHtlc
- :: BS.ByteString -> Either DecodeError (UpdateAddHtlc, BS.ByteString)
-decodeUpdateAddHtlc !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (hid, rest2) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU64 rest1)
- (amtMsat, rest3) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU64 rest2)
- (pHash, rest4) <- decodePaymentHashBytes rest3
- (cltvExp, rest5) <- decodeU32E rest4
- (onion, rest6) <- decodeOnionPacketBytes rest5
- (tlvs, rest7) <- decodeOptionalTlvs rest6
- let !msg = UpdateAddHtlc
- { updateAddHtlcChannelId = cid
- , updateAddHtlcId = htlcId hid
- , updateAddHtlcAmountMsat = MilliSatoshi amtMsat
- , updateAddHtlcPaymentHash = pHash
- , updateAddHtlcCltvExpiry = cltvExp
- , updateAddHtlcOnionPacket = onion
- , updateAddHtlcTlvs = tlvs
- }
- Right (msg, rest7)
-{-# INLINABLE decodeUpdateAddHtlc #-}
-
--- | Encode an UpdateFulfillHtlc message (type 130).
-encodeUpdateFulfillHtlc :: UpdateFulfillHtlc -> BS.ByteString
-encodeUpdateFulfillHtlc !m = mconcat
- [ unChannelId (updateFulfillHtlcChannelId m)
- , encodeU64 (unHtlcId (updateFulfillHtlcId m))
- , unPaymentPreimage (updateFulfillHtlcPaymentPreimage m)
- , encodeTlvStream (updateFulfillHtlcTlvs m)
- ]
+-- | Decode a 'ClosingComplete' payload.
+decode_closing_complete
+ :: BS.ByteString -> Either DecodeError ClosingComplete
+decode_closing_complete = parse $ do
+ cid <- channel_id
+ closer <- script
+ closee <- script
+ fee <- satoshi
+ lock <- u32
+ s <- tlvs closing_known
+ a <- record 1 BOLT1.signature s
+ b <- record 2 BOLT1.signature s
+ c <- record 3 BOLT1.signature s
+ pure (ClosingComplete cid closer closee fee lock a b c
+ (unknown closing_known s))
+
+-- | Encode a 'ClosingSig' payload.
+encode_closing_sig :: ClosingSig -> Either EncodeError BS.ByteString
+encode_closing_sig m = do
+ ts <- encode_tlvs closing_known
+ (closing_records
+ (closing_sig_closer_output_only m)
+ (closing_sig_closee_output_only m)
+ (closing_sig_closer_and_closee_outputs m))
+ (closing_sig_tlvs m)
+ pure $ mconcat [
+ BOLT1.un_channel_id (closing_sig_channel_id m)
+ , script_bytes (closing_sig_closer_scriptpubkey m)
+ , script_bytes (closing_sig_closee_scriptpubkey m)
+ , BOLT1.encode_satoshi (closing_sig_fee_satoshis m)
+ , BOLT1.encode_u32 (closing_sig_locktime m)
+ , ts
+ ]
--- | Decode an UpdateFulfillHtlc message (type 130).
-decodeUpdateFulfillHtlc
- :: BS.ByteString -> Either DecodeError (UpdateFulfillHtlc, BS.ByteString)
-decodeUpdateFulfillHtlc !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (hid, rest2) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU64 rest1)
- (preimage, rest3) <- decodePaymentPreimageBytes rest2
- (tlvs, rest4) <- decodeOptionalTlvs rest3
- let !msg = UpdateFulfillHtlc
- { updateFulfillHtlcChannelId = cid
- , updateFulfillHtlcId = htlcId hid
- , updateFulfillHtlcPaymentPreimage = preimage
- , updateFulfillHtlcTlvs = tlvs
- }
- Right (msg, rest4)
-
--- | Encode an UpdateFailHtlc message (type 131).
-encodeUpdateFailHtlc :: UpdateFailHtlc -> Either EncodeError BS.ByteString
-encodeUpdateFailHtlc !m = do
- reasonEnc <- encodeU16BytesE (updateFailHtlcReason m)
- Right $! mconcat
- [ unChannelId (updateFailHtlcChannelId m)
- , encodeU64 (unHtlcId (updateFailHtlcId m))
- , reasonEnc
- , encodeTlvStream (updateFailHtlcTlvs m)
+-- | Decode a 'ClosingSig' payload.
+decode_closing_sig :: BS.ByteString -> Either DecodeError ClosingSig
+decode_closing_sig = parse $ do
+ cid <- channel_id
+ closer <- script
+ closee <- script
+ fee <- satoshi
+ lock <- u32
+ s <- tlvs closing_known
+ a <- record 1 BOLT1.signature s
+ b <- record 2 BOLT1.signature s
+ c <- record 3 BOLT1.signature s
+ pure (ClosingSig cid closer closee fee lock a b c
+ (unknown closing_known s))
+
+-- closing_signed -------------------------------------------------------------
+
+closing_signed_known :: [Word64]
+closing_signed_known = [1]
+
+-- | Encode a 'ClosingSigned' payload.
+encode_closing_signed :: ClosingSigned -> Either EncodeError BS.ByteString
+encode_closing_signed m = do
+ ts <- encode_tlvs closing_signed_known
+ (opt 1 fee_range_bytes (closing_signed_fee_range m))
+ (closing_signed_tlvs m)
+ pure $ mconcat [
+ BOLT1.un_channel_id (closing_signed_channel_id m)
+ , BOLT1.encode_satoshi (closing_signed_fee_satoshis m)
+ , BOLT1.un_signature (closing_signed_signature m)
+ , ts
]
--- | Decode an UpdateFailHtlc message (type 131).
-decodeUpdateFailHtlc
- :: BS.ByteString -> Either DecodeError (UpdateFailHtlc, BS.ByteString)
-decodeUpdateFailHtlc !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (hid, rest2) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU64 rest1)
- (reason, rest3) <- decodeU16Bytes rest2
- (tlvs, rest4) <- decodeOptionalTlvs rest3
- let !msg = UpdateFailHtlc
- { updateFailHtlcChannelId = cid
- , updateFailHtlcId = htlcId hid
- , updateFailHtlcReason = reason
- , updateFailHtlcTlvs = tlvs
- }
- Right (msg, rest4)
-
--- | Encode an UpdateFailMalformedHtlc message (type 135).
-encodeUpdateFailMalformedHtlc :: UpdateFailMalformedHtlc -> BS.ByteString
-encodeUpdateFailMalformedHtlc !m = mconcat
- [ unChannelId (updateFailMalformedHtlcChannelId m)
- , encodeU64 (unHtlcId (updateFailMalformedHtlcId m))
- , unPaymentHash (updateFailMalformedHtlcSha256Onion m)
- , encodeU16 (updateFailMalformedHtlcFailureCode m)
- ]
+-- | Decode a 'ClosingSigned' payload.
+decode_closing_signed :: BS.ByteString -> Either DecodeError ClosingSigned
+decode_closing_signed = parse $ do
+ cid <- channel_id
+ fee <- satoshi
+ sig <- signature
+ s <- tlvs closing_signed_known
+ range <- record 1 tlv_fee_range s
+ pure (ClosingSigned cid fee sig range (unknown closing_signed_known s))
+
+-- update_add_htlc ------------------------------------------------------------
+
+update_add_htlc_known :: [Word64]
+update_add_htlc_known = [0]
+
+-- | Encode an 'UpdateAddHtlc' payload.
+encode_update_add_htlc :: UpdateAddHtlc -> Either EncodeError BS.ByteString
+encode_update_add_htlc m = do
+ ts <- encode_tlvs update_add_htlc_known
+ (opt 0 BOLT1.un_point (update_add_htlc_path_key m))
+ (update_add_htlc_tlvs m)
+ let HtlcId hid = update_add_htlc_id m
+ pure $ mconcat [
+ BOLT1.un_channel_id (update_add_htlc_channel_id m)
+ , BOLT1.encode_u64 hid
+ , BOLT1.encode_milli_satoshi (update_add_htlc_amount_msat m)
+ , BOLT1.un_payment_hash (update_add_htlc_payment_hash m)
+ , BOLT1.encode_u32 (update_add_htlc_cltv_expiry m)
+ , un_onion_routing_packet (update_add_htlc_onion_routing_packet m)
+ , ts
+ ]
--- | Decode an UpdateFailMalformedHtlc message (type 135).
-decodeUpdateFailMalformedHtlc
- :: BS.ByteString -> Either DecodeError (UpdateFailMalformedHtlc, BS.ByteString)
-decodeUpdateFailMalformedHtlc !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (hid, rest2) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU64 rest1)
- (sha256Onion, rest3) <- decodePaymentHashBytes rest2
- (failCode, rest4) <- decodeU16E rest3
- let !msg = UpdateFailMalformedHtlc
- { updateFailMalformedHtlcChannelId = cid
- , updateFailMalformedHtlcId = htlcId hid
- , updateFailMalformedHtlcSha256Onion = sha256Onion
- , updateFailMalformedHtlcFailureCode = failCode
- }
- Right (msg, rest4)
-
--- | Encode a CommitmentSigned message (type 132).
-encodeCommitmentSigned :: CommitmentSigned -> Either EncodeError BS.ByteString
-encodeCommitmentSigned !m = do
- let !sigs = commitmentSignedHtlcSignatures m
- numHtlcs <- checkListCountU16 (length sigs)
- Right $! mconcat $
- [ unChannelId (commitmentSignedChannelId m)
- , unSignature (commitmentSignedSignature m)
- , encodeU16 numHtlcs
- ] ++ map unSignature sigs
-{-# INLINABLE encodeCommitmentSigned #-}
-
--- | Decode a CommitmentSigned message (type 132).
-decodeCommitmentSigned
- :: BS.ByteString -> Either DecodeError (CommitmentSigned, BS.ByteString)
-decodeCommitmentSigned !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (sig, rest2) <- decodeSignatureBytes rest1
- (numHtlcs, rest3) <- decodeU16E rest2
- (htlcSigs, rest4) <- decodeSignatures (fromIntegral numHtlcs) rest3
- let !msg = CommitmentSigned
- { commitmentSignedChannelId = cid
- , commitmentSignedSignature = sig
- , commitmentSignedHtlcSignatures = htlcSigs
- }
- Right (msg, rest4)
- where
- decodeSignatures :: Int -> BS.ByteString
- -> Either DecodeError ([Signature], BS.ByteString)
- decodeSignatures !n !input = go n input []
- where
- go :: Int -> BS.ByteString -> [Signature]
- -> Either DecodeError ([Signature], BS.ByteString)
- go 0 !remaining !acc = Right (reverse acc, remaining)
- go !count !remaining !acc = do
- (s, rest) <- decodeSignatureBytes remaining
- go (count - 1) rest (s : acc)
-{-# INLINABLE decodeCommitmentSigned #-}
-
--- | Encode a RevokeAndAck message (type 133).
-encodeRevokeAndAck :: RevokeAndAck -> BS.ByteString
-encodeRevokeAndAck !m = mconcat
- [ unChannelId (revokeAndAckChannelId m)
- , unPerCommitmentSecret (revokeAndAckPerCommitmentSecret m)
- , unPoint (revokeAndAckNextPerCommitPoint m)
- ]
+-- | Decode an 'UpdateAddHtlc' payload.
+decode_update_add_htlc :: BS.ByteString -> Either DecodeError UpdateAddHtlc
+decode_update_add_htlc = parse $ do
+ cid <- channel_id
+ hid <- htlc_id
+ amt <- milli_satoshi
+ ph <- payment_hash
+ cltv <- u32
+ onion <- sized 1366 onion_routing_packet
+ s <- tlvs update_add_htlc_known
+ pk <- record 0 tlv_point s
+ pure (UpdateAddHtlc cid hid amt ph cltv onion pk
+ (unknown update_add_htlc_known s))
+
+-- update_fulfill_htlc --------------------------------------------------------
+
+update_fulfill_htlc_known :: [Word64]
+update_fulfill_htlc_known = [1, 3]
+
+-- | Encode an 'UpdateFulfillHtlc' payload.
+encode_update_fulfill_htlc
+ :: UpdateFulfillHtlc -> Either EncodeError BS.ByteString
+encode_update_fulfill_htlc m = do
+ ts <- encode_tlvs update_fulfill_htlc_known
+ ( opt 1 un_attribution_data (update_fulfill_htlc_attribution_data m)
+ <> opt 3 id (update_fulfill_htlc_fulfillment_payload m) )
+ (update_fulfill_htlc_tlvs m)
+ let HtlcId hid = update_fulfill_htlc_id m
+ pure $ mconcat [
+ BOLT1.un_channel_id (update_fulfill_htlc_channel_id m)
+ , BOLT1.encode_u64 hid
+ , BOLT1.un_payment_preimage (update_fulfill_htlc_payment_preimage m)
+ , ts
+ ]
+
+-- | Decode an 'UpdateFulfillHtlc' payload.
+decode_update_fulfill_htlc
+ :: BS.ByteString -> Either DecodeError UpdateFulfillHtlc
+decode_update_fulfill_htlc = parse $ do
+ cid <- channel_id
+ hid <- htlc_id
+ pre <- payment_preimage
+ s <- tlvs update_fulfill_htlc_known
+ att <- record 1 attribution_data s
+ pay <- record 3 Just s
+ pure (UpdateFulfillHtlc cid hid pre att pay
+ (unknown update_fulfill_htlc_known s))
+
+-- update_fail_htlc -----------------------------------------------------------
+
+update_fail_htlc_known :: [Word64]
+update_fail_htlc_known = [1]
+
+-- | Encode an 'UpdateFailHtlc' payload. Fails if @reason@ exceeds 65535
+-- bytes.
+encode_update_fail_htlc :: UpdateFailHtlc -> Either EncodeError BS.ByteString
+encode_update_fail_htlc m = do
+ reason <- u16_prefixed (update_fail_htlc_reason m)
+ ts <- encode_tlvs update_fail_htlc_known
+ (opt 1 un_attribution_data (update_fail_htlc_attribution_data m))
+ (update_fail_htlc_tlvs m)
+ let HtlcId hid = update_fail_htlc_id m
+ pure $ mconcat [
+ BOLT1.un_channel_id (update_fail_htlc_channel_id m)
+ , BOLT1.encode_u64 hid
+ , reason
+ , ts
+ ]
--- | Decode a RevokeAndAck message (type 133).
-decodeRevokeAndAck
- :: BS.ByteString -> Either DecodeError (RevokeAndAck, BS.ByteString)
-decodeRevokeAndAck !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (sec, rest2) <- decodePerCommitmentSecretBytes rest1
- (nextPoint, rest3) <- decodePointBytes rest2
- let !msg = RevokeAndAck
- { revokeAndAckChannelId = cid
- , revokeAndAckPerCommitmentSecret = sec
- , revokeAndAckNextPerCommitPoint = nextPoint
- }
- Right (msg, rest3)
-
--- | Encode an UpdateFee message (type 134).
-encodeUpdateFee :: UpdateFee -> BS.ByteString
-encodeUpdateFee !m = mconcat
- [ unChannelId (updateFeeChannelId m)
- , encodeU32 (updateFeeFeeratePerKw m)
+-- | Decode an 'UpdateFailHtlc' payload.
+decode_update_fail_htlc :: BS.ByteString -> Either DecodeError UpdateFailHtlc
+decode_update_fail_htlc = parse $ do
+ cid <- channel_id
+ hid <- htlc_id
+ reason <- prefixed
+ s <- tlvs update_fail_htlc_known
+ att <- record 1 attribution_data s
+ pure (UpdateFailHtlc cid hid reason att (unknown update_fail_htlc_known s))
+
+-- update_fail_malformed_htlc -------------------------------------------------
+
+-- | Encode an 'UpdateFailMalformedHtlc' payload.
+encode_update_fail_malformed_htlc :: UpdateFailMalformedHtlc -> BS.ByteString
+encode_update_fail_malformed_htlc
+ (UpdateFailMalformedHtlc cid (HtlcId hid) oh code ts) = mconcat [
+ BOLT1.un_channel_id cid
+ , BOLT1.encode_u64 hid
+ , un_onion_hash oh
+ , BOLT1.encode_u16 code
+ , BOLT1.encode_tlv_stream ts
+ ]
+
+-- | Decode an 'UpdateFailMalformedHtlc' payload.
+decode_update_fail_malformed_htlc
+ :: BS.ByteString -> Either DecodeError UpdateFailMalformedHtlc
+decode_update_fail_malformed_htlc = parse $
+ UpdateFailMalformedHtlc <$> channel_id <*> htlc_id <*> sized 32 onion_hash
+ <*> u16 <*> tlvs []
+
+-- commitment_signed ----------------------------------------------------------
+
+commitment_signed_known :: [Word64]
+commitment_signed_known = [1]
+
+-- | Encode a 'CommitmentSigned' payload. Fails if there are more than
+-- 65535 HTLC signatures.
+encode_commitment_signed
+ :: CommitmentSigned -> Either EncodeError BS.ByteString
+encode_commitment_signed m = do
+ let sigs = commitment_signed_htlc_signatures m
+ n <- count_prefix sigs
+ ts <- encode_tlvs commitment_signed_known
+ (opt 1 txid_bytes (commitment_signed_funding_txid m))
+ (commitment_signed_tlvs m)
+ pure $ mconcat [
+ BOLT1.un_channel_id (commitment_signed_channel_id m)
+ , BOLT1.un_signature (commitment_signed_signature m)
+ , n
+ , mconcat (map BOLT1.un_signature sigs)
+ , ts
+ ]
+
+-- | Decode a 'CommitmentSigned' payload.
+decode_commitment_signed
+ :: BS.ByteString -> Either DecodeError CommitmentSigned
+decode_commitment_signed = parse $ do
+ cid <- channel_id
+ sig <- signature
+ n <- u16
+ sigs <- count (fromIntegral n) signature
+ s <- tlvs commitment_signed_known
+ fund <- record 1 mkTxId s
+ pure (CommitmentSigned cid sig sigs fund (unknown commitment_signed_known s))
+
+-- revoke_and_ack, update_fee -------------------------------------------------
+
+-- | Encode a 'RevokeAndAck' payload.
+encode_revoke_and_ack :: RevokeAndAck -> BS.ByteString
+encode_revoke_and_ack (RevokeAndAck cid sec pcp ts) = mconcat [
+ BOLT1.un_channel_id cid
+ , BOLT1.un_per_commitment_secret sec
+ , BOLT1.un_point pcp
+ , BOLT1.encode_tlv_stream ts
]
--- | Decode an UpdateFee message (type 134).
-decodeUpdateFee
- :: BS.ByteString -> Either DecodeError (UpdateFee, BS.ByteString)
-decodeUpdateFee !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (feerate, rest2) <- decodeU32E rest1
- let !msg = UpdateFee
- { updateFeeChannelId = cid
- , updateFeeFeeratePerKw = feerate
- }
- Right (msg, rest2)
-
--- Channel reestablishment -----------------------------------------------------
-
--- | Encode a ChannelReestablish message (type 136).
-encodeChannelReestablish :: ChannelReestablish -> BS.ByteString
-encodeChannelReestablish !m = mconcat
- [ unChannelId (channelReestablishChannelId m)
- , encodeU64 (channelReestablishNextCommitNum m)
- , encodeU64 (channelReestablishNextRevocationNum m)
- , unPerCommitmentSecret (channelReestablishYourLastCommitSecret m)
- , unPoint (channelReestablishMyCurrentCommitPoint m)
- , encodeTlvStream (channelReestablishTlvs m)
+-- | Decode a 'RevokeAndAck' payload.
+decode_revoke_and_ack :: BS.ByteString -> Either DecodeError RevokeAndAck
+decode_revoke_and_ack = parse $
+ RevokeAndAck <$> channel_id <*> per_commitment_secret <*> point <*> tlvs []
+
+-- | Encode an 'UpdateFee' payload.
+encode_update_fee :: UpdateFee -> BS.ByteString
+encode_update_fee (UpdateFee cid fee ts) = mconcat [
+ BOLT1.un_channel_id cid
+ , BOLT1.encode_u32 fee
+ , BOLT1.encode_tlv_stream ts
]
--- | Decode a ChannelReestablish message (type 136).
-decodeChannelReestablish
- :: BS.ByteString -> Either DecodeError (ChannelReestablish, BS.ByteString)
-decodeChannelReestablish !bs = do
- (cid, rest1) <- decodeChannelIdBytes bs
- (nextCommit, rest2) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU64 rest1)
- (nextRevoke, rest3) <- maybe (Left DecodeInsufficientBytes) Right
- (decodeU64 rest2)
- (sec, rest4) <- decodePerCommitmentSecretBytes rest3
- (myPoint, rest5) <- decodePointBytes rest4
- (tlvs, rest6) <- decodeOptionalTlvs rest5
- let !msg = ChannelReestablish
- { channelReestablishChannelId = cid
- , channelReestablishNextCommitNum = nextCommit
- , channelReestablishNextRevocationNum = nextRevoke
- , channelReestablishYourLastCommitSecret = sec
- , channelReestablishMyCurrentCommitPoint = myPoint
- , channelReestablishTlvs = tlvs
- }
- Right (msg, rest6)
+-- | Decode an 'UpdateFee' payload.
+decode_update_fee :: BS.ByteString -> Either DecodeError UpdateFee
+decode_update_fee = parse $ UpdateFee <$> channel_id <*> u32 <*> tlvs []
+
+-- channel_reestablish --------------------------------------------------------
+
+channel_reestablish_known :: [Word64]
+channel_reestablish_known = [1]
+
+-- | Encode a 'ChannelReestablish' payload.
+encode_channel_reestablish
+ :: ChannelReestablish -> Either EncodeError BS.ByteString
+encode_channel_reestablish m = do
+ ts <- encode_tlvs channel_reestablish_known
+ (opt 1 next_funding_bytes (channel_reestablish_next_funding m))
+ (channel_reestablish_tlvs m)
+ pure $ mconcat [
+ BOLT1.un_channel_id (channel_reestablish_channel_id m)
+ , BOLT1.encode_u64 (channel_reestablish_next_commitment_number m)
+ , BOLT1.encode_u64 (channel_reestablish_next_revocation_number m)
+ , BOLT1.un_per_commitment_secret
+ (channel_reestablish_your_last_per_commitment_secret m)
+ , BOLT1.un_point (channel_reestablish_my_current_per_commitment_point m)
+ , ts
+ ]
+
+-- | Decode a 'ChannelReestablish' payload.
+decode_channel_reestablish
+ :: BS.ByteString -> Either DecodeError ChannelReestablish
+decode_channel_reestablish = parse $ do
+ cid <- channel_id
+ nc <- u64
+ nr <- u64
+ sec <- per_commitment_secret
+ pcp <- point
+ s <- tlvs channel_reestablish_known
+ next <- record 1 tlv_next_funding s
+ pure (ChannelReestablish cid nc nr sec pcp next
+ (unknown channel_reestablish_known s))
diff --git a/lib/Lightning/Protocol/BOLT2/Messages.hs b/lib/Lightning/Protocol/BOLT2/Messages.hs
@@ -1,7 +1,5 @@
-{-# OPTIONS_HADDOCK prune #-}
-{-# LANGUAGE BangPatterns #-}
+{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE DerivingStrategies #-}
-- |
-- Module: Lightning.Protocol.BOLT2.Messages
@@ -9,27 +7,18 @@
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
--- Message types for BOLT #2 peer protocol.
---
--- This module defines per-message record types and a top-level Message
--- sum type for all BOLT #2 messages.
+-- The messages defined by BOLT #2.
module Lightning.Protocol.BOLT2.Messages (
- -- * Message type codes
- MsgType(..)
- , msgTypeWord
-
- -- * Top-level message type
- , Message(..)
+ Message(..)
+ , message_type
- -- * Channel establishment v1
, OpenChannel(..)
, AcceptChannel(..)
, FundingCreated(..)
, FundingSigned(..)
, ChannelReady(..)
- -- * Channel establishment v2
, OpenChannel2(..)
, AcceptChannel2(..)
, TxAddInput(..)
@@ -42,14 +31,13 @@ module Lightning.Protocol.BOLT2.Messages (
, TxAckRbf(..)
, TxAbort(..)
- -- * Channel close
, Stfu(..)
+
, Shutdown(..)
- , ClosingSigned(..)
, ClosingComplete(..)
, ClosingSig(..)
+ , ClosingSigned(..)
- -- * Normal operation
, UpdateAddHtlc(..)
, UpdateFulfillHtlc(..)
, UpdateFailHtlc(..)
@@ -58,544 +46,556 @@ module Lightning.Protocol.BOLT2.Messages (
, RevokeAndAck(..)
, UpdateFee(..)
- -- * Reestablishment
, ChannelReestablish(..)
-
- -- * Witness data
- , Witness(..)
) where
+import Bitcoin.Prim.Tx (TxId)
import Control.DeepSeq (NFData)
import qualified Data.ByteString as BS
+import Data.Int (Int64)
import Data.Word (Word8, Word16, Word32, Word64)
import GHC.Generics (Generic)
-import Lightning.Protocol.BOLT1 (TlvStream)
+import Lightning.Protocol.BOLT1
+ ( ChainHash, ChannelId, Signature, Point, PaymentHash, PaymentPreimage
+ , PerCommitmentSecret, ShortChannelId, Satoshi, MilliSatoshi, TlvStream )
+import qualified Lightning.Protocol.BOLT9 as BOLT9
import Lightning.Protocol.BOLT2.Types
--- Message type codes ----------------------------------------------------------
-
--- | BOLT #2 message type codes.
-data MsgType
- = MsgStfu -- ^ 2
- | MsgOpenChannel -- ^ 32
- | MsgAcceptChannel -- ^ 33
- | MsgFundingCreated -- ^ 34
- | MsgFundingSigned -- ^ 35
- | MsgChannelReady -- ^ 36
- | MsgShutdown -- ^ 38
- | MsgClosingSigned -- ^ 39
- | MsgClosingComplete -- ^ 40
- | MsgClosingSig -- ^ 41
- | MsgOpenChannel2 -- ^ 64
- | MsgAcceptChannel2 -- ^ 65
- | MsgTxAddInput -- ^ 66
- | MsgTxAddOutput -- ^ 67
- | MsgTxRemoveInput -- ^ 68
- | MsgTxRemoveOutput -- ^ 69
- | MsgTxComplete -- ^ 70
- | MsgTxSignatures -- ^ 71
- | MsgTxInitRbf -- ^ 72
- | MsgTxAckRbf -- ^ 73
- | MsgTxAbort -- ^ 74
- | MsgUpdateAddHtlc -- ^ 128
- | MsgUpdateFulfillHtlc -- ^ 130
- | MsgUpdateFailHtlc -- ^ 131
- | MsgCommitmentSigned -- ^ 132
- | MsgRevokeAndAck -- ^ 133
- | MsgUpdateFee -- ^ 134
- | MsgUpdateFailMalformedHtlc -- ^ 135
- | MsgChannelReestablish -- ^ 136
- deriving stock (Eq, Ord, Show, Generic)
-
-instance NFData MsgType
-
--- | Get the numeric type code for a message type.
-msgTypeWord :: MsgType -> Word16
-msgTypeWord MsgStfu = 2
-msgTypeWord MsgOpenChannel = 32
-msgTypeWord MsgAcceptChannel = 33
-msgTypeWord MsgFundingCreated = 34
-msgTypeWord MsgFundingSigned = 35
-msgTypeWord MsgChannelReady = 36
-msgTypeWord MsgShutdown = 38
-msgTypeWord MsgClosingSigned = 39
-msgTypeWord MsgClosingComplete = 40
-msgTypeWord MsgClosingSig = 41
-msgTypeWord MsgOpenChannel2 = 64
-msgTypeWord MsgAcceptChannel2 = 65
-msgTypeWord MsgTxAddInput = 66
-msgTypeWord MsgTxAddOutput = 67
-msgTypeWord MsgTxRemoveInput = 68
-msgTypeWord MsgTxRemoveOutput = 69
-msgTypeWord MsgTxComplete = 70
-msgTypeWord MsgTxSignatures = 71
-msgTypeWord MsgTxInitRbf = 72
-msgTypeWord MsgTxAckRbf = 73
-msgTypeWord MsgTxAbort = 74
-msgTypeWord MsgUpdateAddHtlc = 128
-msgTypeWord MsgUpdateFulfillHtlc = 130
-msgTypeWord MsgUpdateFailHtlc = 131
-msgTypeWord MsgCommitmentSigned = 132
-msgTypeWord MsgRevokeAndAck = 133
-msgTypeWord MsgUpdateFee = 134
-msgTypeWord MsgUpdateFailMalformedHtlc = 135
-msgTypeWord MsgChannelReestablish = 136
-{-# INLINE msgTypeWord #-}
-
--- Channel establishment v1 ----------------------------------------------------
-
--- | The open_channel message (type 32).
---
--- Contains information about a node and indicates its desire to set up
--- a new channel.
+-- channel establishment v1 ---------------------------------------------------
+
+-- | The @open_channel@ message (type 32).
data OpenChannel = OpenChannel
- { openChannelChainHash :: !ChainHash
- , openChannelTempChannelId :: !ChannelId
- , openChannelFundingSatoshi :: {-# UNPACK #-} !Satoshi
- , openChannelPushMsat :: {-# UNPACK #-} !MilliSatoshi
- , openChannelDustLimitSatoshi :: {-# UNPACK #-} !Satoshi
- , openChannelMaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshi
- , openChannelChannelReserveSat :: {-# UNPACK #-} !Satoshi
- , openChannelHtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshi
- , openChannelFeeratePerKw :: {-# UNPACK #-} !Word32
- , openChannelToSelfDelay :: {-# UNPACK #-} !Word16
- , openChannelMaxAcceptedHtlcs :: {-# UNPACK #-} !Word16
- , openChannelFundingPubkey :: !Point
- , openChannelRevocationBasepoint :: !Point
- , openChannelPaymentBasepoint :: !Point
- , openChannelDelayedPaymentBase :: !Point
- , openChannelHtlcBasepoint :: !Point
- , openChannelFirstPerCommitPoint :: !Point
- , openChannelChannelFlags :: {-# UNPACK #-} !Word8
- , openChannelTlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { open_channel_chain_hash :: !ChainHash
+ , open_channel_temporary_channel_id :: !ChannelId
+ , open_channel_funding_satoshis :: {-# UNPACK #-} !Satoshi
+ , open_channel_push_msat :: {-# UNPACK #-} !MilliSatoshi
+ , open_channel_dust_limit_satoshis :: {-# UNPACK #-} !Satoshi
+ , open_channel_max_htlc_value_in_flight_msat :: {-# UNPACK #-} !Word64
+ -- ^ a cap, often @maxBound@, so not a bounded amount
+ , open_channel_channel_reserve_satoshis :: {-# UNPACK #-} !Satoshi
+ , open_channel_htlc_minimum_msat :: {-# UNPACK #-} !MilliSatoshi
+ , open_channel_feerate_per_kw :: {-# UNPACK #-} !Word32
+ , open_channel_to_self_delay :: {-# UNPACK #-} !Word16
+ , open_channel_max_accepted_htlcs :: {-# UNPACK #-} !Word16
+ , open_channel_funding_pubkey :: !Point
+ , open_channel_revocation_basepoint :: !Point
+ , open_channel_payment_basepoint :: !Point
+ , open_channel_delayed_payment_basepoint :: !Point
+ , open_channel_htlc_basepoint :: !Point
+ , open_channel_first_per_commitment_point :: !Point
+ , open_channel_channel_flags :: {-# UNPACK #-} !Word8
+ -- ^ bit 0: @announce_channel@
+ , open_channel_upfront_shutdown_script :: !(Maybe ScriptPubKey)
+ -- ^ TLV type 0; an empty script commits to no particular script
+ , open_channel_channel_type :: !(Maybe BOLT9.FeatureVector)
+ -- ^ TLV type 1
+ , open_channel_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData OpenChannel
--- | The accept_channel message (type 33).
---
--- Contains information about a node and indicates its acceptance of
--- the new channel.
+-- | The @accept_channel@ message (type 33).
data AcceptChannel = AcceptChannel
- { acceptChannelTempChannelId :: !ChannelId
- , acceptChannelDustLimitSatoshi :: {-# UNPACK #-} !Satoshi
- , acceptChannelMaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshi
- , acceptChannelChannelReserveSat :: {-# UNPACK #-} !Satoshi
- , acceptChannelHtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshi
- , acceptChannelMinimumDepth :: {-# UNPACK #-} !Word32
- , acceptChannelToSelfDelay :: {-# UNPACK #-} !Word16
- , acceptChannelMaxAcceptedHtlcs :: {-# UNPACK #-} !Word16
- , acceptChannelFundingPubkey :: !Point
- , acceptChannelRevocationBasepoint :: !Point
- , acceptChannelPaymentBasepoint :: !Point
- , acceptChannelDelayedPaymentBase :: !Point
- , acceptChannelHtlcBasepoint :: !Point
- , acceptChannelFirstPerCommitPoint :: !Point
- , acceptChannelTlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { accept_channel_temporary_channel_id :: !ChannelId
+ , accept_channel_dust_limit_satoshis :: {-# UNPACK #-} !Satoshi
+ , accept_channel_max_htlc_value_in_flight_msat :: {-# UNPACK #-} !Word64
+ -- ^ a cap, often @maxBound@, so not a bounded amount
+ , accept_channel_channel_reserve_satoshis :: {-# UNPACK #-} !Satoshi
+ , accept_channel_htlc_minimum_msat
+ :: {-# UNPACK #-} !MilliSatoshi
+ , accept_channel_minimum_depth :: {-# UNPACK #-} !Word32
+ , accept_channel_to_self_delay :: {-# UNPACK #-} !Word16
+ , accept_channel_max_accepted_htlcs :: {-# UNPACK #-} !Word16
+ , accept_channel_funding_pubkey :: !Point
+ , accept_channel_revocation_basepoint :: !Point
+ , accept_channel_payment_basepoint :: !Point
+ , accept_channel_delayed_payment_basepoint :: !Point
+ , accept_channel_htlc_basepoint :: !Point
+ , accept_channel_first_per_commitment_point :: !Point
+ , accept_channel_upfront_shutdown_script :: !(Maybe ScriptPubKey)
+ -- ^ TLV type 0; an empty script commits to no particular script
+ , accept_channel_channel_type
+ :: !(Maybe BOLT9.FeatureVector)
+ -- ^ TLV type 1
+ , accept_channel_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData AcceptChannel
--- | The funding_created message (type 34).
---
--- Describes the outpoint which the funder has created for the initial
--- commitment transactions.
+-- | The @funding_created@ message (type 34).
data FundingCreated = FundingCreated
- { fundingCreatedTempChannelId :: !ChannelId
- , fundingCreatedFundingTxid :: !TxId
- , fundingCreatedFundingOutIdx :: {-# UNPACK #-} !Word16
- , fundingCreatedSignature :: !Signature
- } deriving stock (Eq, Show, Generic)
+ { funding_created_temporary_channel_id :: !ChannelId
+ , funding_created_funding_txid :: !TxId
+ , funding_created_funding_output_index :: {-# UNPACK #-} !Word16
+ , funding_created_signature :: !Signature
+ , funding_created_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData FundingCreated
--- | The funding_signed message (type 35).
---
--- Gives the funder the signature for the first commitment transaction.
+-- | The @funding_signed@ message (type 35).
data FundingSigned = FundingSigned
- { fundingSignedChannelId :: !ChannelId
- , fundingSignedSignature :: !Signature
- } deriving stock (Eq, Show, Generic)
+ { funding_signed_channel_id :: !ChannelId
+ , funding_signed_signature :: !Signature
+ , funding_signed_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData FundingSigned
--- | The channel_ready message (type 36).
---
--- Indicates that the funding transaction has sufficient confirms for
--- channel use.
+-- | The @channel_ready@ message (type 36).
data ChannelReady = ChannelReady
- { channelReadyChannelId :: !ChannelId
- , channelReadySecondPerCommitPoint :: !Point
- , channelReadyTlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { channel_ready_channel_id :: !ChannelId
+ , channel_ready_second_per_commitment_point :: !Point
+ , channel_ready_alias :: !(Maybe ShortChannelId)
+ -- ^ the @short_channel_id@ record (TLV type 1)
+ , channel_ready_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData ChannelReady
--- Channel establishment v2 ----------------------------------------------------
+-- channel establishment v2 ---------------------------------------------------
--- | The open_channel2 message (type 64).
---
--- Initiates the v2 channel establishment workflow.
+-- | The @open_channel2@ message (type 64).
data OpenChannel2 = OpenChannel2
- { openChannel2ChainHash :: !ChainHash
- , openChannel2TempChannelId :: !ChannelId
- , openChannel2FundingFeeratePerkw :: {-# UNPACK #-} !Word32
- , openChannel2CommitFeeratePerkw :: {-# UNPACK #-} !Word32
- , openChannel2FundingSatoshi :: {-# UNPACK #-} !Satoshi
- , openChannel2DustLimitSatoshi :: {-# UNPACK #-} !Satoshi
- , openChannel2MaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshi
- , openChannel2HtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshi
- , openChannel2ToSelfDelay :: {-# UNPACK #-} !Word16
- , openChannel2MaxAcceptedHtlcs :: {-# UNPACK #-} !Word16
- , openChannel2Locktime :: {-# UNPACK #-} !Word32
- , openChannel2FundingPubkey :: !Point
- , openChannel2RevocationBasepoint :: !Point
- , openChannel2PaymentBasepoint :: !Point
- , openChannel2DelayedPaymentBase :: !Point
- , openChannel2HtlcBasepoint :: !Point
- , openChannel2FirstPerCommitPoint :: !Point
- , openChannel2SecondPerCommitPoint :: !Point
- , openChannel2ChannelFlags :: {-# UNPACK #-} !Word8
- , openChannel2Tlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { open_channel2_chain_hash :: !ChainHash
+ , open_channel2_temporary_channel_id :: !ChannelId
+ , open_channel2_funding_feerate_perkw :: {-# UNPACK #-} !Word32
+ , open_channel2_commitment_feerate_perkw :: {-# UNPACK #-} !Word32
+ , open_channel2_funding_satoshis :: {-# UNPACK #-} !Satoshi
+ , open_channel2_dust_limit_satoshis :: {-# UNPACK #-} !Satoshi
+ , open_channel2_max_htlc_value_in_flight_msat :: {-# UNPACK #-} !Word64
+ -- ^ a cap, often @maxBound@, so not a bounded amount
+ , open_channel2_htlc_minimum_msat
+ :: {-# UNPACK #-} !MilliSatoshi
+ , open_channel2_to_self_delay :: {-# UNPACK #-} !Word16
+ , open_channel2_max_accepted_htlcs :: {-# UNPACK #-} !Word16
+ , open_channel2_locktime :: {-# UNPACK #-} !Word32
+ , open_channel2_funding_pubkey :: !Point
+ , open_channel2_revocation_basepoint :: !Point
+ , open_channel2_payment_basepoint :: !Point
+ , open_channel2_delayed_payment_basepoint :: !Point
+ , open_channel2_htlc_basepoint :: !Point
+ , open_channel2_first_per_commitment_point :: !Point
+ , open_channel2_second_per_commitment_point :: !Point
+ , open_channel2_channel_flags :: {-# UNPACK #-} !Word8
+ -- ^ bit 0: @announce_channel@
+ , open_channel2_upfront_shutdown_script :: !(Maybe ScriptPubKey)
+ -- ^ TLV type 0; an empty script commits to no particular script
+ , open_channel2_channel_type
+ :: !(Maybe BOLT9.FeatureVector)
+ -- ^ TLV type 1
+ , open_channel2_require_confirmed_inputs :: !Bool
+ -- ^ TLV type 2
+ , open_channel2_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData OpenChannel2
--- | The accept_channel2 message (type 65).
---
--- Indicates acceptance of the v2 channel.
+-- | The @accept_channel2@ message (type 65).
data AcceptChannel2 = AcceptChannel2
- { acceptChannel2TempChannelId :: !ChannelId
- , acceptChannel2FundingSatoshi :: {-# UNPACK #-} !Satoshi
- , acceptChannel2DustLimitSatoshi :: {-# UNPACK #-} !Satoshi
- , acceptChannel2MaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshi
- , acceptChannel2HtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshi
- , acceptChannel2MinimumDepth :: {-# UNPACK #-} !Word32
- , acceptChannel2ToSelfDelay :: {-# UNPACK #-} !Word16
- , acceptChannel2MaxAcceptedHtlcs :: {-# UNPACK #-} !Word16
- , acceptChannel2FundingPubkey :: !Point
- , acceptChannel2RevocationBasepoint :: !Point
- , acceptChannel2PaymentBasepoint :: !Point
- , acceptChannel2DelayedPaymentBase :: !Point
- , acceptChannel2HtlcBasepoint :: !Point
- , acceptChannel2FirstPerCommitPoint :: !Point
- , acceptChannel2SecondPerCommitPoint :: !Point
- , acceptChannel2Tlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { accept_channel2_temporary_channel_id :: !ChannelId
+ , accept_channel2_funding_satoshis :: {-# UNPACK #-} !Satoshi
+ , accept_channel2_dust_limit_satoshis :: {-# UNPACK #-} !Satoshi
+ , accept_channel2_max_htlc_value_in_flight_msat :: {-# UNPACK #-} !Word64
+ -- ^ a cap, often @maxBound@, so not a bounded amount
+ , accept_channel2_htlc_minimum_msat
+ :: {-# UNPACK #-} !MilliSatoshi
+ , accept_channel2_minimum_depth :: {-# UNPACK #-} !Word32
+ , accept_channel2_to_self_delay :: {-# UNPACK #-} !Word16
+ , accept_channel2_max_accepted_htlcs :: {-# UNPACK #-} !Word16
+ , accept_channel2_funding_pubkey :: !Point
+ , accept_channel2_revocation_basepoint :: !Point
+ , accept_channel2_payment_basepoint :: !Point
+ , accept_channel2_delayed_payment_basepoint :: !Point
+ , accept_channel2_htlc_basepoint :: !Point
+ , accept_channel2_first_per_commitment_point :: !Point
+ , accept_channel2_second_per_commitment_point :: !Point
+ , accept_channel2_upfront_shutdown_script
+ :: !(Maybe ScriptPubKey)
+ -- ^ TLV type 0; an empty script commits to no particular script
+ , accept_channel2_channel_type
+ :: !(Maybe BOLT9.FeatureVector)
+ -- ^ TLV type 1
+ , accept_channel2_require_confirmed_inputs :: !Bool
+ -- ^ TLV type 2
+ , accept_channel2_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData AcceptChannel2
--- Interactive transaction construction ----------------------------------------
-
--- | The tx_add_input message (type 66).
---
--- Adds a transaction input to the collaborative transaction.
+-- | The @tx_add_input@ message (type 66).
data TxAddInput = TxAddInput
- { txAddInputChannelId :: !ChannelId
- , txAddInputSerialId :: !SerialId
- , txAddInputPrevTx :: !BS.ByteString
- , txAddInputPrevVout :: {-# UNPACK #-} !Word32
- , txAddInputSequence :: {-# UNPACK #-} !Word32
- } deriving stock (Eq, Show, Generic)
+ { tx_add_input_channel_id :: !ChannelId
+ , tx_add_input_serial_id :: !SerialId
+ , tx_add_input_prevtx :: !BS.ByteString
+ -- ^ the serialized previous transaction
+ , tx_add_input_prevtx_vout :: {-# UNPACK #-} !Word32
+ , tx_add_input_sequence :: {-# UNPACK #-} !Word32
+ , tx_add_input_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData TxAddInput
--- | The tx_add_output message (type 67).
---
--- Adds a transaction output to the collaborative transaction.
+-- | The @tx_add_output@ message (type 67).
data TxAddOutput = TxAddOutput
- { txAddOutputChannelId :: !ChannelId
- , txAddOutputSerialId :: !SerialId
- , txAddOutputSats :: {-# UNPACK #-} !Satoshi
- , txAddOutputScript :: !ScriptPubKey
- } deriving stock (Eq, Show, Generic)
+ { tx_add_output_channel_id :: !ChannelId
+ , tx_add_output_serial_id :: !SerialId
+ , tx_add_output_sats :: {-# UNPACK #-} !Satoshi
+ , tx_add_output_script :: !ScriptPubKey
+ , tx_add_output_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData TxAddOutput
--- | The tx_remove_input message (type 68).
---
--- Removes a previously added input from the collaborative transaction.
+-- | The @tx_remove_input@ message (type 68).
data TxRemoveInput = TxRemoveInput
- { txRemoveInputChannelId :: !ChannelId
- , txRemoveInputSerialId :: !SerialId
- } deriving stock (Eq, Show, Generic)
+ { tx_remove_input_channel_id :: !ChannelId
+ , tx_remove_input_serial_id :: !SerialId
+ , tx_remove_input_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData TxRemoveInput
--- | The tx_remove_output message (type 69).
---
--- Removes a previously added output from the collaborative transaction.
+-- | The @tx_remove_output@ message (type 69).
data TxRemoveOutput = TxRemoveOutput
- { txRemoveOutputChannelId :: !ChannelId
- , txRemoveOutputSerialId :: !SerialId
- } deriving stock (Eq, Show, Generic)
+ { tx_remove_output_channel_id :: !ChannelId
+ , tx_remove_output_serial_id :: !SerialId
+ , tx_remove_output_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData TxRemoveOutput
--- | The tx_complete message (type 70).
---
--- Signals the conclusion of a peer's transaction contributions.
+-- | The @tx_complete@ message (type 70).
data TxComplete = TxComplete
- { txCompleteChannelId :: !ChannelId
- } deriving stock (Eq, Show, Generic)
+ { tx_complete_channel_id :: !ChannelId
+ , tx_complete_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData TxComplete
--- | Witness data for tx_signatures.
-data Witness = Witness
- { witnessData :: !BS.ByteString
- } deriving stock (Eq, Show, Generic)
-
-instance NFData Witness
-
--- | The tx_signatures message (type 71).
---
--- Contains signatures for the collaborative transaction.
+-- | The @tx_signatures@ message (type 71).
data TxSignatures = TxSignatures
- { txSignaturesChannelId :: !ChannelId
- , txSignaturesTxid :: !TxId
- , txSignaturesWitnesses :: ![Witness]
- } deriving stock (Eq, Show, Generic)
+ { tx_signatures_channel_id :: !ChannelId
+ , tx_signatures_txid :: !TxId
+ , tx_signatures_witnesses :: ![Witness]
+ -- ^ ordered by the @serial_id@ of the inputs they spend
+ , tx_signatures_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData TxSignatures
--- | The tx_init_rbf message (type 72).
---
--- Initiates a replacement of the transaction after it's been completed.
+-- | The @tx_init_rbf@ message (type 72).
data TxInitRbf = TxInitRbf
- { txInitRbfChannelId :: !ChannelId
- , txInitRbfLocktime :: {-# UNPACK #-} !Word32
- , txInitRbfFeerate :: {-# UNPACK #-} !Word32
- , txInitRbfTlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { tx_init_rbf_channel_id :: !ChannelId
+ , tx_init_rbf_locktime :: {-# UNPACK #-} !Word32
+ , tx_init_rbf_feerate :: {-# UNPACK #-} !Word32
+ , tx_init_rbf_funding_output_contribution :: !(Maybe Int64)
+ -- ^ TLV type 0, in satoshis
+ , tx_init_rbf_require_confirmed_inputs :: !Bool
+ -- ^ TLV type 2
+ , tx_init_rbf_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData TxInitRbf
--- | The tx_ack_rbf message (type 73).
---
--- Acknowledges an RBF attempt.
+-- | The @tx_ack_rbf@ message (type 73).
data TxAckRbf = TxAckRbf
- { txAckRbfChannelId :: !ChannelId
- , txAckRbfTlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { tx_ack_rbf_channel_id :: !ChannelId
+ , tx_ack_rbf_funding_output_contribution :: !(Maybe Int64)
+ -- ^ TLV type 0, in satoshis
+ , tx_ack_rbf_require_confirmed_inputs :: !Bool
+ -- ^ TLV type 2
+ , tx_ack_rbf_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData TxAckRbf
--- | The tx_abort message (type 74).
---
--- Aborts the collaborative transaction negotiation.
+-- | The @tx_abort@ message (type 74).
data TxAbort = TxAbort
- { txAbortChannelId :: !ChannelId
- , txAbortData :: !BS.ByteString
- } deriving stock (Eq, Show, Generic)
+ { tx_abort_channel_id :: !ChannelId
+ , tx_abort_data :: !BS.ByteString
+ , tx_abort_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData TxAbort
--- Channel close ---------------------------------------------------------------
+-- channel quiescence ---------------------------------------------------------
--- | The stfu message (type 2).
---
--- Indicates "SomeThing Fundamental is Underway" - used for channel
--- quiescence.
+-- | The @stfu@ message (type 2).
data Stfu = Stfu
- { stfuChannelId :: !ChannelId
- , stfuInitiator :: !Initiator
- } deriving stock (Eq, Show, Generic)
+ { stfu_channel_id :: !ChannelId
+ , stfu_initiator :: !Bool
+ -- ^ whether the sender initiated quiescence (sent as 1 or 0)
+ , stfu_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData Stfu
--- | The shutdown message (type 38).
---
--- Initiates closing of the channel.
+-- channel close --------------------------------------------------------------
+
+-- | The @shutdown@ message (type 38).
data Shutdown = Shutdown
- { shutdownChannelId :: !ChannelId
- , shutdownScriptPubkey :: !ScriptPubKey
- } deriving stock (Eq, Show, Generic)
+ { shutdown_channel_id :: !ChannelId
+ , shutdown_scriptpubkey :: !ScriptPubKey
+ , shutdown_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData Shutdown
--- | The closing_signed message (type 39).
---
--- Used in legacy closing negotiation.
-data ClosingSigned = ClosingSigned
- { closingSignedChannelId :: !ChannelId
- , closingSignedFeeSatoshi :: {-# UNPACK #-} !Satoshi
- , closingSignedSignature :: !Signature
- , closingSignedTlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
-
-instance NFData ClosingSigned
-
--- | The closing_complete message (type 40).
---
--- Proposes a closing transaction in the new closing protocol.
+-- | The @closing_complete@ message (type 40).
data ClosingComplete = ClosingComplete
- { closingCompleteChannelId :: !ChannelId
- , closingCompleteCloserScript :: !ScriptPubKey
- , closingCompleteCloseeScript :: !ScriptPubKey
- , closingCompleteFeeSatoshi :: {-# UNPACK #-} !Satoshi
- , closingCompleteLocktime :: {-# UNPACK #-} !Word32
- , closingCompleteTlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { closing_complete_channel_id :: !ChannelId
+ , closing_complete_closer_scriptpubkey :: !ScriptPubKey
+ , closing_complete_closee_scriptpubkey :: !ScriptPubKey
+ , closing_complete_fee_satoshis :: {-# UNPACK #-} !Satoshi
+ , closing_complete_locktime :: {-# UNPACK #-} !Word32
+ , closing_complete_closer_output_only :: !(Maybe Signature)
+ -- ^ TLV type 1
+ , closing_complete_closee_output_only :: !(Maybe Signature)
+ -- ^ TLV type 2
+ , closing_complete_closer_and_closee_outputs :: !(Maybe Signature)
+ -- ^ TLV type 3
+ , closing_complete_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData ClosingComplete
--- | The closing_sig message (type 41).
---
--- Signs a closing transaction in the new closing protocol.
+-- | The @closing_sig@ message (type 41). A valid @closing_sig@ carries
+-- exactly one signature, in a field set in the @closing_complete@ it
+-- answers; checking that is left to the caller.
data ClosingSig = ClosingSig
- { closingSigChannelId :: !ChannelId
- , closingSigCloserScript :: !ScriptPubKey
- , closingSigCloseeScript :: !ScriptPubKey
- , closingSigFeeSatoshi :: {-# UNPACK #-} !Satoshi
- , closingSigLocktime :: {-# UNPACK #-} !Word32
- , closingSigTlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { closing_sig_channel_id :: !ChannelId
+ , closing_sig_closer_scriptpubkey :: !ScriptPubKey
+ , closing_sig_closee_scriptpubkey :: !ScriptPubKey
+ , closing_sig_fee_satoshis :: {-# UNPACK #-} !Satoshi
+ , closing_sig_locktime :: {-# UNPACK #-} !Word32
+ , closing_sig_closer_output_only :: !(Maybe Signature)
+ -- ^ TLV type 1
+ , closing_sig_closee_output_only :: !(Maybe Signature)
+ -- ^ TLV type 2
+ , closing_sig_closer_and_closee_outputs :: !(Maybe Signature)
+ -- ^ TLV type 3
+ , closing_sig_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData ClosingSig
--- Normal operation ------------------------------------------------------------
+-- | The legacy @closing_signed@ message (type 39), used when
+-- @option_simple_close@ is not negotiated.
+data ClosingSigned = ClosingSigned
+ { closing_signed_channel_id :: !ChannelId
+ , closing_signed_fee_satoshis :: {-# UNPACK #-} !Satoshi
+ , closing_signed_signature :: !Signature
+ , closing_signed_fee_range :: !(Maybe FeeRange)
+ -- ^ TLV type 1
+ , closing_signed_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
--- | The update_add_htlc message (type 128).
---
--- Offers an HTLC to the other node, redeemable in return for a payment
--- preimage.
+instance NFData ClosingSigned
+
+-- normal operation -----------------------------------------------------------
+
+-- | The @update_add_htlc@ message (type 128).
data UpdateAddHtlc = UpdateAddHtlc
- { updateAddHtlcChannelId :: !ChannelId
- , updateAddHtlcId :: !HtlcId
- , updateAddHtlcAmountMsat :: {-# UNPACK #-} !MilliSatoshi
- , updateAddHtlcPaymentHash :: !PaymentHash
- , updateAddHtlcCltvExpiry :: {-# UNPACK #-} !Word32
- , updateAddHtlcOnionPacket :: !OnionPacket
- , updateAddHtlcTlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { update_add_htlc_channel_id :: !ChannelId
+ , update_add_htlc_id :: !HtlcId
+ , update_add_htlc_amount_msat :: {-# UNPACK #-} !MilliSatoshi
+ , update_add_htlc_payment_hash :: !PaymentHash
+ , update_add_htlc_cltv_expiry :: {-# UNPACK #-} !Word32
+ , update_add_htlc_onion_routing_packet :: !OnionRoutingPacket
+ , update_add_htlc_path_key :: !(Maybe Point)
+ -- ^ the @blinded_path@ record (TLV type 0)
+ , update_add_htlc_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData UpdateAddHtlc
--- | The update_fulfill_htlc message (type 130).
---
--- Supplies the preimage to fulfill an HTLC.
+-- | The @update_fulfill_htlc@ message (type 130).
data UpdateFulfillHtlc = UpdateFulfillHtlc
- { updateFulfillHtlcChannelId :: !ChannelId
- , updateFulfillHtlcId :: !HtlcId
- , updateFulfillHtlcPaymentPreimage :: !PaymentPreimage
- , updateFulfillHtlcTlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { update_fulfill_htlc_channel_id :: !ChannelId
+ , update_fulfill_htlc_id :: !HtlcId
+ , update_fulfill_htlc_payment_preimage :: !PaymentPreimage
+ , update_fulfill_htlc_attribution_data :: !(Maybe AttributionData)
+ -- ^ TLV type 1
+ , update_fulfill_htlc_fulfillment_payload :: !(Maybe BS.ByteString)
+ -- ^ TLV type 3
+ , update_fulfill_htlc_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData UpdateFulfillHtlc
--- | The update_fail_htlc message (type 131).
---
--- Indicates an HTLC has failed.
+-- | The @update_fail_htlc@ message (type 131).
data UpdateFailHtlc = UpdateFailHtlc
- { updateFailHtlcChannelId :: !ChannelId
- , updateFailHtlcId :: !HtlcId
- , updateFailHtlcReason :: !BS.ByteString
- , updateFailHtlcTlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { update_fail_htlc_channel_id :: !ChannelId
+ , update_fail_htlc_id :: !HtlcId
+ , update_fail_htlc_reason :: !BS.ByteString
+ , update_fail_htlc_attribution_data :: !(Maybe AttributionData)
+ -- ^ TLV type 1
+ , update_fail_htlc_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData UpdateFailHtlc
--- | The update_fail_malformed_htlc message (type 135).
---
--- Indicates an HTLC could not be parsed.
+-- | The @update_fail_malformed_htlc@ message (type 135).
data UpdateFailMalformedHtlc = UpdateFailMalformedHtlc
- { updateFailMalformedHtlcChannelId :: !ChannelId
- , updateFailMalformedHtlcId :: !HtlcId
- , updateFailMalformedHtlcSha256Onion :: !PaymentHash
- , updateFailMalformedHtlcFailureCode :: {-# UNPACK #-} !Word16
- } deriving stock (Eq, Show, Generic)
+ { update_fail_malformed_htlc_channel_id :: !ChannelId
+ , update_fail_malformed_htlc_id :: !HtlcId
+ , update_fail_malformed_htlc_sha256_of_onion :: !OnionHash
+ , update_fail_malformed_htlc_failure_code :: {-# UNPACK #-} !Word16
+ , update_fail_malformed_htlc_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData UpdateFailMalformedHtlc
--- | The commitment_signed message (type 132).
---
--- Applies pending changes and provides signatures for the commitment
--- transaction.
+-- | The @commitment_signed@ message (type 132).
data CommitmentSigned = CommitmentSigned
- { commitmentSignedChannelId :: !ChannelId
- , commitmentSignedSignature :: !Signature
- , commitmentSignedHtlcSignatures :: ![Signature]
- } deriving stock (Eq, Show, Generic)
+ { commitment_signed_channel_id :: !ChannelId
+ , commitment_signed_signature :: !Signature
+ , commitment_signed_htlc_signatures :: ![Signature]
+ , commitment_signed_funding_txid :: !(Maybe TxId)
+ -- ^ TLV type 1
+ , commitment_signed_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData CommitmentSigned
--- | The revoke_and_ack message (type 133).
---
--- Revokes the previous commitment transaction and acknowledges receipt
--- of the commitment_signed.
+-- | The @revoke_and_ack@ message (type 133).
data RevokeAndAck = RevokeAndAck
- { revokeAndAckChannelId :: !ChannelId
- , revokeAndAckPerCommitmentSecret :: !PerCommitmentSecret
- , revokeAndAckNextPerCommitPoint :: !Point
- } deriving stock (Eq, Show, Generic)
+ { revoke_and_ack_channel_id :: !ChannelId
+ , revoke_and_ack_per_commitment_secret :: !PerCommitmentSecret
+ , revoke_and_ack_next_per_commitment_point :: !Point
+ , revoke_and_ack_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData RevokeAndAck
--- | The update_fee message (type 134).
---
--- Updates the fee rate for commitment transactions.
+-- | The @update_fee@ message (type 134).
data UpdateFee = UpdateFee
- { updateFeeChannelId :: !ChannelId
- , updateFeeFeeratePerKw :: {-# UNPACK #-} !Word32
- } deriving stock (Eq, Show, Generic)
+ { update_fee_channel_id :: !ChannelId
+ , update_fee_feerate_per_kw :: {-# UNPACK #-} !Word32
+ , update_fee_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData UpdateFee
--- Reestablishment -------------------------------------------------------------
+-- message retransmission -----------------------------------------------------
--- | The channel_reestablish message (type 136).
---
--- Used to re-establish a channel after reconnection.
+-- | The @channel_reestablish@ message (type 136).
data ChannelReestablish = ChannelReestablish
- { channelReestablishChannelId :: !ChannelId
- , channelReestablishNextCommitNum :: {-# UNPACK #-} !Word64
- , channelReestablishNextRevocationNum :: {-# UNPACK #-} !Word64
- , channelReestablishYourLastCommitSecret :: !PerCommitmentSecret
- , channelReestablishMyCurrentCommitPoint :: !Point
- , channelReestablishTlvs :: !TlvStream
- } deriving stock (Eq, Show, Generic)
+ { channel_reestablish_channel_id :: !ChannelId
+ , channel_reestablish_next_commitment_number
+ :: {-# UNPACK #-} !Word64
+ , channel_reestablish_next_revocation_number
+ :: {-# UNPACK #-} !Word64
+ , channel_reestablish_your_last_per_commitment_secret
+ :: !PerCommitmentSecret
+ , channel_reestablish_my_current_per_commitment_point :: !Point
+ , channel_reestablish_next_funding
+ :: !(Maybe NextFunding)
+ -- ^ TLV type 1
+ , channel_reestablish_tlvs :: !TlvStream
+ -- ^ unknown TLV records
+ } deriving (Eq, Show, Generic)
instance NFData ChannelReestablish
--- Top-level message type ------------------------------------------------------
+-- messages -------------------------------------------------------------------
--- | All BOLT #2 messages.
+-- | A BOLT #2 message.
data Message
- -- Channel establishment v1
- = MsgOpenChannelVal !OpenChannel
- | MsgAcceptChannelVal !AcceptChannel
- | MsgFundingCreatedVal !FundingCreated
- | MsgFundingSignedVal !FundingSigned
- | MsgChannelReadyVal !ChannelReady
- -- Channel establishment v2
- | MsgOpenChannel2Val !OpenChannel2
- | MsgAcceptChannel2Val !AcceptChannel2
- | MsgTxAddInputVal !TxAddInput
- | MsgTxAddOutputVal !TxAddOutput
- | MsgTxRemoveInputVal !TxRemoveInput
- | MsgTxRemoveOutputVal !TxRemoveOutput
- | MsgTxCompleteVal !TxComplete
- | MsgTxSignaturesVal !TxSignatures
- | MsgTxInitRbfVal !TxInitRbf
- | MsgTxAckRbfVal !TxAckRbf
- | MsgTxAbortVal !TxAbort
- -- Channel close
- | MsgStfuVal !Stfu
- | MsgShutdownVal !Shutdown
- | MsgClosingSignedVal !ClosingSigned
- | MsgClosingCompleteVal !ClosingComplete
- | MsgClosingSigVal !ClosingSig
- -- Normal operation
- | MsgUpdateAddHtlcVal !UpdateAddHtlc
- | MsgUpdateFulfillHtlcVal !UpdateFulfillHtlc
- | MsgUpdateFailHtlcVal !UpdateFailHtlc
- | MsgUpdateFailMalformedHtlcVal !UpdateFailMalformedHtlc
- | MsgCommitmentSignedVal !CommitmentSigned
- | MsgRevokeAndAckVal !RevokeAndAck
- | MsgUpdateFeeVal !UpdateFee
- -- Reestablishment
- | MsgChannelReestablishVal !ChannelReestablish
- deriving stock (Eq, Show, Generic)
+ = MsgOpenChannel !OpenChannel
+ | MsgAcceptChannel !AcceptChannel
+ | MsgFundingCreated !FundingCreated
+ | MsgFundingSigned !FundingSigned
+ | MsgChannelReady !ChannelReady
+ | MsgOpenChannel2 !OpenChannel2
+ | MsgAcceptChannel2 !AcceptChannel2
+ | MsgTxAddInput !TxAddInput
+ | MsgTxAddOutput !TxAddOutput
+ | MsgTxRemoveInput !TxRemoveInput
+ | MsgTxRemoveOutput !TxRemoveOutput
+ | MsgTxComplete !TxComplete
+ | MsgTxSignatures !TxSignatures
+ | MsgTxInitRbf !TxInitRbf
+ | MsgTxAckRbf !TxAckRbf
+ | MsgTxAbort !TxAbort
+ | MsgStfu !Stfu
+ | MsgShutdown !Shutdown
+ | MsgClosingComplete !ClosingComplete
+ | MsgClosingSig !ClosingSig
+ | MsgClosingSigned !ClosingSigned
+ | MsgUpdateAddHtlc !UpdateAddHtlc
+ | MsgUpdateFulfillHtlc !UpdateFulfillHtlc
+ | MsgUpdateFailHtlc !UpdateFailHtlc
+ | MsgUpdateFailMalformedHtlc !UpdateFailMalformedHtlc
+ | MsgCommitmentSigned !CommitmentSigned
+ | MsgRevokeAndAck !RevokeAndAck
+ | MsgUpdateFee !UpdateFee
+ | MsgChannelReestablish !ChannelReestablish
+ deriving (Eq, Show, Generic)
instance NFData Message
+
+-- | The wire type of a 'Message'.
+--
+-- >>> message_type (MsgTxComplete (TxComplete cid BOLT1.empty_tlv_stream))
+-- 70
+message_type :: Message -> Word16
+message_type m = case m of
+ MsgOpenChannel {} -> 32
+ MsgAcceptChannel {} -> 33
+ MsgFundingCreated {} -> 34
+ MsgFundingSigned {} -> 35
+ MsgChannelReady {} -> 36
+ MsgOpenChannel2 {} -> 64
+ MsgAcceptChannel2 {} -> 65
+ MsgTxAddInput {} -> 66
+ MsgTxAddOutput {} -> 67
+ MsgTxRemoveInput {} -> 68
+ MsgTxRemoveOutput {} -> 69
+ MsgTxComplete {} -> 70
+ MsgTxSignatures {} -> 71
+ MsgTxInitRbf {} -> 72
+ MsgTxAckRbf {} -> 73
+ MsgTxAbort {} -> 74
+ MsgStfu {} -> 2
+ MsgShutdown {} -> 38
+ MsgClosingComplete {} -> 40
+ MsgClosingSig {} -> 41
+ MsgClosingSigned {} -> 39
+ MsgUpdateAddHtlc {} -> 128
+ MsgUpdateFulfillHtlc {} -> 130
+ MsgUpdateFailHtlc {} -> 131
+ MsgUpdateFailMalformedHtlc {} -> 135
+ MsgCommitmentSigned {} -> 132
+ MsgRevokeAndAck {} -> 133
+ MsgUpdateFee {} -> 134
+ MsgChannelReestablish {} -> 136
diff --git a/lib/Lightning/Protocol/BOLT2/Types.hs b/lib/Lightning/Protocol/BOLT2/Types.hs
@@ -1,8 +1,5 @@
-{-# OPTIONS_HADDOCK prune #-}
-{-# LANGUAGE BangPatterns #-}
+{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE DerivingStrategies #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- |
-- Module: Lightning.Protocol.BOLT2.Types
@@ -10,246 +7,189 @@
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
--- Core types for BOLT #2 peer protocol.
---
--- This module provides newtypes for identifiers, amounts, hashes, and
--- keys used in the Lightning Network peer protocol.
+-- Field types specific to BOLT #2.
module Lightning.Protocol.BOLT2.Types (
- -- * Identifiers (re-exported from BOLT1)
- ChannelId(..)
- , channelId
- , unChannelId
-
- -- * Amounts (re-exported from BOLT1)
- , Satoshi(..)
- , MilliSatoshi(..)
- , satToMsat
- , msatToSat
-
- -- * Cryptographic types (re-exported from BOLT1)
- , Signature(..)
- , signature
- , unSignature
- , Point(..)
- , point
- , unPoint
- , PaymentHash(..)
- , paymentHash
- , unPaymentHash
- , PaymentPreimage(..)
- , paymentPreimage
- , unPaymentPreimage
- , PerCommitmentSecret(..)
- , perCommitmentSecret
- , unPerCommitmentSecret
-
- -- * Chain types (re-exported from BOLT1)
- , ChainHash(..)
- , chainHash
- , unChainHash
- , ShortChannelId(..)
- , shortChannelId
- , scidBlockHeight
- , scidTxIndex
- , scidOutputIndex
-
- -- * Transaction types
- , TxId(..)
- , mkTxId
- , OutPoint(..)
+ HtlcId(..)
+ , SerialId(..)
, ScriptPubKey
- , scriptPubKey
- , unScriptPubKey
-
- -- * Protocol identifiers
- , HtlcId
- , htlcId
- , unHtlcId
- , SerialId
- , serialId
- , unSerialId
-
- -- * Quiescence
- , Initiator(..)
-
- -- * Protocol types
- , FeatureBits
- , featureBits
- , unFeatureBits
- , OnionPacket
- , onionPacket
- , unOnionPacket
-
- -- * Constants
- , channelIdLen
- , signatureLen
- , pointLen
- , chainHashLen
- , shortChannelIdLen
- , paymentHashLen
- , paymentPreimageLen
- , onionPacketLen
- , perCommitmentSecretLen
+ , script_pubkey
+ , un_script_pubkey
+ , Witness
+ , witness
+ , un_witness
+ , OnionRoutingPacket
+ , onion_routing_packet
+ , un_onion_routing_packet
+ , OnionHash
+ , onion_hash
+ , un_onion_hash
+ , AttributionData
+ , attribution_data
+ , un_attribution_data
+ , FeeRange(..)
+ , NextFunding(..)
) where
-import Bitcoin.Prim.Tx (TxId(..), mkTxId, OutPoint(..))
+import Bitcoin.Prim.Tx (TxId)
import Control.DeepSeq (NFData)
import qualified Data.ByteString as BS
-import Data.Word (Word64)
+import Data.Word (Word8, Word64)
import GHC.Generics (Generic)
-import Lightning.Protocol.BOLT1.Prim
- ( ChannelId(..), channelId, unChannelId
- , Satoshi(..), MilliSatoshi(..), satToMsat, msatToSat
- , Signature(..), signature, unSignature
- , Point(..), point, unPoint
- , PaymentHash(..), paymentHash, unPaymentHash
- , PaymentPreimage(..), paymentPreimage, unPaymentPreimage
- , PerCommitmentSecret(..), perCommitmentSecret
- , unPerCommitmentSecret
- , ChainHash(..), chainHash, unChainHash
- , ShortChannelId(..), shortChannelId
- , scidBlockHeight, scidTxIndex, scidOutputIndex
- )
-
--- constants -------------------------------------------------------------------
-
--- | Length of a channel_id in bytes (32).
-channelIdLen :: Int
-channelIdLen = 32
-{-# INLINE channelIdLen #-}
-
--- | Length of a signature in bytes (64, compact format).
-signatureLen :: Int
-signatureLen = 64
-{-# INLINE signatureLen #-}
-
--- | Length of a compressed secp256k1 public key in bytes (33).
-pointLen :: Int
-pointLen = 33
-{-# INLINE pointLen #-}
-
--- | Length of a chain hash in bytes (32).
-chainHashLen :: Int
-chainHashLen = 32
-{-# INLINE chainHashLen #-}
-
--- | Length of a short_channel_id in bytes (8).
-shortChannelIdLen :: Int
-shortChannelIdLen = 8
-{-# INLINE shortChannelIdLen #-}
-
--- | Length of a payment hash in bytes (32).
-paymentHashLen :: Int
-paymentHashLen = 32
-{-# INLINE paymentHashLen #-}
-
--- | Length of a payment preimage in bytes (32).
-paymentPreimageLen :: Int
-paymentPreimageLen = 32
-{-# INLINE paymentPreimageLen #-}
-
--- | Length of an onion routing packet in bytes (1366).
-onionPacketLen :: Int
-onionPacketLen = 1366
-{-# INLINE onionPacketLen #-}
-
--- | Length of a per-commitment secret in bytes (32).
-perCommitmentSecretLen :: Int
-perCommitmentSecretLen = 32
-{-# INLINE perCommitmentSecretLen #-}
-
--- transaction types -----------------------------------------------------------
-
--- | A script pubkey (output script).
-newtype ScriptPubKey = ScriptPubKey BS.ByteString
- deriving stock (Eq, Ord, Show, Generic)
- deriving newtype NFData
-
--- | Construct a 'ScriptPubKey' from a 'BS.ByteString'.
-scriptPubKey :: BS.ByteString -> ScriptPubKey
-scriptPubKey = ScriptPubKey
-{-# INLINE scriptPubKey #-}
-
--- | Extract the underlying 'BS.ByteString' from a 'ScriptPubKey'.
-unScriptPubKey :: ScriptPubKey -> BS.ByteString
-unScriptPubKey (ScriptPubKey bs) = bs
-{-# INLINE unScriptPubKey #-}
-
--- protocol identifiers -------------------------------------------------------
+import Lightning.Protocol.BOLT1 (Satoshi)
--- | An HTLC identifier, unique per channel per direction.
+-- | An HTLC identifier (the @id@ field of the HTLC messages). The
+-- offerer numbers its HTLCs from 0, incrementing by 1.
newtype HtlcId = HtlcId Word64
- deriving stock (Eq, Ord, Show, Generic)
- deriving newtype NFData
+ deriving (Eq, Ord, Show, Generic)
--- | Construct an 'HtlcId' from a 'Word64'.
-htlcId :: Word64 -> HtlcId
-htlcId = HtlcId
-{-# INLINE htlcId #-}
+instance NFData HtlcId
--- | Extract the underlying 'Word64' from an 'HtlcId'.
-unHtlcId :: HtlcId -> Word64
-unHtlcId (HtlcId w) = w
-{-# INLINE unHtlcId #-}
-
--- | A serial identifier for interactive transaction construction.
+-- | The @serial_id@ of an input or output in interactive transaction
+-- construction. The initiator sends even values, the non-initiator
+-- odd ones.
newtype SerialId = SerialId Word64
- deriving stock (Eq, Ord, Show, Generic)
- deriving newtype NFData
-
--- | Construct a 'SerialId' from a 'Word64'.
-serialId :: Word64 -> SerialId
-serialId = SerialId
-{-# INLINE serialId #-}
-
--- | Extract the underlying 'Word64' from a 'SerialId'.
-unSerialId :: SerialId -> Word64
-unSerialId (SerialId w) = w
-{-# INLINE unSerialId #-}
-
--- quiescence -----------------------------------------------------------------
+ deriving (Eq, Ord, Show, Generic)
--- | Role in quiescence (STFU) protocol.
-data Initiator
- = IsInitiator -- ^ This node initiated quiescence.
- | NotInitiator -- ^ This node did not initiate quiescence.
- deriving stock (Eq, Ord, Show, Generic)
+instance NFData SerialId
-instance NFData Initiator
-
--- protocol types --------------------------------------------------------------
-
--- | Feature bits (variable length).
-newtype FeatureBits = FeatureBits BS.ByteString
- deriving stock (Eq, Ord, Show, Generic)
- deriving newtype NFData
-
--- | Construct 'FeatureBits' from a 'BS.ByteString'.
-featureBits :: BS.ByteString -> FeatureBits
-featureBits = FeatureBits
-{-# INLINE featureBits #-}
-
--- | Extract the underlying 'BS.ByteString' from 'FeatureBits'.
-unFeatureBits :: FeatureBits -> BS.ByteString
-unFeatureBits (FeatureBits bs) = bs
-{-# INLINE unFeatureBits #-}
+-- | A scriptPubKey, at most 65535 bytes (the most a u16 length prefix
+-- can describe).
+newtype ScriptPubKey = ScriptPubKey BS.ByteString
+ deriving (Eq, Ord, Show, Generic)
--- | A 1366-byte onion routing packet.
-newtype OnionPacket = OnionPacket BS.ByteString
- deriving stock (Eq, Ord, Show, Generic)
- deriving newtype NFData
+instance NFData ScriptPubKey
--- | Construct an 'OnionPacket' from a 1366-byte 'BS.ByteString'.
+-- | Construct a 'ScriptPubKey', failing above 65535 bytes. The script
+-- itself isn't checked; the forms acceptable in @shutdown@ depend on
+-- negotiated features.
+--
+-- >>> script_pubkey "\x51\x02\x4e\x73"
+-- Just (ScriptPubKey "Q\STXNs")
+-- >>> script_pubkey (BS.replicate 65536 0x00)
+-- Nothing
+script_pubkey :: BS.ByteString -> Maybe ScriptPubKey
+script_pubkey bs
+ | BS.length bs <= 65535 = Just (ScriptPubKey bs)
+ | otherwise = Nothing
+{-# INLINE script_pubkey #-}
+
+-- | The bytes of a 'ScriptPubKey'.
+un_script_pubkey :: ScriptPubKey -> BS.ByteString
+un_script_pubkey (ScriptPubKey bs) = bs
+{-# INLINE un_script_pubkey #-}
+
+-- | The serialized witness of one input in @tx_signatures@ (encoded as
+-- in Bitcoin's wire protocol), at most 65535 bytes.
+newtype Witness = Witness BS.ByteString
+ deriving (Eq, Ord, Show, Generic)
+
+instance NFData Witness
+
+-- | Construct a 'Witness', failing above 65535 bytes. The contents
+-- aren't checked.
+--
+-- >>> witness "\x01\x01\x2a"
+-- Just (Witness "\SOH\SOH*")
+witness :: BS.ByteString -> Maybe Witness
+witness bs
+ | BS.length bs <= 65535 = Just (Witness bs)
+ | otherwise = Nothing
+{-# INLINE witness #-}
+
+-- | The bytes of a 'Witness'.
+un_witness :: Witness -> BS.ByteString
+un_witness (Witness bs) = bs
+{-# INLINE un_witness #-}
+
+-- | The 1366-byte @onion_routing_packet@ of @update_add_htlc@, kept
+-- opaque (BOLT #4 defines its structure).
+newtype OnionRoutingPacket = OnionRoutingPacket BS.ByteString
+ deriving (Eq, Ord, Show, Generic)
+
+instance NFData OnionRoutingPacket
+
+-- | Construct an 'OnionRoutingPacket' from exactly 1366 bytes.
+--
+-- >>> let bs = BS.replicate 1366 0x00
+-- >>> fmap un_onion_routing_packet (onion_routing_packet bs) == Just bs
+-- True
+-- >>> onion_routing_packet (BS.take 1365 bs)
+-- Nothing
+onion_routing_packet :: BS.ByteString -> Maybe OnionRoutingPacket
+onion_routing_packet bs
+ | BS.length bs == 1366 = Just (OnionRoutingPacket bs)
+ | otherwise = Nothing
+{-# INLINE onion_routing_packet #-}
+
+-- | The bytes of an 'OnionRoutingPacket'.
+un_onion_routing_packet :: OnionRoutingPacket -> BS.ByteString
+un_onion_routing_packet (OnionRoutingPacket bs) = bs
+{-# INLINE un_onion_routing_packet #-}
+
+-- | The SHA256 hash of an onion routing packet (the @sha256_of_onion@
+-- field of @update_fail_malformed_htlc@).
+newtype OnionHash = OnionHash BS.ByteString
+ deriving (Eq, Ord, Show, Generic)
+
+instance NFData OnionHash
+
+-- | Construct an 'OnionHash' from exactly 32 bytes.
+--
+-- >>> onion_hash (BS.replicate 31 0x00)
+-- Nothing
+onion_hash :: BS.ByteString -> Maybe OnionHash
+onion_hash bs
+ | BS.length bs == 32 = Just (OnionHash bs)
+ | otherwise = Nothing
+{-# INLINE onion_hash #-}
+
+-- | The bytes of an 'OnionHash'.
+un_onion_hash :: OnionHash -> BS.ByteString
+un_onion_hash (OnionHash bs) = bs
+{-# INLINE un_onion_hash #-}
+
+-- | The 920-byte @attribution_data@ of @update_fulfill_htlc@ and
+-- @update_fail_htlc@: twenty u32 HTLC hold times followed by 210
+-- four-byte truncated HMACs. Kept opaque (BOLT #4 defines its use).
+newtype AttributionData = AttributionData BS.ByteString
+ deriving (Eq, Ord, Show, Generic)
+
+instance NFData AttributionData
+
+-- | Construct an 'AttributionData' from exactly 920 bytes.
--
--- Returns 'Nothing' if the input is not exactly 1366 bytes.
-onionPacket :: BS.ByteString -> Maybe OnionPacket
-onionPacket !bs
- | BS.length bs == onionPacketLen = Just $! OnionPacket bs
- | otherwise = Nothing
-{-# INLINABLE onionPacket #-}
-
--- | Extract the underlying 'BS.ByteString' from an 'OnionPacket'.
-unOnionPacket :: OnionPacket -> BS.ByteString
-unOnionPacket (OnionPacket bs) = bs
-{-# INLINE unOnionPacket #-}
+-- >>> let bs = BS.replicate 920 0x00
+-- >>> fmap un_attribution_data (attribution_data bs) == Just bs
+-- True
+-- >>> attribution_data (BS.drop 1 bs)
+-- Nothing
+attribution_data :: BS.ByteString -> Maybe AttributionData
+attribution_data bs
+ | BS.length bs == 920 = Just (AttributionData bs)
+ | otherwise = Nothing
+{-# INLINE attribution_data #-}
+
+-- | The bytes of an 'AttributionData'.
+un_attribution_data :: AttributionData -> BS.ByteString
+un_attribution_data (AttributionData bs) = bs
+{-# INLINE un_attribution_data #-}
+
+-- | The @fee_range@ of @closing_signed@: the fees the sender is
+-- prepared to pay for the closing transaction.
+data FeeRange = FeeRange
+ { fee_range_min_fee_satoshis :: {-# UNPACK #-} !Satoshi
+ , fee_range_max_fee_satoshis :: {-# UNPACK #-} !Satoshi
+ } deriving (Eq, Show, Generic)
+
+instance NFData FeeRange
+
+-- | The @next_funding@ record of @channel_reestablish@: an interactive
+-- funding transaction whose signatures are still being exchanged.
+data NextFunding = NextFunding
+ { next_funding_txid :: !TxId
+ , next_funding_retransmit_flags :: {-# UNPACK #-} !Word8
+ -- ^ bit 0: the sender wants @commitment_signed@ retransmitted
+ } deriving (Eq, Show, Generic)
+
+instance NFData NextFunding
diff --git a/ppad-bolt2.cabal b/ppad-bolt2.cabal
@@ -1,6 +1,6 @@
cabal-version: 3.0
name: ppad-bolt2
-version: 0.0.1
+version: 0.1.0
synopsis: Peer protocol per BOLT #2
license: MIT
license-file: LICENSE
@@ -8,7 +8,7 @@ author: Jared Tobin
maintainer: jared@ppad.tech
category: Cryptography
build-type: Simple
-tested-with: GHC == 9.10.3
+tested-with: GHC == { 9.10.3 }
extra-doc-files: CHANGELOG
description:
Peer protocol, per
@@ -25,6 +25,7 @@ library
-Wall
exposed-modules:
Lightning.Protocol.BOLT2
+ other-modules:
Lightning.Protocol.BOLT2.Codec
Lightning.Protocol.BOLT2.Messages
Lightning.Protocol.BOLT2.Types
@@ -32,8 +33,9 @@ library
base >= 4.9 && < 5
, bytestring >= 0.9 && < 0.13
, deepseq >= 1.4 && < 1.6
- , ppad-bolt1 >= 0.0.1 && < 0.1
- , ppad-tx >= 0.1 && < 0.2
+ , ppad-bolt1 >= 0.1 && < 0.2
+ , ppad-bolt9 >= 0.1 && < 0.2
+ , ppad-tx >= 0.2 && < 0.3
test-suite bolt2-tests
type: exitcode-stdio-1.0
@@ -42,7 +44,7 @@ test-suite bolt2-tests
main-is: Main.hs
ghc-options:
- -rtsopts -Wall -O2
+ -rtsopts -Wall
build-depends:
base
@@ -50,6 +52,8 @@ test-suite bolt2-tests
, ppad-base16
, ppad-bolt1
, ppad-bolt2
+ , ppad-bolt9
+ , ppad-tx
, tasty
, tasty-hunit
, tasty-quickcheck
@@ -59,31 +63,35 @@ benchmark bolt2-bench
default-language: Haskell2010
hs-source-dirs: bench
main-is: Main.hs
+ other-modules: Fixtures
ghc-options:
- -rtsopts -O2 -Wall -fno-warn-orphans
+ -rtsopts -O2 -Wall
build-depends:
base
, bytestring
, criterion
- , deepseq
, ppad-bolt1
, ppad-bolt2
+ , ppad-bolt9
+ , ppad-tx
benchmark bolt2-weigh
type: exitcode-stdio-1.0
default-language: Haskell2010
hs-source-dirs: bench
main-is: Weight.hs
+ other-modules: Fixtures
ghc-options:
- -rtsopts -O2 -Wall -fno-warn-orphans
+ -rtsopts -O2 -Wall
build-depends:
base
, bytestring
- , deepseq
, ppad-bolt1
, ppad-bolt2
+ , ppad-bolt9
+ , ppad-tx
, weigh