ppad-bolt2-0.0.1: lib/Lightning/Protocol/BOLT2/Codec.hs
{-# OPTIONS_HADDOCK prune #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
-- |
-- Module: Lightning.Protocol.BOLT2.Codec
-- Copyright: (c) 2025 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
-- Encode/decode functions for 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
) where
import Control.DeepSeq (NFData)
import Control.Monad (unless)
import qualified Data.ByteString as BS
import Data.Word (Word8, Word16, Word32)
import GHC.Generics (Generic)
import Lightning.Protocol.BOLT1
( TlvStream
, unsafeTlvStream
, TlvError
, encodeU16
, encodeU32
, encodeU64
, decodeU16
, decodeU32
, decodeU64
, encodeTlvStream
, decodeTlvStreamRaw
)
import Lightning.Protocol.BOLT2.Types
import Lightning.Protocol.BOLT2.Messages
-- Error types -----------------------------------------------------------------
-- | Encoding errors.
data EncodeError
= EncodeLengthOverflow -- ^ Payload exceeds u16 max (65535 bytes)
deriving stock (Eq, Show, Generic)
instance NFData EncodeError
-- | Decoding errors.
data DecodeError
= DecodeInsufficientBytes
| DecodeInvalidLength
| DecodeInvalidChannelId
| DecodeInvalidChainHash
| DecodeInvalidSignature
| DecodeInvalidPoint
| DecodeInvalidTxId
| DecodeInvalidPaymentHash
| DecodeInvalidPaymentPreimage
| DecodeInvalidOnionPacket
| DecodeInvalidSecret
| DecodeTlvError !TlvError
deriving stock (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 txIdLen bs)
tid <- maybe (Left DecodeInvalidTxId) Right (txId 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 Satoshis.
decodeSatoshis
:: BS.ByteString -> Either DecodeError (Satoshis, BS.ByteString)
decodeSatoshis !bs = do
(val, rest) <- maybe (Left DecodeInsufficientBytes) Right (decodeU64 bs)
Right (Satoshis val, rest)
{-# INLINE decodeSatoshis #-}
-- | Decode a u64 as MilliSatoshis.
decodeMilliSatoshis
:: BS.ByteString -> Either DecodeError (MilliSatoshis, BS.ByteString)
decodeMilliSatoshis !bs = do
(val, rest) <- maybe (Left DecodeInsufficientBytes) Right (decodeU64 bs)
Right (MilliSatoshis val, rest)
{-# INLINE decodeMilliSatoshis #-}
-- | 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 Secret (32 bytes).
decodeSecretBytes
:: BS.ByteString -> Either DecodeError (Secret, BS.ByteString)
decodeSecretBytes !bs = do
(raw, rest) <- maybe (Left DecodeInsufficientBytes) Right
(decodeBytes secretLen bs)
sec <- maybe (Left DecodeInvalidSecret) Right (secret raw)
Right (sec, rest)
{-# INLINE decodeSecretBytes #-}
-- | 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
| 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 (unSatoshis (openChannelFundingSatoshis msg))
, encodeU64 (unMilliSatoshis (openChannelPushMsat msg))
, encodeU64 (unSatoshis (openChannelDustLimitSatoshis msg))
, encodeU64 (unMilliSatoshis (openChannelMaxHtlcValueInFlight msg))
, encodeU64 (unSatoshis (openChannelChannelReserveSat msg))
, encodeU64 (unMilliSatoshis (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)
]
-- | 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) <- decodeSatoshis rest2
(pushMsat, rest4) <- decodeMilliSatoshis rest3
(dustLimit, rest5) <- decodeSatoshis rest4
(maxHtlcVal, rest6) <- decodeMilliSatoshis rest5
(chanReserve, rest7) <- decodeSatoshis rest6
(htlcMin, rest8) <- decodeMilliSatoshis 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
, openChannelFundingSatoshis = fundingSats
, openChannelPushMsat = pushMsat
, openChannelDustLimitSatoshis = 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 (unSatoshis (acceptChannelDustLimitSatoshis msg))
, encodeU64 (unMilliSatoshis (acceptChannelMaxHtlcValueInFlight msg))
, encodeU64 (unSatoshis (acceptChannelChannelReserveSat msg))
, encodeU64 (unMilliSatoshis (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)
]
-- | Decode an AcceptChannel message (type 33).
decodeAcceptChannel
:: BS.ByteString -> Either DecodeError (AcceptChannel, BS.ByteString)
decodeAcceptChannel !bs = do
(tempChanId, rest1) <- decodeChannelIdBytes bs
(dustLimit, rest2) <- decodeSatoshis rest1
(maxHtlcVal, rest3) <- decodeMilliSatoshis rest2
(chanReserve, rest4) <- decodeSatoshis rest3
(htlcMin, rest5) <- decodeMilliSatoshis 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
, acceptChannelDustLimitSatoshis = 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)
, unTxId (fundingCreatedFundingTxid msg)
, encodeU16 (fundingCreatedFundingOutIdx msg)
, unSignature (fundingCreatedSignature msg)
]
-- | 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)
]
-- | 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)
]
-- | 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 (stfuInitiator msg)
]
-- | Decode a Stfu message (type 2).
decodeStfu :: BS.ByteString -> Either DecodeError (Stfu, BS.ByteString)
decodeStfu !bs = do
(chanId, rest1) <- decodeChannelIdBytes bs
(initiator, rest2) <- maybe (Left DecodeInsufficientBytes) Right
(decodeU8 rest1)
let !msg = Stfu
{ stfuChannelId = chanId
, stfuInitiator = initiator
}
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).
--
-- 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 (unSatoshis (closingSignedFeeSatoshis 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) <- decodeSatoshis rest1
(sig, rest3) <- decodeSignatureBytes rest2
tlvs <- decodeTlvs rest3
let !msg = ClosingSigned
{ closingSignedChannelId = chanId
, closingSignedFeeSatoshis = feeSats
, closingSignedSignature = sig
, closingSignedTlvs = tlvs
}
Right (msg, BS.empty)
-- | Encode a ClosingComplete message (type 40).
--
-- 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 (unSatoshis (closingCompleteFeeSatoshis 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) <- decodeSatoshis rest3
(locktime, rest5) <- decodeU32E rest4
tlvs <- decodeTlvs rest5
let !msg = ClosingComplete
{ closingCompleteChannelId = chanId
, closingCompleteCloserScript = closerScript
, closingCompleteCloseeScript = closeeScript
, closingCompleteFeeSatoshis = feeSats
, closingCompleteLocktime = locktime
, closingCompleteTlvs = tlvs
}
Right (msg, BS.empty)
-- | Encode a ClosingSig message (type 41).
--
-- 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 (unSatoshis (closingSigFeeSatoshis 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) <- decodeSatoshis rest3
(locktime, rest5) <- decodeU32E rest4
tlvs <- decodeTlvs rest5
let !msg = ClosingSig
{ closingSigChannelId = chanId
, closingSigCloserScript = closerScript
, closingSigCloseeScript = closeeScript
, closingSigFeeSatoshis = 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 (unSatoshis (openChannel2FundingSatoshis msg))
, encodeU64 (unSatoshis (openChannel2DustLimitSatoshis msg))
, encodeU64 (unMilliSatoshis (openChannel2MaxHtlcValueInFlight msg))
, encodeU64 (unMilliSatoshis (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)
]
-- | 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) <- decodeSatoshis rest4
(dustLimit, rest6) <- decodeSatoshis rest5
(maxHtlcVal, rest7) <- decodeMilliSatoshis rest6
(htlcMin, rest8) <- decodeMilliSatoshis 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
, openChannel2FundingSatoshis = fundingSats
, openChannel2DustLimitSatoshis = 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 (unSatoshis (acceptChannel2FundingSatoshis msg))
, encodeU64 (unSatoshis (acceptChannel2DustLimitSatoshis msg))
, encodeU64 (unMilliSatoshis (acceptChannel2MaxHtlcValueInFlight msg))
, encodeU64 (unMilliSatoshis (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 an AcceptChannel2 message (type 65).
decodeAcceptChannel2
:: BS.ByteString -> Either DecodeError (AcceptChannel2, BS.ByteString)
decodeAcceptChannel2 !bs = do
(tempCid, rest1) <- decodeChannelIdBytes bs
(fundingSats, rest2) <- decodeSatoshis rest1
(dustLimit, rest3) <- decodeSatoshis rest2
(maxHtlcVal, rest4) <- decodeMilliSatoshis rest3
(htlcMin, rest5) <- decodeMilliSatoshis 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
, acceptChannel2FundingSatoshis = fundingSats
, acceptChannel2DustLimitSatoshis = 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 (txAddInputSerialId msg)
, prevTxEnc
, encodeU32 (txAddInputPrevVout msg)
, encodeU32 (txAddInputSequence msg)
]
-- | Decode a TxAddInput message (type 66).
decodeTxAddInput
:: BS.ByteString -> Either DecodeError (TxAddInput, BS.ByteString)
decodeTxAddInput !bs = do
(cid, rest1) <- decodeChannelIdBytes bs
(serialId, 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
, 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 (txAddOutputSerialId msg)
, encodeU64 (unSatoshis (txAddOutputSats msg))
, scriptEnc
]
-- | Decode a TxAddOutput message (type 67).
decodeTxAddOutput
:: BS.ByteString -> Either DecodeError (TxAddOutput, BS.ByteString)
decodeTxAddOutput !bs = do
(cid, rest1) <- decodeChannelIdBytes bs
(serialId, rest2) <- maybe (Left DecodeInsufficientBytes) Right
(decodeU64 rest1)
(sats, rest3) <- decodeSatoshis rest2
(scriptBs, rest4) <- decodeU16Bytes rest3
let !msg = TxAddOutput
{ txAddOutputChannelId = cid
, txAddOutputSerialId = serialId
, 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 (txRemoveInputSerialId msg)
]
-- | Decode a TxRemoveInput message (type 68).
decodeTxRemoveInput
:: BS.ByteString -> Either DecodeError (TxRemoveInput, BS.ByteString)
decodeTxRemoveInput !bs = do
(cid, rest1) <- decodeChannelIdBytes bs
(serialId, rest2) <- maybe (Left DecodeInsufficientBytes) Right
(decodeU64 rest1)
let !msg = TxRemoveInput
{ txRemoveInputChannelId = cid
, txRemoveInputSerialId = serialId
}
Right (msg, rest2)
-- | Encode a TxRemoveOutput message (type 69).
encodeTxRemoveOutput :: TxRemoveOutput -> BS.ByteString
encodeTxRemoveOutput !msg = mconcat
[ unChannelId (txRemoveOutputChannelId msg)
, encodeU64 (txRemoveOutputSerialId msg)
]
-- | Decode a TxRemoveOutput message (type 69).
decodeTxRemoveOutput
:: BS.ByteString -> Either DecodeError (TxRemoveOutput, BS.ByteString)
decodeTxRemoveOutput !bs = do
(cid, rest1) <- decodeChannelIdBytes bs
(serialId, rest2) <- maybe (Left DecodeInsufficientBytes) Right
(decodeU64 rest1)
let !msg = TxRemoveOutput
{ txRemoveOutputChannelId = cid
, txRemoveOutputSerialId = serialId
}
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)
, unTxId (txSignaturesTxid msg)
, 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)
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)
]
-- | 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 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 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 (updateAddHtlcId m)
, encodeU64 (unMilliSatoshis (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
(htlcId, 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
, updateAddHtlcAmountMsat = MilliSatoshis 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 (updateFulfillHtlcId m)
, unPaymentPreimage (updateFulfillHtlcPaymentPreimage m)
, encodeTlvStream (updateFulfillHtlcTlvs m)
]
-- | Decode an UpdateFulfillHtlc message (type 130).
decodeUpdateFulfillHtlc
:: BS.ByteString -> Either DecodeError (UpdateFulfillHtlc, BS.ByteString)
decodeUpdateFulfillHtlc !bs = do
(cid, rest1) <- decodeChannelIdBytes bs
(htlcId, rest2) <- maybe (Left DecodeInsufficientBytes) Right
(decodeU64 rest1)
(preimage, rest3) <- decodePaymentPreimageBytes rest2
(tlvs, rest4) <- decodeOptionalTlvs rest3
let !msg = UpdateFulfillHtlc
{ updateFulfillHtlcChannelId = cid
, updateFulfillHtlcId = htlcId
, 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 (updateFailHtlcId m)
, reasonEnc
, encodeTlvStream (updateFailHtlcTlvs m)
]
-- | Decode an UpdateFailHtlc message (type 131).
decodeUpdateFailHtlc
:: BS.ByteString -> Either DecodeError (UpdateFailHtlc, BS.ByteString)
decodeUpdateFailHtlc !bs = do
(cid, rest1) <- decodeChannelIdBytes bs
(htlcId, rest2) <- maybe (Left DecodeInsufficientBytes) Right
(decodeU64 rest1)
(reason, rest3) <- decodeU16Bytes rest2
(tlvs, rest4) <- decodeOptionalTlvs rest3
let !msg = UpdateFailHtlc
{ updateFailHtlcChannelId = cid
, updateFailHtlcId = htlcId
, updateFailHtlcReason = reason
, updateFailHtlcTlvs = tlvs
}
Right (msg, rest4)
-- | Encode an UpdateFailMalformedHtlc message (type 135).
encodeUpdateFailMalformedHtlc :: UpdateFailMalformedHtlc -> BS.ByteString
encodeUpdateFailMalformedHtlc !m = mconcat
[ unChannelId (updateFailMalformedHtlcChannelId m)
, encodeU64 (updateFailMalformedHtlcId m)
, unPaymentHash (updateFailMalformedHtlcSha256Onion m)
, encodeU16 (updateFailMalformedHtlcFailureCode m)
]
-- | Decode an UpdateFailMalformedHtlc message (type 135).
decodeUpdateFailMalformedHtlc
:: BS.ByteString -> Either DecodeError (UpdateFailMalformedHtlc, BS.ByteString)
decodeUpdateFailMalformedHtlc !bs = do
(cid, rest1) <- decodeChannelIdBytes bs
(htlcId, rest2) <- maybe (Left DecodeInsufficientBytes) Right
(decodeU64 rest1)
(sha256Onion, rest3) <- decodePaymentHashBytes rest2
(failCode, rest4) <- decodeU16E rest3
let !msg = UpdateFailMalformedHtlc
{ updateFailMalformedHtlcChannelId = cid
, updateFailMalformedHtlcId = htlcId
, 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)
, unSecret (revokeAndAckPerCommitmentSecret m)
, unPoint (revokeAndAckNextPerCommitPoint m)
]
-- | Decode a RevokeAndAck message (type 133).
decodeRevokeAndAck
:: BS.ByteString -> Either DecodeError (RevokeAndAck, BS.ByteString)
decodeRevokeAndAck !bs = do
(cid, rest1) <- decodeChannelIdBytes bs
(sec, rest2) <- decodeSecretBytes 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 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)
, unSecret (channelReestablishYourLastCommitSecret m)
, unPoint (channelReestablishMyCurrentCommitPoint m)
, encodeTlvStream (channelReestablishTlvs m)
]
-- | 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) <- decodeSecretBytes 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)