ppad-bolt2 0.0.1 → 0.1.0
raw patch · 10 files changed
+3715/−4263 lines, 10 filesdep +ppad-bolt9dep +ppad-txdep ~deepseqdep ~ppad-bolt1PVP ok
version bump matches the API change (PVP)
Dependencies added: ppad-bolt9, ppad-tx
Dependency ranges changed: deepseq, ppad-bolt1
API changes (from Hackage documentation)
- Lightning.Protocol.BOLT2.Codec: DecodeInsufficientBytes :: DecodeError
- Lightning.Protocol.BOLT2.Codec: DecodeInvalidChainHash :: DecodeError
- Lightning.Protocol.BOLT2.Codec: DecodeInvalidChannelId :: DecodeError
- Lightning.Protocol.BOLT2.Codec: DecodeInvalidLength :: DecodeError
- Lightning.Protocol.BOLT2.Codec: DecodeInvalidOnionPacket :: DecodeError
- Lightning.Protocol.BOLT2.Codec: DecodeInvalidPaymentHash :: DecodeError
- Lightning.Protocol.BOLT2.Codec: DecodeInvalidPaymentPreimage :: DecodeError
- Lightning.Protocol.BOLT2.Codec: DecodeInvalidPoint :: DecodeError
- Lightning.Protocol.BOLT2.Codec: DecodeInvalidSecret :: DecodeError
- Lightning.Protocol.BOLT2.Codec: DecodeInvalidSignature :: DecodeError
- Lightning.Protocol.BOLT2.Codec: DecodeInvalidTxId :: DecodeError
- Lightning.Protocol.BOLT2.Codec: DecodeTlvError :: !TlvError -> DecodeError
- Lightning.Protocol.BOLT2.Codec: EncodeLengthOverflow :: EncodeError
- Lightning.Protocol.BOLT2.Codec: data DecodeError
- Lightning.Protocol.BOLT2.Codec: data EncodeError
- Lightning.Protocol.BOLT2.Codec: decodeAcceptChannel :: ByteString -> Either DecodeError (AcceptChannel, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeAcceptChannel2 :: ByteString -> Either DecodeError (AcceptChannel2, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeChannelReady :: ByteString -> Either DecodeError (ChannelReady, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeChannelReestablish :: ByteString -> Either DecodeError (ChannelReestablish, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeClosingComplete :: ByteString -> Either DecodeError (ClosingComplete, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeClosingSig :: ByteString -> Either DecodeError (ClosingSig, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeClosingSigned :: ByteString -> Either DecodeError (ClosingSigned, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeCommitmentSigned :: ByteString -> Either DecodeError (CommitmentSigned, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeFundingCreated :: ByteString -> Either DecodeError (FundingCreated, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeFundingSigned :: ByteString -> Either DecodeError (FundingSigned, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeOpenChannel :: ByteString -> Either DecodeError (OpenChannel, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeOpenChannel2 :: ByteString -> Either DecodeError (OpenChannel2, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeRevokeAndAck :: ByteString -> Either DecodeError (RevokeAndAck, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeShutdown :: ByteString -> Either DecodeError (Shutdown, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeStfu :: ByteString -> Either DecodeError (Stfu, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeTxAbort :: ByteString -> Either DecodeError (TxAbort, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeTxAckRbf :: ByteString -> Either DecodeError (TxAckRbf, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeTxAddInput :: ByteString -> Either DecodeError (TxAddInput, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeTxAddOutput :: ByteString -> Either DecodeError (TxAddOutput, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeTxComplete :: ByteString -> Either DecodeError (TxComplete, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeTxInitRbf :: ByteString -> Either DecodeError (TxInitRbf, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeTxRemoveInput :: ByteString -> Either DecodeError (TxRemoveInput, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeTxRemoveOutput :: ByteString -> Either DecodeError (TxRemoveOutput, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeTxSignatures :: ByteString -> Either DecodeError (TxSignatures, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeUpdateAddHtlc :: ByteString -> Either DecodeError (UpdateAddHtlc, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeUpdateFailHtlc :: ByteString -> Either DecodeError (UpdateFailHtlc, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeUpdateFailMalformedHtlc :: ByteString -> Either DecodeError (UpdateFailMalformedHtlc, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeUpdateFee :: ByteString -> Either DecodeError (UpdateFee, ByteString)
- Lightning.Protocol.BOLT2.Codec: decodeUpdateFulfillHtlc :: ByteString -> Either DecodeError (UpdateFulfillHtlc, ByteString)
- Lightning.Protocol.BOLT2.Codec: encodeAcceptChannel :: AcceptChannel -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeAcceptChannel2 :: AcceptChannel2 -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeChannelReady :: ChannelReady -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeChannelReestablish :: ChannelReestablish -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeClosingComplete :: ClosingComplete -> Either EncodeError ByteString
- Lightning.Protocol.BOLT2.Codec: encodeClosingSig :: ClosingSig -> Either EncodeError ByteString
- Lightning.Protocol.BOLT2.Codec: encodeClosingSigned :: ClosingSigned -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeCommitmentSigned :: CommitmentSigned -> Either EncodeError ByteString
- Lightning.Protocol.BOLT2.Codec: encodeFundingCreated :: FundingCreated -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeFundingSigned :: FundingSigned -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeOpenChannel :: OpenChannel -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeOpenChannel2 :: OpenChannel2 -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeRevokeAndAck :: RevokeAndAck -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeShutdown :: Shutdown -> Either EncodeError ByteString
- Lightning.Protocol.BOLT2.Codec: encodeStfu :: Stfu -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeTxAbort :: TxAbort -> Either EncodeError ByteString
- Lightning.Protocol.BOLT2.Codec: encodeTxAckRbf :: TxAckRbf -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeTxAddInput :: TxAddInput -> Either EncodeError ByteString
- Lightning.Protocol.BOLT2.Codec: encodeTxAddOutput :: TxAddOutput -> Either EncodeError ByteString
- Lightning.Protocol.BOLT2.Codec: encodeTxComplete :: TxComplete -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeTxInitRbf :: TxInitRbf -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeTxRemoveInput :: TxRemoveInput -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeTxRemoveOutput :: TxRemoveOutput -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeTxSignatures :: TxSignatures -> Either EncodeError ByteString
- Lightning.Protocol.BOLT2.Codec: encodeUpdateAddHtlc :: UpdateAddHtlc -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeUpdateFailHtlc :: UpdateFailHtlc -> Either EncodeError ByteString
- Lightning.Protocol.BOLT2.Codec: encodeUpdateFailMalformedHtlc :: UpdateFailMalformedHtlc -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeUpdateFee :: UpdateFee -> ByteString
- Lightning.Protocol.BOLT2.Codec: encodeUpdateFulfillHtlc :: UpdateFulfillHtlc -> ByteString
- Lightning.Protocol.BOLT2.Codec: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Codec.DecodeError
- Lightning.Protocol.BOLT2.Codec: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Codec.EncodeError
- Lightning.Protocol.BOLT2.Codec: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Codec.DecodeError
- Lightning.Protocol.BOLT2.Codec: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Codec.EncodeError
- Lightning.Protocol.BOLT2.Codec: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Codec.DecodeError
- Lightning.Protocol.BOLT2.Codec: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Codec.EncodeError
- Lightning.Protocol.BOLT2.Codec: instance GHC.Show.Show Lightning.Protocol.BOLT2.Codec.DecodeError
- Lightning.Protocol.BOLT2.Codec: instance GHC.Show.Show Lightning.Protocol.BOLT2.Codec.EncodeError
- Lightning.Protocol.BOLT2.Messages: AcceptChannel :: !ChannelId -> {-# UNPACK #-} !Satoshis -> {-# UNPACK #-} !MilliSatoshis -> {-# UNPACK #-} !Satoshis -> {-# UNPACK #-} !MilliSatoshis -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Word16 -> {-# UNPACK #-} !Word16 -> !Point -> !Point -> !Point -> !Point -> !Point -> !Point -> !TlvStream -> AcceptChannel
- Lightning.Protocol.BOLT2.Messages: AcceptChannel2 :: !ChannelId -> {-# UNPACK #-} !Satoshis -> {-# UNPACK #-} !Satoshis -> {-# UNPACK #-} !MilliSatoshis -> {-# UNPACK #-} !MilliSatoshis -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Word16 -> {-# UNPACK #-} !Word16 -> !Point -> !Point -> !Point -> !Point -> !Point -> !Point -> !Point -> !TlvStream -> AcceptChannel2
- Lightning.Protocol.BOLT2.Messages: ChannelReady :: !ChannelId -> !Point -> !TlvStream -> ChannelReady
- Lightning.Protocol.BOLT2.Messages: ChannelReestablish :: !ChannelId -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> !Secret -> !Point -> !TlvStream -> ChannelReestablish
- Lightning.Protocol.BOLT2.Messages: ClosingComplete :: !ChannelId -> !ScriptPubKey -> !ScriptPubKey -> {-# UNPACK #-} !Satoshis -> {-# UNPACK #-} !Word32 -> !TlvStream -> ClosingComplete
- Lightning.Protocol.BOLT2.Messages: ClosingSig :: !ChannelId -> !ScriptPubKey -> !ScriptPubKey -> {-# UNPACK #-} !Satoshis -> {-# UNPACK #-} !Word32 -> !TlvStream -> ClosingSig
- Lightning.Protocol.BOLT2.Messages: ClosingSigned :: !ChannelId -> {-# UNPACK #-} !Satoshis -> !Signature -> !TlvStream -> ClosingSigned
- Lightning.Protocol.BOLT2.Messages: CommitmentSigned :: !ChannelId -> !Signature -> ![Signature] -> CommitmentSigned
- Lightning.Protocol.BOLT2.Messages: FundingCreated :: !ChannelId -> !TxId -> {-# UNPACK #-} !Word16 -> !Signature -> FundingCreated
- Lightning.Protocol.BOLT2.Messages: FundingSigned :: !ChannelId -> !Signature -> FundingSigned
- Lightning.Protocol.BOLT2.Messages: MsgAcceptChannel :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgAcceptChannel2 :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgAcceptChannel2Val :: !AcceptChannel2 -> Message
- Lightning.Protocol.BOLT2.Messages: MsgAcceptChannelVal :: !AcceptChannel -> Message
- Lightning.Protocol.BOLT2.Messages: MsgChannelReady :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgChannelReadyVal :: !ChannelReady -> Message
- Lightning.Protocol.BOLT2.Messages: MsgChannelReestablish :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgChannelReestablishVal :: !ChannelReestablish -> Message
- Lightning.Protocol.BOLT2.Messages: MsgClosingComplete :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgClosingCompleteVal :: !ClosingComplete -> Message
- Lightning.Protocol.BOLT2.Messages: MsgClosingSig :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgClosingSigVal :: !ClosingSig -> Message
- Lightning.Protocol.BOLT2.Messages: MsgClosingSigned :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgClosingSignedVal :: !ClosingSigned -> Message
- Lightning.Protocol.BOLT2.Messages: MsgCommitmentSigned :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgCommitmentSignedVal :: !CommitmentSigned -> Message
- Lightning.Protocol.BOLT2.Messages: MsgFundingCreated :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgFundingCreatedVal :: !FundingCreated -> Message
- Lightning.Protocol.BOLT2.Messages: MsgFundingSigned :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgFundingSignedVal :: !FundingSigned -> Message
- Lightning.Protocol.BOLT2.Messages: MsgOpenChannel :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgOpenChannel2 :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgOpenChannel2Val :: !OpenChannel2 -> Message
- Lightning.Protocol.BOLT2.Messages: MsgOpenChannelVal :: !OpenChannel -> Message
- Lightning.Protocol.BOLT2.Messages: MsgRevokeAndAck :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgRevokeAndAckVal :: !RevokeAndAck -> Message
- Lightning.Protocol.BOLT2.Messages: MsgShutdown :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgShutdownVal :: !Shutdown -> Message
- Lightning.Protocol.BOLT2.Messages: MsgStfu :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgStfuVal :: !Stfu -> Message
- Lightning.Protocol.BOLT2.Messages: MsgTxAbort :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgTxAbortVal :: !TxAbort -> Message
- Lightning.Protocol.BOLT2.Messages: MsgTxAckRbf :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgTxAckRbfVal :: !TxAckRbf -> Message
- Lightning.Protocol.BOLT2.Messages: MsgTxAddInput :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgTxAddInputVal :: !TxAddInput -> Message
- Lightning.Protocol.BOLT2.Messages: MsgTxAddOutput :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgTxAddOutputVal :: !TxAddOutput -> Message
- Lightning.Protocol.BOLT2.Messages: MsgTxComplete :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgTxCompleteVal :: !TxComplete -> Message
- Lightning.Protocol.BOLT2.Messages: MsgTxInitRbf :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgTxInitRbfVal :: !TxInitRbf -> Message
- Lightning.Protocol.BOLT2.Messages: MsgTxRemoveInput :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgTxRemoveInputVal :: !TxRemoveInput -> Message
- Lightning.Protocol.BOLT2.Messages: MsgTxRemoveOutput :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgTxRemoveOutputVal :: !TxRemoveOutput -> Message
- Lightning.Protocol.BOLT2.Messages: MsgTxSignatures :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgTxSignaturesVal :: !TxSignatures -> Message
- Lightning.Protocol.BOLT2.Messages: MsgUpdateAddHtlc :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgUpdateAddHtlcVal :: !UpdateAddHtlc -> Message
- Lightning.Protocol.BOLT2.Messages: MsgUpdateFailHtlc :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgUpdateFailHtlcVal :: !UpdateFailHtlc -> Message
- Lightning.Protocol.BOLT2.Messages: MsgUpdateFailMalformedHtlc :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgUpdateFailMalformedHtlcVal :: !UpdateFailMalformedHtlc -> Message
- Lightning.Protocol.BOLT2.Messages: MsgUpdateFee :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgUpdateFeeVal :: !UpdateFee -> Message
- Lightning.Protocol.BOLT2.Messages: MsgUpdateFulfillHtlc :: MsgType
- Lightning.Protocol.BOLT2.Messages: MsgUpdateFulfillHtlcVal :: !UpdateFulfillHtlc -> Message
- Lightning.Protocol.BOLT2.Messages: OpenChannel :: !ChainHash -> !ChannelId -> {-# UNPACK #-} !Satoshis -> {-# UNPACK #-} !MilliSatoshis -> {-# UNPACK #-} !Satoshis -> {-# UNPACK #-} !MilliSatoshis -> {-# UNPACK #-} !Satoshis -> {-# UNPACK #-} !MilliSatoshis -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Word16 -> {-# UNPACK #-} !Word16 -> !Point -> !Point -> !Point -> !Point -> !Point -> !Point -> {-# UNPACK #-} !Word8 -> !TlvStream -> OpenChannel
- Lightning.Protocol.BOLT2.Messages: OpenChannel2 :: !ChainHash -> !ChannelId -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Satoshis -> {-# UNPACK #-} !Satoshis -> {-# UNPACK #-} !MilliSatoshis -> {-# UNPACK #-} !MilliSatoshis -> {-# UNPACK #-} !Word16 -> {-# UNPACK #-} !Word16 -> {-# UNPACK #-} !Word32 -> !Point -> !Point -> !Point -> !Point -> !Point -> !Point -> !Point -> {-# UNPACK #-} !Word8 -> !TlvStream -> OpenChannel2
- Lightning.Protocol.BOLT2.Messages: RevokeAndAck :: !ChannelId -> !Secret -> !Point -> RevokeAndAck
- Lightning.Protocol.BOLT2.Messages: Shutdown :: !ChannelId -> !ScriptPubKey -> Shutdown
- Lightning.Protocol.BOLT2.Messages: Stfu :: !ChannelId -> {-# UNPACK #-} !Word8 -> Stfu
- Lightning.Protocol.BOLT2.Messages: TxAbort :: !ChannelId -> !ByteString -> TxAbort
- Lightning.Protocol.BOLT2.Messages: TxAckRbf :: !ChannelId -> !TlvStream -> TxAckRbf
- Lightning.Protocol.BOLT2.Messages: TxAddInput :: !ChannelId -> {-# UNPACK #-} !Word64 -> !ByteString -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Word32 -> TxAddInput
- Lightning.Protocol.BOLT2.Messages: TxAddOutput :: !ChannelId -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Satoshis -> !ScriptPubKey -> TxAddOutput
- Lightning.Protocol.BOLT2.Messages: TxComplete :: !ChannelId -> TxComplete
- Lightning.Protocol.BOLT2.Messages: TxInitRbf :: !ChannelId -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Word32 -> !TlvStream -> TxInitRbf
- Lightning.Protocol.BOLT2.Messages: TxRemoveInput :: !ChannelId -> {-# UNPACK #-} !Word64 -> TxRemoveInput
- Lightning.Protocol.BOLT2.Messages: TxRemoveOutput :: !ChannelId -> {-# UNPACK #-} !Word64 -> TxRemoveOutput
- Lightning.Protocol.BOLT2.Messages: TxSignatures :: !ChannelId -> !TxId -> ![Witness] -> TxSignatures
- Lightning.Protocol.BOLT2.Messages: UpdateAddHtlc :: !ChannelId -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !MilliSatoshis -> !PaymentHash -> {-# UNPACK #-} !Word32 -> !OnionPacket -> !TlvStream -> UpdateAddHtlc
- Lightning.Protocol.BOLT2.Messages: UpdateFailHtlc :: !ChannelId -> {-# UNPACK #-} !Word64 -> !ByteString -> !TlvStream -> UpdateFailHtlc
- Lightning.Protocol.BOLT2.Messages: UpdateFailMalformedHtlc :: !ChannelId -> {-# UNPACK #-} !Word64 -> !PaymentHash -> {-# UNPACK #-} !Word16 -> UpdateFailMalformedHtlc
- Lightning.Protocol.BOLT2.Messages: UpdateFee :: !ChannelId -> {-# UNPACK #-} !Word32 -> UpdateFee
- Lightning.Protocol.BOLT2.Messages: UpdateFulfillHtlc :: !ChannelId -> {-# UNPACK #-} !Word64 -> !PaymentPreimage -> !TlvStream -> UpdateFulfillHtlc
- Lightning.Protocol.BOLT2.Messages: Witness :: !ByteString -> Witness
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2DelayedPaymentBase] :: AcceptChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2DustLimitSatoshis] :: AcceptChannel2 -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2FirstPerCommitPoint] :: AcceptChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2FundingPubkey] :: AcceptChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2FundingSatoshis] :: AcceptChannel2 -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2HtlcBasepoint] :: AcceptChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2HtlcMinimumMsat] :: AcceptChannel2 -> {-# UNPACK #-} !MilliSatoshis
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2MaxAcceptedHtlcs] :: AcceptChannel2 -> {-# UNPACK #-} !Word16
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2MaxHtlcValueInFlight] :: AcceptChannel2 -> {-# UNPACK #-} !MilliSatoshis
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2MinimumDepth] :: AcceptChannel2 -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2PaymentBasepoint] :: AcceptChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2RevocationBasepoint] :: AcceptChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2SecondPerCommitPoint] :: AcceptChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2TempChannelId] :: AcceptChannel2 -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2Tlvs] :: AcceptChannel2 -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [acceptChannel2ToSelfDelay] :: AcceptChannel2 -> {-# UNPACK #-} !Word16
- Lightning.Protocol.BOLT2.Messages: [acceptChannelChannelReserveSat] :: AcceptChannel -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [acceptChannelDelayedPaymentBase] :: AcceptChannel -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannelDustLimitSatoshis] :: AcceptChannel -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [acceptChannelFirstPerCommitPoint] :: AcceptChannel -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannelFundingPubkey] :: AcceptChannel -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannelHtlcBasepoint] :: AcceptChannel -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannelHtlcMinimumMsat] :: AcceptChannel -> {-# UNPACK #-} !MilliSatoshis
- Lightning.Protocol.BOLT2.Messages: [acceptChannelMaxAcceptedHtlcs] :: AcceptChannel -> {-# UNPACK #-} !Word16
- Lightning.Protocol.BOLT2.Messages: [acceptChannelMaxHtlcValueInFlight] :: AcceptChannel -> {-# UNPACK #-} !MilliSatoshis
- Lightning.Protocol.BOLT2.Messages: [acceptChannelMinimumDepth] :: AcceptChannel -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [acceptChannelPaymentBasepoint] :: AcceptChannel -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannelRevocationBasepoint] :: AcceptChannel -> !Point
- Lightning.Protocol.BOLT2.Messages: [acceptChannelTempChannelId] :: AcceptChannel -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [acceptChannelTlvs] :: AcceptChannel -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [acceptChannelToSelfDelay] :: AcceptChannel -> {-# UNPACK #-} !Word16
- Lightning.Protocol.BOLT2.Messages: [channelReadyChannelId] :: ChannelReady -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [channelReadySecondPerCommitPoint] :: ChannelReady -> !Point
- Lightning.Protocol.BOLT2.Messages: [channelReadyTlvs] :: ChannelReady -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [channelReestablishChannelId] :: ChannelReestablish -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [channelReestablishMyCurrentCommitPoint] :: ChannelReestablish -> !Point
- Lightning.Protocol.BOLT2.Messages: [channelReestablishNextCommitNum] :: ChannelReestablish -> {-# UNPACK #-} !Word64
- Lightning.Protocol.BOLT2.Messages: [channelReestablishNextRevocationNum] :: ChannelReestablish -> {-# UNPACK #-} !Word64
- Lightning.Protocol.BOLT2.Messages: [channelReestablishTlvs] :: ChannelReestablish -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [channelReestablishYourLastCommitSecret] :: ChannelReestablish -> !Secret
- Lightning.Protocol.BOLT2.Messages: [closingCompleteChannelId] :: ClosingComplete -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [closingCompleteCloseeScript] :: ClosingComplete -> !ScriptPubKey
- Lightning.Protocol.BOLT2.Messages: [closingCompleteCloserScript] :: ClosingComplete -> !ScriptPubKey
- Lightning.Protocol.BOLT2.Messages: [closingCompleteFeeSatoshis] :: ClosingComplete -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [closingCompleteLocktime] :: ClosingComplete -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [closingCompleteTlvs] :: ClosingComplete -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [closingSigChannelId] :: ClosingSig -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [closingSigCloseeScript] :: ClosingSig -> !ScriptPubKey
- Lightning.Protocol.BOLT2.Messages: [closingSigCloserScript] :: ClosingSig -> !ScriptPubKey
- Lightning.Protocol.BOLT2.Messages: [closingSigFeeSatoshis] :: ClosingSig -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [closingSigLocktime] :: ClosingSig -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [closingSigTlvs] :: ClosingSig -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [closingSignedChannelId] :: ClosingSigned -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [closingSignedFeeSatoshis] :: ClosingSigned -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [closingSignedSignature] :: ClosingSigned -> !Signature
- Lightning.Protocol.BOLT2.Messages: [closingSignedTlvs] :: ClosingSigned -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [commitmentSignedChannelId] :: CommitmentSigned -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [commitmentSignedHtlcSignatures] :: CommitmentSigned -> ![Signature]
- Lightning.Protocol.BOLT2.Messages: [commitmentSignedSignature] :: CommitmentSigned -> !Signature
- Lightning.Protocol.BOLT2.Messages: [fundingCreatedFundingOutIdx] :: FundingCreated -> {-# UNPACK #-} !Word16
- Lightning.Protocol.BOLT2.Messages: [fundingCreatedFundingTxid] :: FundingCreated -> !TxId
- Lightning.Protocol.BOLT2.Messages: [fundingCreatedSignature] :: FundingCreated -> !Signature
- Lightning.Protocol.BOLT2.Messages: [fundingCreatedTempChannelId] :: FundingCreated -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [fundingSignedChannelId] :: FundingSigned -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [fundingSignedSignature] :: FundingSigned -> !Signature
- Lightning.Protocol.BOLT2.Messages: [openChannel2ChainHash] :: OpenChannel2 -> !ChainHash
- Lightning.Protocol.BOLT2.Messages: [openChannel2ChannelFlags] :: OpenChannel2 -> {-# UNPACK #-} !Word8
- Lightning.Protocol.BOLT2.Messages: [openChannel2CommitFeeratePerkw] :: OpenChannel2 -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [openChannel2DelayedPaymentBase] :: OpenChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannel2DustLimitSatoshis] :: OpenChannel2 -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [openChannel2FirstPerCommitPoint] :: OpenChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannel2FundingFeeratePerkw] :: OpenChannel2 -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [openChannel2FundingPubkey] :: OpenChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannel2FundingSatoshis] :: OpenChannel2 -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [openChannel2HtlcBasepoint] :: OpenChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannel2HtlcMinimumMsat] :: OpenChannel2 -> {-# UNPACK #-} !MilliSatoshis
- Lightning.Protocol.BOLT2.Messages: [openChannel2Locktime] :: OpenChannel2 -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [openChannel2MaxAcceptedHtlcs] :: OpenChannel2 -> {-# UNPACK #-} !Word16
- Lightning.Protocol.BOLT2.Messages: [openChannel2MaxHtlcValueInFlight] :: OpenChannel2 -> {-# UNPACK #-} !MilliSatoshis
- Lightning.Protocol.BOLT2.Messages: [openChannel2PaymentBasepoint] :: OpenChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannel2RevocationBasepoint] :: OpenChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannel2SecondPerCommitPoint] :: OpenChannel2 -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannel2TempChannelId] :: OpenChannel2 -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [openChannel2Tlvs] :: OpenChannel2 -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [openChannel2ToSelfDelay] :: OpenChannel2 -> {-# UNPACK #-} !Word16
- Lightning.Protocol.BOLT2.Messages: [openChannelChainHash] :: OpenChannel -> !ChainHash
- Lightning.Protocol.BOLT2.Messages: [openChannelChannelFlags] :: OpenChannel -> {-# UNPACK #-} !Word8
- Lightning.Protocol.BOLT2.Messages: [openChannelChannelReserveSat] :: OpenChannel -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [openChannelDelayedPaymentBase] :: OpenChannel -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannelDustLimitSatoshis] :: OpenChannel -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [openChannelFeeratePerKw] :: OpenChannel -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [openChannelFirstPerCommitPoint] :: OpenChannel -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannelFundingPubkey] :: OpenChannel -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannelFundingSatoshis] :: OpenChannel -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [openChannelHtlcBasepoint] :: OpenChannel -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannelHtlcMinimumMsat] :: OpenChannel -> {-# UNPACK #-} !MilliSatoshis
- Lightning.Protocol.BOLT2.Messages: [openChannelMaxAcceptedHtlcs] :: OpenChannel -> {-# UNPACK #-} !Word16
- Lightning.Protocol.BOLT2.Messages: [openChannelMaxHtlcValueInFlight] :: OpenChannel -> {-# UNPACK #-} !MilliSatoshis
- Lightning.Protocol.BOLT2.Messages: [openChannelPaymentBasepoint] :: OpenChannel -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannelPushMsat] :: OpenChannel -> {-# UNPACK #-} !MilliSatoshis
- Lightning.Protocol.BOLT2.Messages: [openChannelRevocationBasepoint] :: OpenChannel -> !Point
- Lightning.Protocol.BOLT2.Messages: [openChannelTempChannelId] :: OpenChannel -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [openChannelTlvs] :: OpenChannel -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [openChannelToSelfDelay] :: OpenChannel -> {-# UNPACK #-} !Word16
- Lightning.Protocol.BOLT2.Messages: [revokeAndAckChannelId] :: RevokeAndAck -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [revokeAndAckNextPerCommitPoint] :: RevokeAndAck -> !Point
- Lightning.Protocol.BOLT2.Messages: [revokeAndAckPerCommitmentSecret] :: RevokeAndAck -> !Secret
- Lightning.Protocol.BOLT2.Messages: [shutdownChannelId] :: Shutdown -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [shutdownScriptPubkey] :: Shutdown -> !ScriptPubKey
- Lightning.Protocol.BOLT2.Messages: [stfuChannelId] :: Stfu -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [stfuInitiator] :: Stfu -> {-# UNPACK #-} !Word8
- Lightning.Protocol.BOLT2.Messages: [txAbortChannelId] :: TxAbort -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [txAbortData] :: TxAbort -> !ByteString
- Lightning.Protocol.BOLT2.Messages: [txAckRbfChannelId] :: TxAckRbf -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [txAckRbfTlvs] :: TxAckRbf -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [txAddInputChannelId] :: TxAddInput -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [txAddInputPrevTx] :: TxAddInput -> !ByteString
- Lightning.Protocol.BOLT2.Messages: [txAddInputPrevVout] :: TxAddInput -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [txAddInputSequence] :: TxAddInput -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [txAddInputSerialId] :: TxAddInput -> {-# UNPACK #-} !Word64
- Lightning.Protocol.BOLT2.Messages: [txAddOutputChannelId] :: TxAddOutput -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [txAddOutputSats] :: TxAddOutput -> {-# UNPACK #-} !Satoshis
- Lightning.Protocol.BOLT2.Messages: [txAddOutputScript] :: TxAddOutput -> !ScriptPubKey
- Lightning.Protocol.BOLT2.Messages: [txAddOutputSerialId] :: TxAddOutput -> {-# UNPACK #-} !Word64
- Lightning.Protocol.BOLT2.Messages: [txCompleteChannelId] :: TxComplete -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [txInitRbfChannelId] :: TxInitRbf -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [txInitRbfFeerate] :: TxInitRbf -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [txInitRbfLocktime] :: TxInitRbf -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [txInitRbfTlvs] :: TxInitRbf -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [txRemoveInputChannelId] :: TxRemoveInput -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [txRemoveInputSerialId] :: TxRemoveInput -> {-# UNPACK #-} !Word64
- Lightning.Protocol.BOLT2.Messages: [txRemoveOutputChannelId] :: TxRemoveOutput -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [txRemoveOutputSerialId] :: TxRemoveOutput -> {-# UNPACK #-} !Word64
- Lightning.Protocol.BOLT2.Messages: [txSignaturesChannelId] :: TxSignatures -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [txSignaturesTxid] :: TxSignatures -> !TxId
- Lightning.Protocol.BOLT2.Messages: [txSignaturesWitnesses] :: TxSignatures -> ![Witness]
- Lightning.Protocol.BOLT2.Messages: [updateAddHtlcAmountMsat] :: UpdateAddHtlc -> {-# UNPACK #-} !MilliSatoshis
- Lightning.Protocol.BOLT2.Messages: [updateAddHtlcChannelId] :: UpdateAddHtlc -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [updateAddHtlcCltvExpiry] :: UpdateAddHtlc -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [updateAddHtlcId] :: UpdateAddHtlc -> {-# UNPACK #-} !Word64
- Lightning.Protocol.BOLT2.Messages: [updateAddHtlcOnionPacket] :: UpdateAddHtlc -> !OnionPacket
- Lightning.Protocol.BOLT2.Messages: [updateAddHtlcPaymentHash] :: UpdateAddHtlc -> !PaymentHash
- Lightning.Protocol.BOLT2.Messages: [updateAddHtlcTlvs] :: UpdateAddHtlc -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [updateFailHtlcChannelId] :: UpdateFailHtlc -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [updateFailHtlcId] :: UpdateFailHtlc -> {-# UNPACK #-} !Word64
- Lightning.Protocol.BOLT2.Messages: [updateFailHtlcReason] :: UpdateFailHtlc -> !ByteString
- Lightning.Protocol.BOLT2.Messages: [updateFailHtlcTlvs] :: UpdateFailHtlc -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [updateFailMalformedHtlcChannelId] :: UpdateFailMalformedHtlc -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [updateFailMalformedHtlcFailureCode] :: UpdateFailMalformedHtlc -> {-# UNPACK #-} !Word16
- Lightning.Protocol.BOLT2.Messages: [updateFailMalformedHtlcId] :: UpdateFailMalformedHtlc -> {-# UNPACK #-} !Word64
- Lightning.Protocol.BOLT2.Messages: [updateFailMalformedHtlcSha256Onion] :: UpdateFailMalformedHtlc -> !PaymentHash
- Lightning.Protocol.BOLT2.Messages: [updateFeeChannelId] :: UpdateFee -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [updateFeeFeeratePerKw] :: UpdateFee -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Messages: [updateFulfillHtlcChannelId] :: UpdateFulfillHtlc -> !ChannelId
- Lightning.Protocol.BOLT2.Messages: [updateFulfillHtlcId] :: UpdateFulfillHtlc -> {-# UNPACK #-} !Word64
- Lightning.Protocol.BOLT2.Messages: [updateFulfillHtlcPaymentPreimage] :: UpdateFulfillHtlc -> !PaymentPreimage
- Lightning.Protocol.BOLT2.Messages: [updateFulfillHtlcTlvs] :: UpdateFulfillHtlc -> !TlvStream
- Lightning.Protocol.BOLT2.Messages: [witnessData] :: Witness -> !ByteString
- Lightning.Protocol.BOLT2.Messages: data AcceptChannel
- Lightning.Protocol.BOLT2.Messages: data AcceptChannel2
- Lightning.Protocol.BOLT2.Messages: data ChannelReady
- Lightning.Protocol.BOLT2.Messages: data ChannelReestablish
- Lightning.Protocol.BOLT2.Messages: data ClosingComplete
- Lightning.Protocol.BOLT2.Messages: data ClosingSig
- Lightning.Protocol.BOLT2.Messages: data ClosingSigned
- Lightning.Protocol.BOLT2.Messages: data CommitmentSigned
- Lightning.Protocol.BOLT2.Messages: data FundingCreated
- Lightning.Protocol.BOLT2.Messages: data FundingSigned
- Lightning.Protocol.BOLT2.Messages: data Message
- Lightning.Protocol.BOLT2.Messages: data MsgType
- Lightning.Protocol.BOLT2.Messages: data OpenChannel
- Lightning.Protocol.BOLT2.Messages: data OpenChannel2
- Lightning.Protocol.BOLT2.Messages: data RevokeAndAck
- Lightning.Protocol.BOLT2.Messages: data Shutdown
- Lightning.Protocol.BOLT2.Messages: data Stfu
- Lightning.Protocol.BOLT2.Messages: data TxAbort
- Lightning.Protocol.BOLT2.Messages: data TxAckRbf
- Lightning.Protocol.BOLT2.Messages: data TxAddInput
- Lightning.Protocol.BOLT2.Messages: data TxAddOutput
- Lightning.Protocol.BOLT2.Messages: data TxComplete
- Lightning.Protocol.BOLT2.Messages: data TxInitRbf
- Lightning.Protocol.BOLT2.Messages: data TxRemoveInput
- Lightning.Protocol.BOLT2.Messages: data TxRemoveOutput
- Lightning.Protocol.BOLT2.Messages: data TxSignatures
- Lightning.Protocol.BOLT2.Messages: data UpdateAddHtlc
- Lightning.Protocol.BOLT2.Messages: data UpdateFailHtlc
- Lightning.Protocol.BOLT2.Messages: data UpdateFailMalformedHtlc
- Lightning.Protocol.BOLT2.Messages: data UpdateFee
- Lightning.Protocol.BOLT2.Messages: data UpdateFulfillHtlc
- Lightning.Protocol.BOLT2.Messages: data Witness
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.AcceptChannel
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.AcceptChannel2
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.ChannelReady
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.ChannelReestablish
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.ClosingComplete
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.ClosingSig
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.ClosingSigned
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.CommitmentSigned
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.FundingCreated
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.FundingSigned
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.Message
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.MsgType
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.OpenChannel
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.OpenChannel2
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.RevokeAndAck
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.Shutdown
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.Stfu
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.TxAbort
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.TxAckRbf
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.TxAddInput
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.TxAddOutput
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.TxComplete
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.TxInitRbf
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.TxRemoveInput
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.TxRemoveOutput
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.TxSignatures
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.UpdateAddHtlc
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.UpdateFailHtlc
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.UpdateFailMalformedHtlc
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.UpdateFee
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.UpdateFulfillHtlc
- Lightning.Protocol.BOLT2.Messages: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Messages.Witness
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.AcceptChannel
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.AcceptChannel2
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.ChannelReady
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.ChannelReestablish
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.ClosingComplete
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.ClosingSig
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.ClosingSigned
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.CommitmentSigned
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.FundingCreated
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.FundingSigned
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.Message
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.MsgType
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.OpenChannel
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.OpenChannel2
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.RevokeAndAck
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.Shutdown
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.Stfu
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.TxAbort
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.TxAckRbf
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.TxAddInput
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.TxAddOutput
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.TxComplete
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.TxInitRbf
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.TxRemoveInput
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.TxRemoveOutput
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.TxSignatures
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.UpdateAddHtlc
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.UpdateFailHtlc
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.UpdateFailMalformedHtlc
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.UpdateFee
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.UpdateFulfillHtlc
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Messages.Witness
- Lightning.Protocol.BOLT2.Messages: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Messages.MsgType
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.AcceptChannel
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.AcceptChannel2
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.ChannelReady
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.ChannelReestablish
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.ClosingComplete
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.ClosingSig
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.ClosingSigned
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.CommitmentSigned
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.FundingCreated
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.FundingSigned
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.Message
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.MsgType
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.OpenChannel
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.OpenChannel2
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.RevokeAndAck
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.Shutdown
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.Stfu
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.TxAbort
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.TxAckRbf
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.TxAddInput
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.TxAddOutput
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.TxComplete
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.TxInitRbf
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.TxRemoveInput
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.TxRemoveOutput
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.TxSignatures
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.UpdateAddHtlc
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.UpdateFailHtlc
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.UpdateFailMalformedHtlc
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.UpdateFee
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.UpdateFulfillHtlc
- Lightning.Protocol.BOLT2.Messages: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Messages.Witness
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.AcceptChannel
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.AcceptChannel2
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.ChannelReady
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.ChannelReestablish
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.ClosingComplete
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.ClosingSig
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.ClosingSigned
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.CommitmentSigned
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.FundingCreated
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.FundingSigned
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.Message
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.MsgType
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.OpenChannel
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.OpenChannel2
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.RevokeAndAck
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.Shutdown
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.Stfu
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.TxAbort
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.TxAckRbf
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.TxAddInput
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.TxAddOutput
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.TxComplete
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.TxInitRbf
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.TxRemoveInput
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.TxRemoveOutput
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.TxSignatures
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.UpdateAddHtlc
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.UpdateFailHtlc
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.UpdateFailMalformedHtlc
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.UpdateFee
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.UpdateFulfillHtlc
- Lightning.Protocol.BOLT2.Messages: instance GHC.Show.Show Lightning.Protocol.BOLT2.Messages.Witness
- Lightning.Protocol.BOLT2.Messages: msgTypeWord :: MsgType -> Word16
- Lightning.Protocol.BOLT2.Types: MilliSatoshis :: Word64 -> MilliSatoshis
- Lightning.Protocol.BOLT2.Types: Outpoint :: {-# UNPACK #-} !TxId -> {-# UNPACK #-} !Word32 -> Outpoint
- Lightning.Protocol.BOLT2.Types: Satoshis :: Word64 -> Satoshis
- Lightning.Protocol.BOLT2.Types: ShortChannelId :: {-# UNPACK #-} !Word64 -> ShortChannelId
- Lightning.Protocol.BOLT2.Types: [outpointTxId] :: Outpoint -> {-# UNPACK #-} !TxId
- Lightning.Protocol.BOLT2.Types: [outpointVout] :: Outpoint -> {-# UNPACK #-} !Word32
- Lightning.Protocol.BOLT2.Types: [scidBytes] :: ShortChannelId -> {-# UNPACK #-} !Word64
- Lightning.Protocol.BOLT2.Types: [unMilliSatoshis] :: MilliSatoshis -> Word64
- Lightning.Protocol.BOLT2.Types: [unSatoshis] :: Satoshis -> Word64
- Lightning.Protocol.BOLT2.Types: chainHash :: ByteString -> Maybe ChainHash
- Lightning.Protocol.BOLT2.Types: chainHashLen :: Int
- Lightning.Protocol.BOLT2.Types: channelId :: ByteString -> Maybe ChannelId
- Lightning.Protocol.BOLT2.Types: channelIdLen :: Int
- Lightning.Protocol.BOLT2.Types: data ChainHash
- Lightning.Protocol.BOLT2.Types: data ChannelId
- Lightning.Protocol.BOLT2.Types: data FeatureBits
- Lightning.Protocol.BOLT2.Types: data OnionPacket
- Lightning.Protocol.BOLT2.Types: data Outpoint
- Lightning.Protocol.BOLT2.Types: data PaymentHash
- Lightning.Protocol.BOLT2.Types: data PaymentPreimage
- Lightning.Protocol.BOLT2.Types: data Point
- Lightning.Protocol.BOLT2.Types: data ScriptPubKey
- Lightning.Protocol.BOLT2.Types: data Secret
- Lightning.Protocol.BOLT2.Types: data ShortChannelId
- Lightning.Protocol.BOLT2.Types: data Signature
- Lightning.Protocol.BOLT2.Types: data TxId
- Lightning.Protocol.BOLT2.Types: featureBits :: ByteString -> FeatureBits
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.ChainHash
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.ChannelId
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.FeatureBits
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.MilliSatoshis
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.OnionPacket
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.Outpoint
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.PaymentHash
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.PaymentPreimage
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.Point
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.Satoshis
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.ScriptPubKey
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.Secret
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.ShortChannelId
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.Signature
- Lightning.Protocol.BOLT2.Types: instance Control.DeepSeq.NFData Lightning.Protocol.BOLT2.Types.TxId
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.ChainHash
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.ChannelId
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.FeatureBits
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.MilliSatoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.OnionPacket
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.Outpoint
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.PaymentHash
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.PaymentPreimage
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.Point
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.Satoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.ScriptPubKey
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.Secret
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.ShortChannelId
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.Signature
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Eq Lightning.Protocol.BOLT2.Types.TxId
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.ChainHash
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.ChannelId
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.FeatureBits
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.MilliSatoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.OnionPacket
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.Outpoint
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.PaymentHash
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.PaymentPreimage
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.Point
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.Satoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.ScriptPubKey
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.Secret
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.ShortChannelId
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.Signature
- Lightning.Protocol.BOLT2.Types: instance GHC.Classes.Ord Lightning.Protocol.BOLT2.Types.TxId
- Lightning.Protocol.BOLT2.Types: instance GHC.Enum.Enum Lightning.Protocol.BOLT2.Types.MilliSatoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Enum.Enum Lightning.Protocol.BOLT2.Types.Satoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.ChainHash
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.ChannelId
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.FeatureBits
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.MilliSatoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.OnionPacket
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.Outpoint
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.PaymentHash
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.PaymentPreimage
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.Point
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.Satoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.ScriptPubKey
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.Secret
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.ShortChannelId
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.Signature
- Lightning.Protocol.BOLT2.Types: instance GHC.Generics.Generic Lightning.Protocol.BOLT2.Types.TxId
- Lightning.Protocol.BOLT2.Types: instance GHC.Num.Num Lightning.Protocol.BOLT2.Types.MilliSatoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Num.Num Lightning.Protocol.BOLT2.Types.Satoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Real.Integral Lightning.Protocol.BOLT2.Types.MilliSatoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Real.Integral Lightning.Protocol.BOLT2.Types.Satoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Real.Real Lightning.Protocol.BOLT2.Types.MilliSatoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Real.Real Lightning.Protocol.BOLT2.Types.Satoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.ChainHash
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.ChannelId
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.FeatureBits
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.MilliSatoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.OnionPacket
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.Outpoint
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.PaymentHash
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.PaymentPreimage
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.Point
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.Satoshis
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.ScriptPubKey
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.Secret
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.ShortChannelId
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.Signature
- Lightning.Protocol.BOLT2.Types: instance GHC.Show.Show Lightning.Protocol.BOLT2.Types.TxId
- Lightning.Protocol.BOLT2.Types: msatToSatoshis :: MilliSatoshis -> Satoshis
- Lightning.Protocol.BOLT2.Types: newtype MilliSatoshis
- Lightning.Protocol.BOLT2.Types: newtype Satoshis
- Lightning.Protocol.BOLT2.Types: onionPacket :: ByteString -> Maybe OnionPacket
- Lightning.Protocol.BOLT2.Types: onionPacketLen :: Int
- Lightning.Protocol.BOLT2.Types: paymentHash :: ByteString -> Maybe PaymentHash
- Lightning.Protocol.BOLT2.Types: paymentHashLen :: Int
- Lightning.Protocol.BOLT2.Types: paymentPreimage :: ByteString -> Maybe PaymentPreimage
- Lightning.Protocol.BOLT2.Types: paymentPreimageLen :: Int
- Lightning.Protocol.BOLT2.Types: point :: ByteString -> Maybe Point
- Lightning.Protocol.BOLT2.Types: pointLen :: Int
- Lightning.Protocol.BOLT2.Types: satoshisToMsat :: Satoshis -> MilliSatoshis
- Lightning.Protocol.BOLT2.Types: scidBlockHeight :: ShortChannelId -> Word32
- Lightning.Protocol.BOLT2.Types: scidOutputIndex :: ShortChannelId -> Word16
- Lightning.Protocol.BOLT2.Types: scidTxIndex :: ShortChannelId -> Word32
- Lightning.Protocol.BOLT2.Types: scriptPubKey :: ByteString -> ScriptPubKey
- Lightning.Protocol.BOLT2.Types: secret :: ByteString -> Maybe Secret
- Lightning.Protocol.BOLT2.Types: secretLen :: Int
- Lightning.Protocol.BOLT2.Types: shortChannelId :: Word32 -> Word32 -> Word16 -> Maybe ShortChannelId
- Lightning.Protocol.BOLT2.Types: shortChannelIdLen :: Int
- Lightning.Protocol.BOLT2.Types: signature :: ByteString -> Maybe Signature
- Lightning.Protocol.BOLT2.Types: signatureLen :: Int
- Lightning.Protocol.BOLT2.Types: txId :: ByteString -> Maybe TxId
- Lightning.Protocol.BOLT2.Types: txIdLen :: Int
- Lightning.Protocol.BOLT2.Types: unChainHash :: ChainHash -> ByteString
- Lightning.Protocol.BOLT2.Types: unChannelId :: ChannelId -> ByteString
- Lightning.Protocol.BOLT2.Types: unFeatureBits :: FeatureBits -> ByteString
- Lightning.Protocol.BOLT2.Types: unOnionPacket :: OnionPacket -> ByteString
- Lightning.Protocol.BOLT2.Types: unPaymentHash :: PaymentHash -> ByteString
- Lightning.Protocol.BOLT2.Types: unPaymentPreimage :: PaymentPreimage -> ByteString
- Lightning.Protocol.BOLT2.Types: unPoint :: Point -> ByteString
- Lightning.Protocol.BOLT2.Types: unScriptPubKey :: ScriptPubKey -> ByteString
- Lightning.Protocol.BOLT2.Types: unSecret :: Secret -> ByteString
- Lightning.Protocol.BOLT2.Types: unSignature :: Signature -> ByteString
- Lightning.Protocol.BOLT2.Types: unTxId :: TxId -> ByteString
+ Lightning.Protocol.BOLT2: AcceptChannel :: !ChannelId -> {-# UNPACK #-} !Satoshi -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Satoshi -> {-# UNPACK #-} !MilliSatoshi -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Word16 -> {-# UNPACK #-} !Word16 -> !Point -> !Point -> !Point -> !Point -> !Point -> !Point -> !Maybe ScriptPubKey -> !Maybe FeatureVector -> !TlvStream -> AcceptChannel
+ Lightning.Protocol.BOLT2: AcceptChannel2 :: !ChannelId -> {-# UNPACK #-} !Satoshi -> {-# UNPACK #-} !Satoshi -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !MilliSatoshi -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Word16 -> {-# UNPACK #-} !Word16 -> !Point -> !Point -> !Point -> !Point -> !Point -> !Point -> !Point -> !Maybe ScriptPubKey -> !Maybe FeatureVector -> !Bool -> !TlvStream -> AcceptChannel2
+ Lightning.Protocol.BOLT2: ChannelReady :: !ChannelId -> !Point -> !Maybe ShortChannelId -> !TlvStream -> ChannelReady
+ Lightning.Protocol.BOLT2: ChannelReestablish :: !ChannelId -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> !PerCommitmentSecret -> !Point -> !Maybe NextFunding -> !TlvStream -> ChannelReestablish
+ Lightning.Protocol.BOLT2: ClosingComplete :: !ChannelId -> !ScriptPubKey -> !ScriptPubKey -> {-# UNPACK #-} !Satoshi -> {-# UNPACK #-} !Word32 -> !Maybe Signature -> !Maybe Signature -> !Maybe Signature -> !TlvStream -> ClosingComplete
+ Lightning.Protocol.BOLT2: ClosingSig :: !ChannelId -> !ScriptPubKey -> !ScriptPubKey -> {-# UNPACK #-} !Satoshi -> {-# UNPACK #-} !Word32 -> !Maybe Signature -> !Maybe Signature -> !Maybe Signature -> !TlvStream -> ClosingSig
+ Lightning.Protocol.BOLT2: ClosingSigned :: !ChannelId -> {-# UNPACK #-} !Satoshi -> !Signature -> !Maybe FeeRange -> !TlvStream -> ClosingSigned
+ Lightning.Protocol.BOLT2: CommitmentSigned :: !ChannelId -> !Signature -> ![Signature] -> !Maybe TxId -> !TlvStream -> CommitmentSigned
+ Lightning.Protocol.BOLT2: DecodeInsufficientBytes :: DecodeError
+ Lightning.Protocol.BOLT2: DecodeInvalidAmount :: DecodeError
+ Lightning.Protocol.BOLT2: DecodeInvalidInitiator :: DecodeError
+ Lightning.Protocol.BOLT2: DecodeInvalidPoint :: DecodeError
+ Lightning.Protocol.BOLT2: DecodeInvalidTlvValue :: !Word64 -> DecodeError
+ Lightning.Protocol.BOLT2: DecodeTlvError :: !TlvError -> DecodeError
+ Lightning.Protocol.BOLT2: DecodeUnknownEvenType :: !Word16 -> DecodeError
+ Lightning.Protocol.BOLT2: DecodeUnknownOddType :: !Word16 -> DecodeError
+ Lightning.Protocol.BOLT2: EncodeInvalidTlvs :: EncodeError
+ Lightning.Protocol.BOLT2: EncodeLengthOverflow :: EncodeError
+ Lightning.Protocol.BOLT2: EncodeMessageTooLarge :: EncodeError
+ Lightning.Protocol.BOLT2: FeeRange :: {-# UNPACK #-} !Satoshi -> {-# UNPACK #-} !Satoshi -> FeeRange
+ Lightning.Protocol.BOLT2: FundingCreated :: !ChannelId -> !TxId -> {-# UNPACK #-} !Word16 -> !Signature -> !TlvStream -> FundingCreated
+ Lightning.Protocol.BOLT2: FundingSigned :: !ChannelId -> !Signature -> !TlvStream -> FundingSigned
+ Lightning.Protocol.BOLT2: HtlcId :: Word64 -> HtlcId
+ Lightning.Protocol.BOLT2: MsgAcceptChannel :: !AcceptChannel -> Message
+ Lightning.Protocol.BOLT2: MsgAcceptChannel2 :: !AcceptChannel2 -> Message
+ Lightning.Protocol.BOLT2: MsgChannelReady :: !ChannelReady -> Message
+ Lightning.Protocol.BOLT2: MsgChannelReestablish :: !ChannelReestablish -> Message
+ Lightning.Protocol.BOLT2: MsgClosingComplete :: !ClosingComplete -> Message
+ Lightning.Protocol.BOLT2: MsgClosingSig :: !ClosingSig -> Message
+ Lightning.Protocol.BOLT2: MsgClosingSigned :: !ClosingSigned -> Message
+ Lightning.Protocol.BOLT2: MsgCommitmentSigned :: !CommitmentSigned -> Message
+ Lightning.Protocol.BOLT2: MsgFundingCreated :: !FundingCreated -> Message
+ Lightning.Protocol.BOLT2: MsgFundingSigned :: !FundingSigned -> Message
+ Lightning.Protocol.BOLT2: MsgOpenChannel :: !OpenChannel -> Message
+ Lightning.Protocol.BOLT2: MsgOpenChannel2 :: !OpenChannel2 -> Message
+ Lightning.Protocol.BOLT2: MsgRevokeAndAck :: !RevokeAndAck -> Message
+ Lightning.Protocol.BOLT2: MsgShutdown :: !Shutdown -> Message
+ Lightning.Protocol.BOLT2: MsgStfu :: !Stfu -> Message
+ Lightning.Protocol.BOLT2: MsgTxAbort :: !TxAbort -> Message
+ Lightning.Protocol.BOLT2: MsgTxAckRbf :: !TxAckRbf -> Message
+ Lightning.Protocol.BOLT2: MsgTxAddInput :: !TxAddInput -> Message
+ Lightning.Protocol.BOLT2: MsgTxAddOutput :: !TxAddOutput -> Message
+ Lightning.Protocol.BOLT2: MsgTxComplete :: !TxComplete -> Message
+ Lightning.Protocol.BOLT2: MsgTxInitRbf :: !TxInitRbf -> Message
+ Lightning.Protocol.BOLT2: MsgTxRemoveInput :: !TxRemoveInput -> Message
+ Lightning.Protocol.BOLT2: MsgTxRemoveOutput :: !TxRemoveOutput -> Message
+ Lightning.Protocol.BOLT2: MsgTxSignatures :: !TxSignatures -> Message
+ Lightning.Protocol.BOLT2: MsgUpdateAddHtlc :: !UpdateAddHtlc -> Message
+ Lightning.Protocol.BOLT2: MsgUpdateFailHtlc :: !UpdateFailHtlc -> Message
+ Lightning.Protocol.BOLT2: MsgUpdateFailMalformedHtlc :: !UpdateFailMalformedHtlc -> Message
+ Lightning.Protocol.BOLT2: MsgUpdateFee :: !UpdateFee -> Message
+ Lightning.Protocol.BOLT2: MsgUpdateFulfillHtlc :: !UpdateFulfillHtlc -> Message
+ Lightning.Protocol.BOLT2: NextFunding :: !TxId -> {-# UNPACK #-} !Word8 -> NextFunding
+ Lightning.Protocol.BOLT2: OpenChannel :: !ChainHash -> !ChannelId -> {-# UNPACK #-} !Satoshi -> {-# UNPACK #-} !MilliSatoshi -> {-# UNPACK #-} !Satoshi -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Satoshi -> {-# UNPACK #-} !MilliSatoshi -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Word16 -> {-# UNPACK #-} !Word16 -> !Point -> !Point -> !Point -> !Point -> !Point -> !Point -> {-# UNPACK #-} !Word8 -> !Maybe ScriptPubKey -> !Maybe FeatureVector -> !TlvStream -> OpenChannel
+ Lightning.Protocol.BOLT2: OpenChannel2 :: !ChainHash -> !ChannelId -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Satoshi -> {-# UNPACK #-} !Satoshi -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !MilliSatoshi -> {-# UNPACK #-} !Word16 -> {-# UNPACK #-} !Word16 -> {-# UNPACK #-} !Word32 -> !Point -> !Point -> !Point -> !Point -> !Point -> !Point -> !Point -> {-# UNPACK #-} !Word8 -> !Maybe ScriptPubKey -> !Maybe FeatureVector -> !Bool -> !TlvStream -> OpenChannel2
+ Lightning.Protocol.BOLT2: RevokeAndAck :: !ChannelId -> !PerCommitmentSecret -> !Point -> !TlvStream -> RevokeAndAck
+ Lightning.Protocol.BOLT2: SerialId :: Word64 -> SerialId
+ Lightning.Protocol.BOLT2: Shutdown :: !ChannelId -> !ScriptPubKey -> !TlvStream -> Shutdown
+ Lightning.Protocol.BOLT2: Stfu :: !ChannelId -> !Bool -> !TlvStream -> Stfu
+ Lightning.Protocol.BOLT2: TxAbort :: !ChannelId -> !ByteString -> !TlvStream -> TxAbort
+ Lightning.Protocol.BOLT2: TxAckRbf :: !ChannelId -> !Maybe Int64 -> !Bool -> !TlvStream -> TxAckRbf
+ Lightning.Protocol.BOLT2: TxAddInput :: !ChannelId -> !SerialId -> !ByteString -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Word32 -> !TlvStream -> TxAddInput
+ Lightning.Protocol.BOLT2: TxAddOutput :: !ChannelId -> !SerialId -> {-# UNPACK #-} !Satoshi -> !ScriptPubKey -> !TlvStream -> TxAddOutput
+ Lightning.Protocol.BOLT2: TxComplete :: !ChannelId -> !TlvStream -> TxComplete
+ Lightning.Protocol.BOLT2: TxInitRbf :: !ChannelId -> {-# UNPACK #-} !Word32 -> {-# UNPACK #-} !Word32 -> !Maybe Int64 -> !Bool -> !TlvStream -> TxInitRbf
+ Lightning.Protocol.BOLT2: TxRemoveInput :: !ChannelId -> !SerialId -> !TlvStream -> TxRemoveInput
+ Lightning.Protocol.BOLT2: TxRemoveOutput :: !ChannelId -> !SerialId -> !TlvStream -> TxRemoveOutput
+ Lightning.Protocol.BOLT2: TxSignatures :: !ChannelId -> !TxId -> ![Witness] -> !TlvStream -> TxSignatures
+ Lightning.Protocol.BOLT2: UpdateAddHtlc :: !ChannelId -> !HtlcId -> {-# UNPACK #-} !MilliSatoshi -> !PaymentHash -> {-# UNPACK #-} !Word32 -> !OnionRoutingPacket -> !Maybe Point -> !TlvStream -> UpdateAddHtlc
+ Lightning.Protocol.BOLT2: UpdateFailHtlc :: !ChannelId -> !HtlcId -> !ByteString -> !Maybe AttributionData -> !TlvStream -> UpdateFailHtlc
+ Lightning.Protocol.BOLT2: UpdateFailMalformedHtlc :: !ChannelId -> !HtlcId -> !OnionHash -> {-# UNPACK #-} !Word16 -> !TlvStream -> UpdateFailMalformedHtlc
+ Lightning.Protocol.BOLT2: UpdateFee :: !ChannelId -> {-# UNPACK #-} !Word32 -> !TlvStream -> UpdateFee
+ Lightning.Protocol.BOLT2: UpdateFulfillHtlc :: !ChannelId -> !HtlcId -> !PaymentPreimage -> !Maybe AttributionData -> !Maybe ByteString -> !TlvStream -> UpdateFulfillHtlc
+ Lightning.Protocol.BOLT2: [accept_channel2_channel_type] :: AcceptChannel2 -> !Maybe FeatureVector
+ Lightning.Protocol.BOLT2: [accept_channel2_delayed_payment_basepoint] :: AcceptChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel2_dust_limit_satoshis] :: AcceptChannel2 -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [accept_channel2_first_per_commitment_point] :: AcceptChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel2_funding_pubkey] :: AcceptChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel2_funding_satoshis] :: AcceptChannel2 -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [accept_channel2_htlc_basepoint] :: AcceptChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel2_htlc_minimum_msat] :: AcceptChannel2 -> {-# UNPACK #-} !MilliSatoshi
+ Lightning.Protocol.BOLT2: [accept_channel2_max_accepted_htlcs] :: AcceptChannel2 -> {-# UNPACK #-} !Word16
+ Lightning.Protocol.BOLT2: [accept_channel2_max_htlc_value_in_flight_msat] :: AcceptChannel2 -> {-# UNPACK #-} !Word64
+ Lightning.Protocol.BOLT2: [accept_channel2_minimum_depth] :: AcceptChannel2 -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [accept_channel2_payment_basepoint] :: AcceptChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel2_require_confirmed_inputs] :: AcceptChannel2 -> !Bool
+ Lightning.Protocol.BOLT2: [accept_channel2_revocation_basepoint] :: AcceptChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel2_second_per_commitment_point] :: AcceptChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel2_temporary_channel_id] :: AcceptChannel2 -> !ChannelId
+ Lightning.Protocol.BOLT2: [accept_channel2_tlvs] :: AcceptChannel2 -> !TlvStream
+ Lightning.Protocol.BOLT2: [accept_channel2_to_self_delay] :: AcceptChannel2 -> {-# UNPACK #-} !Word16
+ Lightning.Protocol.BOLT2: [accept_channel2_upfront_shutdown_script] :: AcceptChannel2 -> !Maybe ScriptPubKey
+ Lightning.Protocol.BOLT2: [accept_channel_channel_reserve_satoshis] :: AcceptChannel -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [accept_channel_channel_type] :: AcceptChannel -> !Maybe FeatureVector
+ Lightning.Protocol.BOLT2: [accept_channel_delayed_payment_basepoint] :: AcceptChannel -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel_dust_limit_satoshis] :: AcceptChannel -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [accept_channel_first_per_commitment_point] :: AcceptChannel -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel_funding_pubkey] :: AcceptChannel -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel_htlc_basepoint] :: AcceptChannel -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel_htlc_minimum_msat] :: AcceptChannel -> {-# UNPACK #-} !MilliSatoshi
+ Lightning.Protocol.BOLT2: [accept_channel_max_accepted_htlcs] :: AcceptChannel -> {-# UNPACK #-} !Word16
+ Lightning.Protocol.BOLT2: [accept_channel_max_htlc_value_in_flight_msat] :: AcceptChannel -> {-# UNPACK #-} !Word64
+ Lightning.Protocol.BOLT2: [accept_channel_minimum_depth] :: AcceptChannel -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [accept_channel_payment_basepoint] :: AcceptChannel -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel_revocation_basepoint] :: AcceptChannel -> !Point
+ Lightning.Protocol.BOLT2: [accept_channel_temporary_channel_id] :: AcceptChannel -> !ChannelId
+ Lightning.Protocol.BOLT2: [accept_channel_tlvs] :: AcceptChannel -> !TlvStream
+ Lightning.Protocol.BOLT2: [accept_channel_to_self_delay] :: AcceptChannel -> {-# UNPACK #-} !Word16
+ Lightning.Protocol.BOLT2: [accept_channel_upfront_shutdown_script] :: AcceptChannel -> !Maybe ScriptPubKey
+ Lightning.Protocol.BOLT2: [channel_ready_alias] :: ChannelReady -> !Maybe ShortChannelId
+ Lightning.Protocol.BOLT2: [channel_ready_channel_id] :: ChannelReady -> !ChannelId
+ Lightning.Protocol.BOLT2: [channel_ready_second_per_commitment_point] :: ChannelReady -> !Point
+ Lightning.Protocol.BOLT2: [channel_ready_tlvs] :: ChannelReady -> !TlvStream
+ Lightning.Protocol.BOLT2: [channel_reestablish_channel_id] :: ChannelReestablish -> !ChannelId
+ Lightning.Protocol.BOLT2: [channel_reestablish_my_current_per_commitment_point] :: ChannelReestablish -> !Point
+ Lightning.Protocol.BOLT2: [channel_reestablish_next_commitment_number] :: ChannelReestablish -> {-# UNPACK #-} !Word64
+ Lightning.Protocol.BOLT2: [channel_reestablish_next_funding] :: ChannelReestablish -> !Maybe NextFunding
+ Lightning.Protocol.BOLT2: [channel_reestablish_next_revocation_number] :: ChannelReestablish -> {-# UNPACK #-} !Word64
+ Lightning.Protocol.BOLT2: [channel_reestablish_tlvs] :: ChannelReestablish -> !TlvStream
+ Lightning.Protocol.BOLT2: [channel_reestablish_your_last_per_commitment_secret] :: ChannelReestablish -> !PerCommitmentSecret
+ Lightning.Protocol.BOLT2: [closing_complete_channel_id] :: ClosingComplete -> !ChannelId
+ Lightning.Protocol.BOLT2: [closing_complete_closee_output_only] :: ClosingComplete -> !Maybe Signature
+ Lightning.Protocol.BOLT2: [closing_complete_closee_scriptpubkey] :: ClosingComplete -> !ScriptPubKey
+ Lightning.Protocol.BOLT2: [closing_complete_closer_and_closee_outputs] :: ClosingComplete -> !Maybe Signature
+ Lightning.Protocol.BOLT2: [closing_complete_closer_output_only] :: ClosingComplete -> !Maybe Signature
+ Lightning.Protocol.BOLT2: [closing_complete_closer_scriptpubkey] :: ClosingComplete -> !ScriptPubKey
+ Lightning.Protocol.BOLT2: [closing_complete_fee_satoshis] :: ClosingComplete -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [closing_complete_locktime] :: ClosingComplete -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [closing_complete_tlvs] :: ClosingComplete -> !TlvStream
+ Lightning.Protocol.BOLT2: [closing_sig_channel_id] :: ClosingSig -> !ChannelId
+ Lightning.Protocol.BOLT2: [closing_sig_closee_output_only] :: ClosingSig -> !Maybe Signature
+ Lightning.Protocol.BOLT2: [closing_sig_closee_scriptpubkey] :: ClosingSig -> !ScriptPubKey
+ Lightning.Protocol.BOLT2: [closing_sig_closer_and_closee_outputs] :: ClosingSig -> !Maybe Signature
+ Lightning.Protocol.BOLT2: [closing_sig_closer_output_only] :: ClosingSig -> !Maybe Signature
+ Lightning.Protocol.BOLT2: [closing_sig_closer_scriptpubkey] :: ClosingSig -> !ScriptPubKey
+ Lightning.Protocol.BOLT2: [closing_sig_fee_satoshis] :: ClosingSig -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [closing_sig_locktime] :: ClosingSig -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [closing_sig_tlvs] :: ClosingSig -> !TlvStream
+ Lightning.Protocol.BOLT2: [closing_signed_channel_id] :: ClosingSigned -> !ChannelId
+ Lightning.Protocol.BOLT2: [closing_signed_fee_range] :: ClosingSigned -> !Maybe FeeRange
+ Lightning.Protocol.BOLT2: [closing_signed_fee_satoshis] :: ClosingSigned -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [closing_signed_signature] :: ClosingSigned -> !Signature
+ Lightning.Protocol.BOLT2: [closing_signed_tlvs] :: ClosingSigned -> !TlvStream
+ Lightning.Protocol.BOLT2: [commitment_signed_channel_id] :: CommitmentSigned -> !ChannelId
+ Lightning.Protocol.BOLT2: [commitment_signed_funding_txid] :: CommitmentSigned -> !Maybe TxId
+ Lightning.Protocol.BOLT2: [commitment_signed_htlc_signatures] :: CommitmentSigned -> ![Signature]
+ Lightning.Protocol.BOLT2: [commitment_signed_signature] :: CommitmentSigned -> !Signature
+ Lightning.Protocol.BOLT2: [commitment_signed_tlvs] :: CommitmentSigned -> !TlvStream
+ Lightning.Protocol.BOLT2: [fee_range_max_fee_satoshis] :: FeeRange -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [fee_range_min_fee_satoshis] :: FeeRange -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [funding_created_funding_output_index] :: FundingCreated -> {-# UNPACK #-} !Word16
+ Lightning.Protocol.BOLT2: [funding_created_funding_txid] :: FundingCreated -> !TxId
+ Lightning.Protocol.BOLT2: [funding_created_signature] :: FundingCreated -> !Signature
+ Lightning.Protocol.BOLT2: [funding_created_temporary_channel_id] :: FundingCreated -> !ChannelId
+ Lightning.Protocol.BOLT2: [funding_created_tlvs] :: FundingCreated -> !TlvStream
+ Lightning.Protocol.BOLT2: [funding_signed_channel_id] :: FundingSigned -> !ChannelId
+ Lightning.Protocol.BOLT2: [funding_signed_signature] :: FundingSigned -> !Signature
+ Lightning.Protocol.BOLT2: [funding_signed_tlvs] :: FundingSigned -> !TlvStream
+ Lightning.Protocol.BOLT2: [next_funding_retransmit_flags] :: NextFunding -> {-# UNPACK #-} !Word8
+ Lightning.Protocol.BOLT2: [next_funding_txid] :: NextFunding -> !TxId
+ Lightning.Protocol.BOLT2: [open_channel2_chain_hash] :: OpenChannel2 -> !ChainHash
+ Lightning.Protocol.BOLT2: [open_channel2_channel_flags] :: OpenChannel2 -> {-# UNPACK #-} !Word8
+ Lightning.Protocol.BOLT2: [open_channel2_channel_type] :: OpenChannel2 -> !Maybe FeatureVector
+ Lightning.Protocol.BOLT2: [open_channel2_commitment_feerate_perkw] :: OpenChannel2 -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [open_channel2_delayed_payment_basepoint] :: OpenChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [open_channel2_dust_limit_satoshis] :: OpenChannel2 -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [open_channel2_first_per_commitment_point] :: OpenChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [open_channel2_funding_feerate_perkw] :: OpenChannel2 -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [open_channel2_funding_pubkey] :: OpenChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [open_channel2_funding_satoshis] :: OpenChannel2 -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [open_channel2_htlc_basepoint] :: OpenChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [open_channel2_htlc_minimum_msat] :: OpenChannel2 -> {-# UNPACK #-} !MilliSatoshi
+ Lightning.Protocol.BOLT2: [open_channel2_locktime] :: OpenChannel2 -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [open_channel2_max_accepted_htlcs] :: OpenChannel2 -> {-# UNPACK #-} !Word16
+ Lightning.Protocol.BOLT2: [open_channel2_max_htlc_value_in_flight_msat] :: OpenChannel2 -> {-# UNPACK #-} !Word64
+ Lightning.Protocol.BOLT2: [open_channel2_payment_basepoint] :: OpenChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [open_channel2_require_confirmed_inputs] :: OpenChannel2 -> !Bool
+ Lightning.Protocol.BOLT2: [open_channel2_revocation_basepoint] :: OpenChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [open_channel2_second_per_commitment_point] :: OpenChannel2 -> !Point
+ Lightning.Protocol.BOLT2: [open_channel2_temporary_channel_id] :: OpenChannel2 -> !ChannelId
+ Lightning.Protocol.BOLT2: [open_channel2_tlvs] :: OpenChannel2 -> !TlvStream
+ Lightning.Protocol.BOLT2: [open_channel2_to_self_delay] :: OpenChannel2 -> {-# UNPACK #-} !Word16
+ Lightning.Protocol.BOLT2: [open_channel2_upfront_shutdown_script] :: OpenChannel2 -> !Maybe ScriptPubKey
+ Lightning.Protocol.BOLT2: [open_channel_chain_hash] :: OpenChannel -> !ChainHash
+ Lightning.Protocol.BOLT2: [open_channel_channel_flags] :: OpenChannel -> {-# UNPACK #-} !Word8
+ Lightning.Protocol.BOLT2: [open_channel_channel_reserve_satoshis] :: OpenChannel -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [open_channel_channel_type] :: OpenChannel -> !Maybe FeatureVector
+ Lightning.Protocol.BOLT2: [open_channel_delayed_payment_basepoint] :: OpenChannel -> !Point
+ Lightning.Protocol.BOLT2: [open_channel_dust_limit_satoshis] :: OpenChannel -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [open_channel_feerate_per_kw] :: OpenChannel -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [open_channel_first_per_commitment_point] :: OpenChannel -> !Point
+ Lightning.Protocol.BOLT2: [open_channel_funding_pubkey] :: OpenChannel -> !Point
+ Lightning.Protocol.BOLT2: [open_channel_funding_satoshis] :: OpenChannel -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [open_channel_htlc_basepoint] :: OpenChannel -> !Point
+ Lightning.Protocol.BOLT2: [open_channel_htlc_minimum_msat] :: OpenChannel -> {-# UNPACK #-} !MilliSatoshi
+ Lightning.Protocol.BOLT2: [open_channel_max_accepted_htlcs] :: OpenChannel -> {-# UNPACK #-} !Word16
+ Lightning.Protocol.BOLT2: [open_channel_max_htlc_value_in_flight_msat] :: OpenChannel -> {-# UNPACK #-} !Word64
+ Lightning.Protocol.BOLT2: [open_channel_payment_basepoint] :: OpenChannel -> !Point
+ Lightning.Protocol.BOLT2: [open_channel_push_msat] :: OpenChannel -> {-# UNPACK #-} !MilliSatoshi
+ Lightning.Protocol.BOLT2: [open_channel_revocation_basepoint] :: OpenChannel -> !Point
+ Lightning.Protocol.BOLT2: [open_channel_temporary_channel_id] :: OpenChannel -> !ChannelId
+ Lightning.Protocol.BOLT2: [open_channel_tlvs] :: OpenChannel -> !TlvStream
+ Lightning.Protocol.BOLT2: [open_channel_to_self_delay] :: OpenChannel -> {-# UNPACK #-} !Word16
+ Lightning.Protocol.BOLT2: [open_channel_upfront_shutdown_script] :: OpenChannel -> !Maybe ScriptPubKey
+ Lightning.Protocol.BOLT2: [revoke_and_ack_channel_id] :: RevokeAndAck -> !ChannelId
+ Lightning.Protocol.BOLT2: [revoke_and_ack_next_per_commitment_point] :: RevokeAndAck -> !Point
+ Lightning.Protocol.BOLT2: [revoke_and_ack_per_commitment_secret] :: RevokeAndAck -> !PerCommitmentSecret
+ Lightning.Protocol.BOLT2: [revoke_and_ack_tlvs] :: RevokeAndAck -> !TlvStream
+ Lightning.Protocol.BOLT2: [shutdown_channel_id] :: Shutdown -> !ChannelId
+ Lightning.Protocol.BOLT2: [shutdown_scriptpubkey] :: Shutdown -> !ScriptPubKey
+ Lightning.Protocol.BOLT2: [shutdown_tlvs] :: Shutdown -> !TlvStream
+ Lightning.Protocol.BOLT2: [stfu_channel_id] :: Stfu -> !ChannelId
+ Lightning.Protocol.BOLT2: [stfu_initiator] :: Stfu -> !Bool
+ Lightning.Protocol.BOLT2: [stfu_tlvs] :: Stfu -> !TlvStream
+ Lightning.Protocol.BOLT2: [tx_abort_channel_id] :: TxAbort -> !ChannelId
+ Lightning.Protocol.BOLT2: [tx_abort_data] :: TxAbort -> !ByteString
+ Lightning.Protocol.BOLT2: [tx_abort_tlvs] :: TxAbort -> !TlvStream
+ Lightning.Protocol.BOLT2: [tx_ack_rbf_channel_id] :: TxAckRbf -> !ChannelId
+ Lightning.Protocol.BOLT2: [tx_ack_rbf_funding_output_contribution] :: TxAckRbf -> !Maybe Int64
+ Lightning.Protocol.BOLT2: [tx_ack_rbf_require_confirmed_inputs] :: TxAckRbf -> !Bool
+ Lightning.Protocol.BOLT2: [tx_ack_rbf_tlvs] :: TxAckRbf -> !TlvStream
+ Lightning.Protocol.BOLT2: [tx_add_input_channel_id] :: TxAddInput -> !ChannelId
+ Lightning.Protocol.BOLT2: [tx_add_input_prevtx] :: TxAddInput -> !ByteString
+ Lightning.Protocol.BOLT2: [tx_add_input_prevtx_vout] :: TxAddInput -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [tx_add_input_sequence] :: TxAddInput -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [tx_add_input_serial_id] :: TxAddInput -> !SerialId
+ Lightning.Protocol.BOLT2: [tx_add_input_tlvs] :: TxAddInput -> !TlvStream
+ Lightning.Protocol.BOLT2: [tx_add_output_channel_id] :: TxAddOutput -> !ChannelId
+ Lightning.Protocol.BOLT2: [tx_add_output_sats] :: TxAddOutput -> {-# UNPACK #-} !Satoshi
+ Lightning.Protocol.BOLT2: [tx_add_output_script] :: TxAddOutput -> !ScriptPubKey
+ Lightning.Protocol.BOLT2: [tx_add_output_serial_id] :: TxAddOutput -> !SerialId
+ Lightning.Protocol.BOLT2: [tx_add_output_tlvs] :: TxAddOutput -> !TlvStream
+ Lightning.Protocol.BOLT2: [tx_complete_channel_id] :: TxComplete -> !ChannelId
+ Lightning.Protocol.BOLT2: [tx_complete_tlvs] :: TxComplete -> !TlvStream
+ Lightning.Protocol.BOLT2: [tx_init_rbf_channel_id] :: TxInitRbf -> !ChannelId
+ Lightning.Protocol.BOLT2: [tx_init_rbf_feerate] :: TxInitRbf -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [tx_init_rbf_funding_output_contribution] :: TxInitRbf -> !Maybe Int64
+ Lightning.Protocol.BOLT2: [tx_init_rbf_locktime] :: TxInitRbf -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [tx_init_rbf_require_confirmed_inputs] :: TxInitRbf -> !Bool
+ Lightning.Protocol.BOLT2: [tx_init_rbf_tlvs] :: TxInitRbf -> !TlvStream
+ Lightning.Protocol.BOLT2: [tx_remove_input_channel_id] :: TxRemoveInput -> !ChannelId
+ Lightning.Protocol.BOLT2: [tx_remove_input_serial_id] :: TxRemoveInput -> !SerialId
+ Lightning.Protocol.BOLT2: [tx_remove_input_tlvs] :: TxRemoveInput -> !TlvStream
+ Lightning.Protocol.BOLT2: [tx_remove_output_channel_id] :: TxRemoveOutput -> !ChannelId
+ Lightning.Protocol.BOLT2: [tx_remove_output_serial_id] :: TxRemoveOutput -> !SerialId
+ Lightning.Protocol.BOLT2: [tx_remove_output_tlvs] :: TxRemoveOutput -> !TlvStream
+ Lightning.Protocol.BOLT2: [tx_signatures_channel_id] :: TxSignatures -> !ChannelId
+ Lightning.Protocol.BOLT2: [tx_signatures_tlvs] :: TxSignatures -> !TlvStream
+ Lightning.Protocol.BOLT2: [tx_signatures_txid] :: TxSignatures -> !TxId
+ Lightning.Protocol.BOLT2: [tx_signatures_witnesses] :: TxSignatures -> ![Witness]
+ Lightning.Protocol.BOLT2: [update_add_htlc_amount_msat] :: UpdateAddHtlc -> {-# UNPACK #-} !MilliSatoshi
+ Lightning.Protocol.BOLT2: [update_add_htlc_channel_id] :: UpdateAddHtlc -> !ChannelId
+ Lightning.Protocol.BOLT2: [update_add_htlc_cltv_expiry] :: UpdateAddHtlc -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [update_add_htlc_id] :: UpdateAddHtlc -> !HtlcId
+ Lightning.Protocol.BOLT2: [update_add_htlc_onion_routing_packet] :: UpdateAddHtlc -> !OnionRoutingPacket
+ Lightning.Protocol.BOLT2: [update_add_htlc_path_key] :: UpdateAddHtlc -> !Maybe Point
+ Lightning.Protocol.BOLT2: [update_add_htlc_payment_hash] :: UpdateAddHtlc -> !PaymentHash
+ Lightning.Protocol.BOLT2: [update_add_htlc_tlvs] :: UpdateAddHtlc -> !TlvStream
+ Lightning.Protocol.BOLT2: [update_fail_htlc_attribution_data] :: UpdateFailHtlc -> !Maybe AttributionData
+ Lightning.Protocol.BOLT2: [update_fail_htlc_channel_id] :: UpdateFailHtlc -> !ChannelId
+ Lightning.Protocol.BOLT2: [update_fail_htlc_id] :: UpdateFailHtlc -> !HtlcId
+ Lightning.Protocol.BOLT2: [update_fail_htlc_reason] :: UpdateFailHtlc -> !ByteString
+ Lightning.Protocol.BOLT2: [update_fail_htlc_tlvs] :: UpdateFailHtlc -> !TlvStream
+ Lightning.Protocol.BOLT2: [update_fail_malformed_htlc_channel_id] :: UpdateFailMalformedHtlc -> !ChannelId
+ Lightning.Protocol.BOLT2: [update_fail_malformed_htlc_failure_code] :: UpdateFailMalformedHtlc -> {-# UNPACK #-} !Word16
+ Lightning.Protocol.BOLT2: [update_fail_malformed_htlc_id] :: UpdateFailMalformedHtlc -> !HtlcId
+ Lightning.Protocol.BOLT2: [update_fail_malformed_htlc_sha256_of_onion] :: UpdateFailMalformedHtlc -> !OnionHash
+ Lightning.Protocol.BOLT2: [update_fail_malformed_htlc_tlvs] :: UpdateFailMalformedHtlc -> !TlvStream
+ Lightning.Protocol.BOLT2: [update_fee_channel_id] :: UpdateFee -> !ChannelId
+ Lightning.Protocol.BOLT2: [update_fee_feerate_per_kw] :: UpdateFee -> {-# UNPACK #-} !Word32
+ Lightning.Protocol.BOLT2: [update_fee_tlvs] :: UpdateFee -> !TlvStream
+ Lightning.Protocol.BOLT2: [update_fulfill_htlc_attribution_data] :: UpdateFulfillHtlc -> !Maybe AttributionData
+ Lightning.Protocol.BOLT2: [update_fulfill_htlc_channel_id] :: UpdateFulfillHtlc -> !ChannelId
+ Lightning.Protocol.BOLT2: [update_fulfill_htlc_fulfillment_payload] :: UpdateFulfillHtlc -> !Maybe ByteString
+ Lightning.Protocol.BOLT2: [update_fulfill_htlc_id] :: UpdateFulfillHtlc -> !HtlcId
+ Lightning.Protocol.BOLT2: [update_fulfill_htlc_payment_preimage] :: UpdateFulfillHtlc -> !PaymentPreimage
+ Lightning.Protocol.BOLT2: [update_fulfill_htlc_tlvs] :: UpdateFulfillHtlc -> !TlvStream
+ Lightning.Protocol.BOLT2: attribution_data :: ByteString -> Maybe AttributionData
+ Lightning.Protocol.BOLT2: data AcceptChannel
+ Lightning.Protocol.BOLT2: data AcceptChannel2
+ Lightning.Protocol.BOLT2: data AttributionData
+ Lightning.Protocol.BOLT2: data ChannelReady
+ Lightning.Protocol.BOLT2: data ChannelReestablish
+ Lightning.Protocol.BOLT2: data ClosingComplete
+ Lightning.Protocol.BOLT2: data ClosingSig
+ Lightning.Protocol.BOLT2: data ClosingSigned
+ Lightning.Protocol.BOLT2: data CommitmentSigned
+ Lightning.Protocol.BOLT2: data DecodeError
+ Lightning.Protocol.BOLT2: data EncodeError
+ Lightning.Protocol.BOLT2: data FeeRange
+ Lightning.Protocol.BOLT2: data FundingCreated
+ Lightning.Protocol.BOLT2: data FundingSigned
+ Lightning.Protocol.BOLT2: data Message
+ Lightning.Protocol.BOLT2: data NextFunding
+ Lightning.Protocol.BOLT2: data OnionHash
+ Lightning.Protocol.BOLT2: data OnionRoutingPacket
+ Lightning.Protocol.BOLT2: data OpenChannel
+ Lightning.Protocol.BOLT2: data OpenChannel2
+ Lightning.Protocol.BOLT2: data RevokeAndAck
+ Lightning.Protocol.BOLT2: data ScriptPubKey
+ Lightning.Protocol.BOLT2: data Shutdown
+ Lightning.Protocol.BOLT2: data Stfu
+ Lightning.Protocol.BOLT2: data TxAbort
+ Lightning.Protocol.BOLT2: data TxAckRbf
+ Lightning.Protocol.BOLT2: data TxAddInput
+ Lightning.Protocol.BOLT2: data TxAddOutput
+ Lightning.Protocol.BOLT2: data TxComplete
+ Lightning.Protocol.BOLT2: data TxInitRbf
+ Lightning.Protocol.BOLT2: data TxRemoveInput
+ Lightning.Protocol.BOLT2: data TxRemoveOutput
+ Lightning.Protocol.BOLT2: data TxSignatures
+ Lightning.Protocol.BOLT2: data UpdateAddHtlc
+ Lightning.Protocol.BOLT2: data UpdateFailHtlc
+ Lightning.Protocol.BOLT2: data UpdateFailMalformedHtlc
+ Lightning.Protocol.BOLT2: data UpdateFee
+ Lightning.Protocol.BOLT2: data UpdateFulfillHtlc
+ Lightning.Protocol.BOLT2: data Witness
+ Lightning.Protocol.BOLT2: decode_accept_channel :: ByteString -> Either DecodeError AcceptChannel
+ Lightning.Protocol.BOLT2: decode_accept_channel2 :: ByteString -> Either DecodeError AcceptChannel2
+ Lightning.Protocol.BOLT2: decode_channel_ready :: ByteString -> Either DecodeError ChannelReady
+ Lightning.Protocol.BOLT2: decode_channel_reestablish :: ByteString -> Either DecodeError ChannelReestablish
+ Lightning.Protocol.BOLT2: decode_closing_complete :: ByteString -> Either DecodeError ClosingComplete
+ Lightning.Protocol.BOLT2: decode_closing_sig :: ByteString -> Either DecodeError ClosingSig
+ Lightning.Protocol.BOLT2: decode_closing_signed :: ByteString -> Either DecodeError ClosingSigned
+ Lightning.Protocol.BOLT2: decode_commitment_signed :: ByteString -> Either DecodeError CommitmentSigned
+ Lightning.Protocol.BOLT2: decode_funding_created :: ByteString -> Either DecodeError FundingCreated
+ Lightning.Protocol.BOLT2: decode_funding_signed :: ByteString -> Either DecodeError FundingSigned
+ Lightning.Protocol.BOLT2: decode_message :: ByteString -> Either DecodeError Message
+ Lightning.Protocol.BOLT2: decode_open_channel :: ByteString -> Either DecodeError OpenChannel
+ Lightning.Protocol.BOLT2: decode_open_channel2 :: ByteString -> Either DecodeError OpenChannel2
+ Lightning.Protocol.BOLT2: decode_revoke_and_ack :: ByteString -> Either DecodeError RevokeAndAck
+ Lightning.Protocol.BOLT2: decode_shutdown :: ByteString -> Either DecodeError Shutdown
+ Lightning.Protocol.BOLT2: decode_stfu :: ByteString -> Either DecodeError Stfu
+ Lightning.Protocol.BOLT2: decode_tx_abort :: ByteString -> Either DecodeError TxAbort
+ Lightning.Protocol.BOLT2: decode_tx_ack_rbf :: ByteString -> Either DecodeError TxAckRbf
+ Lightning.Protocol.BOLT2: decode_tx_add_input :: ByteString -> Either DecodeError TxAddInput
+ Lightning.Protocol.BOLT2: decode_tx_add_output :: ByteString -> Either DecodeError TxAddOutput
+ Lightning.Protocol.BOLT2: decode_tx_complete :: ByteString -> Either DecodeError TxComplete
+ Lightning.Protocol.BOLT2: decode_tx_init_rbf :: ByteString -> Either DecodeError TxInitRbf
+ Lightning.Protocol.BOLT2: decode_tx_remove_input :: ByteString -> Either DecodeError TxRemoveInput
+ Lightning.Protocol.BOLT2: decode_tx_remove_output :: ByteString -> Either DecodeError TxRemoveOutput
+ Lightning.Protocol.BOLT2: decode_tx_signatures :: ByteString -> Either DecodeError TxSignatures
+ Lightning.Protocol.BOLT2: decode_update_add_htlc :: ByteString -> Either DecodeError UpdateAddHtlc
+ Lightning.Protocol.BOLT2: decode_update_fail_htlc :: ByteString -> Either DecodeError UpdateFailHtlc
+ Lightning.Protocol.BOLT2: decode_update_fail_malformed_htlc :: ByteString -> Either DecodeError UpdateFailMalformedHtlc
+ Lightning.Protocol.BOLT2: decode_update_fee :: ByteString -> Either DecodeError UpdateFee
+ Lightning.Protocol.BOLT2: decode_update_fulfill_htlc :: ByteString -> Either DecodeError UpdateFulfillHtlc
+ Lightning.Protocol.BOLT2: encode_accept_channel :: AcceptChannel -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_accept_channel2 :: AcceptChannel2 -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_channel_ready :: ChannelReady -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_channel_reestablish :: ChannelReestablish -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_closing_complete :: ClosingComplete -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_closing_sig :: ClosingSig -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_closing_signed :: ClosingSigned -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_commitment_signed :: CommitmentSigned -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_funding_created :: FundingCreated -> ByteString
+ Lightning.Protocol.BOLT2: encode_funding_signed :: FundingSigned -> ByteString
+ Lightning.Protocol.BOLT2: encode_message :: Message -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_open_channel :: OpenChannel -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_open_channel2 :: OpenChannel2 -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_revoke_and_ack :: RevokeAndAck -> ByteString
+ Lightning.Protocol.BOLT2: encode_shutdown :: Shutdown -> ByteString
+ Lightning.Protocol.BOLT2: encode_stfu :: Stfu -> ByteString
+ Lightning.Protocol.BOLT2: encode_tx_abort :: TxAbort -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_tx_ack_rbf :: TxAckRbf -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_tx_add_input :: TxAddInput -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_tx_add_output :: TxAddOutput -> ByteString
+ Lightning.Protocol.BOLT2: encode_tx_complete :: TxComplete -> ByteString
+ Lightning.Protocol.BOLT2: encode_tx_init_rbf :: TxInitRbf -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_tx_remove_input :: TxRemoveInput -> ByteString
+ Lightning.Protocol.BOLT2: encode_tx_remove_output :: TxRemoveOutput -> ByteString
+ Lightning.Protocol.BOLT2: encode_tx_signatures :: TxSignatures -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_update_add_htlc :: UpdateAddHtlc -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_update_fail_htlc :: UpdateFailHtlc -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: encode_update_fail_malformed_htlc :: UpdateFailMalformedHtlc -> ByteString
+ Lightning.Protocol.BOLT2: encode_update_fee :: UpdateFee -> ByteString
+ Lightning.Protocol.BOLT2: encode_update_fulfill_htlc :: UpdateFulfillHtlc -> Either EncodeError ByteString
+ Lightning.Protocol.BOLT2: message_type :: Message -> Word16
+ Lightning.Protocol.BOLT2: newtype HtlcId
+ Lightning.Protocol.BOLT2: newtype SerialId
+ Lightning.Protocol.BOLT2: onion_hash :: ByteString -> Maybe OnionHash
+ Lightning.Protocol.BOLT2: onion_routing_packet :: ByteString -> Maybe OnionRoutingPacket
+ Lightning.Protocol.BOLT2: script_pubkey :: ByteString -> Maybe ScriptPubKey
+ Lightning.Protocol.BOLT2: un_attribution_data :: AttributionData -> ByteString
+ Lightning.Protocol.BOLT2: un_onion_hash :: OnionHash -> ByteString
+ Lightning.Protocol.BOLT2: un_onion_routing_packet :: OnionRoutingPacket -> ByteString
+ Lightning.Protocol.BOLT2: un_script_pubkey :: ScriptPubKey -> ByteString
+ Lightning.Protocol.BOLT2: un_witness :: Witness -> ByteString
+ Lightning.Protocol.BOLT2: witness :: ByteString -> Maybe Witness
Files
- CHANGELOG +39/−1
- bench/Fixtures.hs +126/−0
- bench/Main.hs +55/−291
- bench/Weight.hs +43/−338
- lib/Lightning/Protocol/BOLT2.hs +168/−109
- lib/Lightning/Protocol/BOLT2/Codec.hs +1388/−1347
- lib/Lightning/Protocol/BOLT2/Messages.hs +429/−429
- lib/Lightning/Protocol/BOLT2/Types.hs +146/−452
- ppad-bolt2.cabal +17/−8
- test/Main.hs +1304/−1288
CHANGELOG view
@@ -1,4 +1,42 @@ # Changelog -- 0.0.1 (2025-01-25)+- 0.1.0 (2026-10-10)+ * A substantial rewrite against ppad-bolt1 0.1.0, with breaking+ changes throughout:++ * The API is exported from Lightning.Protocol.BOLT2 alone, and uses+ snake_case names, with record fields prefixed by their message's+ name (e.g. encode_open_channel, open_channel_funding_satoshis).++ * Payload decoders have type ByteString -> Either DecodeError a and+ consume their whole input; encoders return Either EncodeError+ ByteString only where they can fail. A Message type, with+ message_type, encode_message and decode_message, handles complete+ messages.++ * Every message has a TLV stream. Known TLV records are typed fields+ (channel_type is a ppad-bolt9 feature vector), unknown even records+ are rejected, and unknown odd records are kept, so encoding a+ decoded message reproduces its bytes.++ * Amounts use ppad-bolt1's bounded Satoshi and MilliSatoshi, except+ max_htlc_value_in_flight_msat. Types from ppad-bolt1 and ppad-tx+ are no longer re-exported.++ * OnionPacket is renamed OnionRoutingPacket and checks its length;+ ScriptPubKey and Witness are bounded at 65535 bytes; FeatureBits,+ Initiator and MsgType are removed; OnionHash, AttributionData,+ FeeRange and NextFunding are added.++ * Catches up with BOLT #2 as of lightning/bolts 1aadb719:+ channel_reestablish's next_funding moves to TLV type 1, and+ update_fulfill_htlc (fulfillment_payload), commitment_signed+ (funding_txid), tx_add_input and tx_signatures gain TLV streams.++ * Fixes decoding, which accepted unknown even TLV types, didn't check+ known TLV values, point prefixes or amounts, and ignored trailing+ bytes on some messages; and encoding, which accepted malformed+ field values.++- 0.0.1 (2026-04-18) * Initial release.
+ bench/Fixtures.hs view
@@ -0,0 +1,126 @@+{-# LANGUAGE OverloadedStrings #-}++module Fixtures (+ Fixtures(..)+ , fixtures+ ) where++import qualified Bitcoin.Prim.Tx as Tx+import qualified Data.ByteString as BS+import qualified Lightning.Protocol.BOLT1 as BOLT1+import Lightning.Protocol.BOLT2+import qualified Lightning.Protocol.BOLT9 as BOLT9++-- representative messages, with their encoded payloads+data Fixtures = Fixtures+ { fx_open_channel :: !OpenChannel+ , fx_open_channel_bytes :: !BS.ByteString+ , fx_accept_channel2 :: !AcceptChannel2+ , fx_accept_channel2_bytes :: !BS.ByteString+ , fx_tx_signatures :: !TxSignatures+ , fx_tx_signatures_bytes :: !BS.ByteString+ , fx_closing_complete :: !ClosingComplete+ , fx_closing_complete_bytes :: !BS.ByteString+ , fx_update_add_htlc :: !UpdateAddHtlc+ , fx_update_add_htlc_bytes :: !BS.ByteString+ , fx_update_add_htlc_wire :: !BS.ByteString+ , fx_update_fulfill_htlc :: !UpdateFulfillHtlc+ , fx_update_fulfill_htlc_bytes :: !BS.ByteString+ , fx_commitment_signed :: !CommitmentSigned+ , fx_commitment_signed_bytes :: !BS.ByteString+ , fx_commitment_signed_483 :: !CommitmentSigned+ , fx_commitment_signed_483_bytes :: !BS.ByteString+ , fx_revoke_and_ack :: !RevokeAndAck+ , fx_revoke_and_ack_bytes :: !BS.ByteString+ , fx_channel_reestablish :: !ChannelReestablish+ , fx_channel_reestablish_bytes :: !BS.ByteString+ }++ok :: Either e a -> Maybe a+ok = either (const Nothing) Just++empty :: BOLT1.TlvStream+empty = BOLT1.empty_tlv_stream++fixtures :: Maybe Fixtures+fixtures = do+ ch <- BOLT1.chain_hash (BS.replicate 32 0x6f)+ cid <- BOLT1.channel_id (BS.replicate 32 0xab)+ pts <- traverse (\b -> BOLT1.point (BS.cons 0x02 (BS.replicate 32 b)))+ [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77]+ sig <- BOLT1.signature (BS.replicate 64 0xa1)+ txid <- Tx.mk_txid (BS.replicate 32 0x7e)+ spk <- script_pubkey ("\x00\x14" <> BS.replicate 20 0x88)+ fund <- BOLT1.satoshi 1000000+ dust <- BOLT1.satoshi 546+ res <- BOLT1.satoshi 10000+ push <- BOLT1.milli_satoshi 0+ hmin <- BOLT1.milli_satoshi 1000+ amt <- BOLT1.milli_satoshi 100000+ fee <- BOLT1.satoshi 500+ ph <- BOLT1.payment_hash (BS.replicate 32 0x9a)+ pre <- BOLT1.payment_preimage (BS.replicate 32 0x50)+ sec <- BOLT1.per_commitment_secret (BS.replicate 32 0x5e)+ onion <- onion_routing_packet (BS.replicate 1366 0x44)+ att <- attribution_data (BS.replicate 920 0x0b)+ ws <- traverse witness+ [ "\x02\x47" <> BS.replicate 71 0x30 <> "\x21"+ <> BS.replicate 33 0x02+ , "\x01\x40" <> BS.replicate 64 0x01 ]+ ext <- BOLT1.tlv_stream [BOLT1.TlvRecord 43 (BS.replicate 16 0x2a)]+ (p1, p2, p3, p4, p5, p6, p7) <- case pts of+ [a, b, c, d, e, f, g] -> Just (a, b, c, d, e, f, g)+ _ -> Nothing+ let ctype = BOLT9.channel_type_features+ (BOLT9.ChannelType BOLT9.BasicAnchors False False)++ oc = OpenChannel ch cid fund push dust maxBound res hmin 253 144 483+ p1 p2 p3 p4 p5 p6 1 (Just spk) (Just ctype) empty+ ac2 = AcceptChannel2 cid fund dust maxBound hmin 3 144 483+ p1 p2 p3 p4 p5 p6 p7 (Just spk) (Just ctype) True ext+ txs = TxSignatures cid txid ws empty+ cc = ClosingComplete cid spk spk fee 0 (Just sig) Nothing (Just sig)+ empty+ add = UpdateAddHtlc cid (HtlcId 42) amt ph 800000 onion (Just p1)+ empty+ ful = UpdateFulfillHtlc cid (HtlcId 42) pre (Just att) Nothing empty+ cs0 = CommitmentSigned cid sig [] (Just txid) empty+ cs483 = CommitmentSigned cid sig (replicate 483 sig) (Just txid)+ empty+ raa = RevokeAndAck cid sec p1 empty+ rst = ChannelReestablish cid 5 4 sec p1 (Just (NextFunding txid 1))+ empty++ oc_b <- ok (encode_open_channel oc)+ ac2_b <- ok (encode_accept_channel2 ac2)+ txs_b <- ok (encode_tx_signatures txs)+ cc_b <- ok (encode_closing_complete cc)+ add_b <- ok (encode_update_add_htlc add)+ add_w <- ok (encode_message (MsgUpdateAddHtlc add))+ ful_b <- ok (encode_update_fulfill_htlc ful)+ cs0_b <- ok (encode_commitment_signed cs0)+ cs483_b <- ok (encode_commitment_signed cs483)+ rst_b <- ok (encode_channel_reestablish rst)+ pure Fixtures+ { fx_open_channel = oc+ , fx_open_channel_bytes = oc_b+ , fx_accept_channel2 = ac2+ , fx_accept_channel2_bytes = ac2_b+ , fx_tx_signatures = txs+ , fx_tx_signatures_bytes = txs_b+ , fx_closing_complete = cc+ , fx_closing_complete_bytes = cc_b+ , fx_update_add_htlc = add+ , fx_update_add_htlc_bytes = add_b+ , fx_update_add_htlc_wire = add_w+ , fx_update_fulfill_htlc = ful+ , fx_update_fulfill_htlc_bytes = ful_b+ , fx_commitment_signed = cs0+ , fx_commitment_signed_bytes = cs0_b+ , fx_commitment_signed_483 = cs483+ , fx_commitment_signed_483_bytes = cs483_b+ , fx_revoke_and_ack = raa+ , fx_revoke_and_ack_bytes = encode_revoke_and_ack raa+ , fx_channel_reestablish = rst+ , fx_channel_reestablish_bytes = rst_b+ }
bench/Main.hs view
@@ -1,301 +1,65 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE OverloadedStrings #-}---- |--- Module: Main--- Copyright: (c) 2025 Jared Tobin--- License: MIT--- Maintainer: Jared Tobin <jared@ppad.tech>------ Criterion timing benchmarks for BOLT #2 message codecs.- module Main where import Criterion.Main-import qualified Data.ByteString as BS-import Lightning.Protocol.BOLT1 (TlvStream, unsafeTlvStream)+import Fixtures import Lightning.Protocol.BOLT2 --- Test data construction ---------------------------------------------------------- | 32 zero bytes for channel IDs, chain hashes, etc.-zeroBytes32 :: BS.ByteString-zeroBytes32 = BS.replicate 32 0x00-{-# NOINLINE zeroBytes32 #-}---- | 33-byte compressed public key (02 prefix + 32 zero bytes).-testPoint :: Point-testPoint = case point (BS.cons 0x02 zeroBytes32) of- Just p -> p- Nothing -> error "testPoint: invalid"-{-# NOINLINE testPoint #-}---- | 64-byte signature.-testSignature :: Signature-testSignature = case signature (BS.replicate 64 0x01) of- Just s -> s- Nothing -> error "testSignature: invalid"-{-# NOINLINE testSignature #-}---- | 32-byte channel ID.-testChannelId :: ChannelId-testChannelId = case channelId zeroBytes32 of- Just c -> c- Nothing -> error "testChannelId: invalid"-{-# NOINLINE testChannelId #-}---- | 32-byte chain hash.-testChainHash :: ChainHash-testChainHash = case chainHash zeroBytes32 of- Just h -> h- Nothing -> error "testChainHash: invalid"-{-# NOINLINE testChainHash #-}---- | 32-byte txid.-testTxId :: TxId-testTxId = case txId zeroBytes32 of- Just t -> t- Nothing -> error "testTxId: invalid"-{-# NOINLINE testTxId #-}---- | 32-byte payment hash.-testPaymentHash :: PaymentHash-testPaymentHash = case paymentHash zeroBytes32 of- Just h -> h- Nothing -> error "testPaymentHash: invalid"-{-# NOINLINE testPaymentHash #-}---- | 1366-byte onion packet.-testOnionPacket :: OnionPacket-testOnionPacket = case onionPacket (BS.replicate 1366 0x00) of- Just o -> o- Nothing -> error "testOnionPacket: invalid"-{-# NOINLINE testOnionPacket #-}---- | Empty TLV stream.-emptyTlvs :: TlvStream-emptyTlvs = unsafeTlvStream []-{-# NOINLINE emptyTlvs #-}---- V1 messages --------------------------------------------------------------------- | Test OpenChannel message.-testOpenChannel :: OpenChannel-testOpenChannel = OpenChannel- { openChannelChainHash = testChainHash- , openChannelTempChannelId = testChannelId- , openChannelFundingSatoshis = Satoshis 1000000- , openChannelPushMsat = MilliSatoshis 0- , openChannelDustLimitSatoshis = Satoshis 546- , openChannelMaxHtlcValueInFlight = MilliSatoshis 1000000000- , openChannelChannelReserveSat = Satoshis 10000- , openChannelHtlcMinimumMsat = MilliSatoshis 1000- , openChannelFeeratePerKw = 250- , openChannelToSelfDelay = 144- , openChannelMaxAcceptedHtlcs = 30- , openChannelFundingPubkey = testPoint- , openChannelRevocationBasepoint = testPoint- , openChannelPaymentBasepoint = testPoint- , openChannelDelayedPaymentBase = testPoint- , openChannelHtlcBasepoint = testPoint- , openChannelFirstPerCommitPoint = testPoint- , openChannelChannelFlags = 0x00- , openChannelTlvs = emptyTlvs- }-{-# NOINLINE testOpenChannel #-}---- | Encoded OpenChannel for decode benchmarks.-encodedOpenChannel :: BS.ByteString-encodedOpenChannel = encodeOpenChannel testOpenChannel-{-# NOINLINE encodedOpenChannel #-}---- V2 messages --------------------------------------------------------------------- | Test OpenChannel2 message.-testOpenChannel2 :: OpenChannel2-testOpenChannel2 = OpenChannel2- { openChannel2ChainHash = testChainHash- , openChannel2TempChannelId = testChannelId- , openChannel2FundingFeeratePerkw = 2500- , openChannel2CommitFeeratePerkw = 250- , openChannel2FundingSatoshis = Satoshis 1000000- , openChannel2DustLimitSatoshis = Satoshis 546- , openChannel2MaxHtlcValueInFlight = MilliSatoshis 1000000000- , openChannel2HtlcMinimumMsat = MilliSatoshis 1000- , openChannel2ToSelfDelay = 144- , openChannel2MaxAcceptedHtlcs = 30- , openChannel2Locktime = 0- , openChannel2FundingPubkey = testPoint- , openChannel2RevocationBasepoint = testPoint- , openChannel2PaymentBasepoint = testPoint- , openChannel2DelayedPaymentBase = testPoint- , openChannel2HtlcBasepoint = testPoint- , openChannel2FirstPerCommitPoint = testPoint- , openChannel2SecondPerCommitPoint = testPoint- , openChannel2ChannelFlags = 0x00- , openChannel2Tlvs = emptyTlvs- }-{-# NOINLINE testOpenChannel2 #-}---- | Encoded OpenChannel2 for decode benchmarks.-encodedOpenChannel2 :: BS.ByteString-encodedOpenChannel2 = encodeOpenChannel2 testOpenChannel2-{-# NOINLINE encodedOpenChannel2 #-}---- | Test witness data (simulated P2WPKH signature + pubkey).-testWitness :: Witness-testWitness = Witness (BS.replicate 107 0xab)-{-# NOINLINE testWitness #-}---- | TxSignatures with multiple witnesses.-testTxSignatures :: TxSignatures-testTxSignatures = TxSignatures- { txSignaturesChannelId = testChannelId- , txSignaturesTxid = testTxId- , txSignaturesWitnesses = replicate 5 testWitness- }-{-# NOINLINE testTxSignatures #-}---- | Encoded TxSignatures for decode benchmarks.-encodedTxSignatures :: BS.ByteString-encodedTxSignatures = case encodeTxSignatures testTxSignatures of- Right bs -> bs- Left e -> error $ "encodedTxSignatures: " ++ show e-{-# NOINLINE encodedTxSignatures #-}---- Close messages ------------------------------------------------------------------ | Test ClosingSigned message.-testClosingSigned :: ClosingSigned-testClosingSigned = ClosingSigned- { closingSignedChannelId = testChannelId- , closingSignedFeeSatoshis = Satoshis 1000- , closingSignedSignature = testSignature- , closingSignedTlvs = emptyTlvs- }-{-# NOINLINE testClosingSigned #-}---- | Encoded ClosingSigned for decode benchmarks.-encodedClosingSigned :: BS.ByteString-encodedClosingSigned = encodeClosingSigned testClosingSigned-{-# NOINLINE encodedClosingSigned #-}---- Normal operation messages ------------------------------------------------------- | Test UpdateAddHtlc message.-testUpdateAddHtlc :: UpdateAddHtlc-testUpdateAddHtlc = UpdateAddHtlc- { updateAddHtlcChannelId = testChannelId- , updateAddHtlcId = 0- , updateAddHtlcAmountMsat = MilliSatoshis 10000000- , updateAddHtlcPaymentHash = testPaymentHash- , updateAddHtlcCltvExpiry = 800000- , updateAddHtlcOnionPacket = testOnionPacket- , updateAddHtlcTlvs = emptyTlvs- }-{-# NOINLINE testUpdateAddHtlc #-}---- | Encoded UpdateAddHtlc for decode benchmarks.-encodedUpdateAddHtlc :: BS.ByteString-encodedUpdateAddHtlc = encodeUpdateAddHtlc testUpdateAddHtlc-{-# NOINLINE encodedUpdateAddHtlc #-}---- | Test CommitmentSigned message with HTLC signatures (10 sigs).-testCommitmentSigned :: CommitmentSigned-testCommitmentSigned = CommitmentSigned- { commitmentSignedChannelId = testChannelId- , commitmentSignedSignature = testSignature- , commitmentSignedHtlcSignatures = replicate 10 testSignature- }-{-# NOINLINE testCommitmentSigned #-}---- | Encoded CommitmentSigned for decode benchmarks.-encodedCommitmentSigned :: BS.ByteString-encodedCommitmentSigned = case encodeCommitmentSigned testCommitmentSigned of- Right bs -> bs- Left e -> error $ "encodedCommitmentSigned: " ++ show e-{-# NOINLINE encodedCommitmentSigned #-}---- | Test CommitmentSigned with many HTLC signatures (100 sigs).-testCommitmentSignedLarge :: CommitmentSigned-testCommitmentSignedLarge = CommitmentSigned- { commitmentSignedChannelId = testChannelId- , commitmentSignedSignature = testSignature- , commitmentSignedHtlcSignatures = replicate 100 testSignature- }-{-# NOINLINE testCommitmentSignedLarge #-}---- | Encoded large CommitmentSigned for decode benchmarks.-encodedCommitmentSignedLarge :: BS.ByteString-encodedCommitmentSignedLarge =- case encodeCommitmentSigned testCommitmentSignedLarge of- Right bs -> bs- Left e -> error $ "encodedCommitmentSignedLarge: " ++ show e-{-# NOINLINE encodedCommitmentSignedLarge #-}---- | Test CommitmentSigned with max HTLC signatures (483 sigs).-testCommitmentSignedMax :: CommitmentSigned-testCommitmentSignedMax = CommitmentSigned- { commitmentSignedChannelId = testChannelId- , commitmentSignedSignature = testSignature- , commitmentSignedHtlcSignatures = replicate 483 testSignature- }-{-# NOINLINE testCommitmentSignedMax #-}---- | Encoded max CommitmentSigned for decode benchmarks.-encodedCommitmentSignedMax :: BS.ByteString-encodedCommitmentSignedMax =- case encodeCommitmentSigned testCommitmentSignedMax of- Right bs -> bs- Left e -> error $ "encodedCommitmentSignedMax: " ++ show e-{-# NOINLINE encodedCommitmentSignedMax #-}---- Benchmark groups ------------------------------------------------------------- main :: IO ()-main = defaultMain- [ bgroup "v1"- [ bgroup "open_channel"- [ bench "encode" $ nf encodeOpenChannel testOpenChannel- , bench "decode" $ nf decodeOpenChannel encodedOpenChannel- ]+main = case fixtures of+ Nothing -> fail "invalid fixtures"+ Just fx -> defaultMain [+ bgroup "open_channel" [+ bench "encode" $ nf encode_open_channel (fx_open_channel fx)+ , bench "decode" $ nf decode_open_channel (fx_open_channel_bytes fx) ]- , bgroup "v2"- [ bgroup "open_channel2"- [ bench "encode" $ nf encodeOpenChannel2 testOpenChannel2- , bench "decode" $ nf decodeOpenChannel2 encodedOpenChannel2- ]- , bgroup "tx_signatures"- [ bench "encode" $ nf encodeTxSignatures testTxSignatures- , bench "decode" $ nf decodeTxSignatures encodedTxSignatures- ]+ , bgroup "accept_channel2" [+ bench "encode" $ nf encode_accept_channel2 (fx_accept_channel2 fx)+ , bench "decode" $+ nf decode_accept_channel2 (fx_accept_channel2_bytes fx) ]- , bgroup "close"- [ bgroup "closing_signed"- [ bench "encode" $ nf encodeClosingSigned testClosingSigned- , bench "decode" $ nf decodeClosingSigned encodedClosingSigned- ]+ , bgroup "tx_signatures" [+ bench "encode" $ nf encode_tx_signatures (fx_tx_signatures fx)+ , bench "decode" $ nf decode_tx_signatures (fx_tx_signatures_bytes fx) ]- , bgroup "normal"- [ bgroup "update_add_htlc"- [ bench "encode" $ nf encodeUpdateAddHtlc testUpdateAddHtlc- , bench "decode" $ nf decodeUpdateAddHtlc encodedUpdateAddHtlc- ]- , bgroup "commitment_signed"- [ bench "encode" $ nf encodeCommitmentSigned testCommitmentSigned- , bench "decode" $ nf decodeCommitmentSigned encodedCommitmentSigned- ]- , bgroup "commitment_signed_100"- [ bench "encode" $- nf encodeCommitmentSigned testCommitmentSignedLarge- , bench "decode" $- nf decodeCommitmentSigned encodedCommitmentSignedLarge- ]- , bgroup "commitment_signed_483"- [ bench "encode" $- nf encodeCommitmentSigned testCommitmentSignedMax- , bench "decode" $- nf decodeCommitmentSigned encodedCommitmentSignedMax- ]+ , bgroup "closing_complete" [+ bench "encode" $ nf encode_closing_complete (fx_closing_complete fx)+ , bench "decode" $+ nf decode_closing_complete (fx_closing_complete_bytes fx) ]- ]+ , bgroup "update_add_htlc" [+ bench "encode" $ nf encode_update_add_htlc (fx_update_add_htlc fx)+ , bench "decode" $+ nf decode_update_add_htlc (fx_update_add_htlc_bytes fx)+ , bench "encode_message" $+ nf encode_message (MsgUpdateAddHtlc (fx_update_add_htlc fx))+ , bench "decode_message" $+ nf decode_message (fx_update_add_htlc_wire fx)+ ]+ , bgroup "update_fulfill_htlc" [+ bench "encode" $+ nf encode_update_fulfill_htlc (fx_update_fulfill_htlc fx)+ , bench "decode" $+ nf decode_update_fulfill_htlc (fx_update_fulfill_htlc_bytes fx)+ ]+ , bgroup "commitment_signed" [+ bench "encode (0 htlcs)" $+ nf encode_commitment_signed (fx_commitment_signed fx)+ , bench "decode (0 htlcs)" $+ nf decode_commitment_signed (fx_commitment_signed_bytes fx)+ , bench "encode (483 htlcs)" $+ nf encode_commitment_signed (fx_commitment_signed_483 fx)+ , bench "decode (483 htlcs)" $+ nf decode_commitment_signed (fx_commitment_signed_483_bytes fx)+ ]+ , bgroup "revoke_and_ack" [+ bench "encode" $ nf encode_revoke_and_ack (fx_revoke_and_ack fx)+ , bench "decode" $+ nf decode_revoke_and_ack (fx_revoke_and_ack_bytes fx)+ ]+ , bgroup "channel_reestablish" [+ bench "encode" $+ nf encode_channel_reestablish (fx_channel_reestablish fx)+ , bench "decode" $+ nf decode_channel_reestablish (fx_channel_reestablish_bytes fx)+ ]+ ]
bench/Weight.hs view
@@ -1,344 +1,49 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE OverloadedStrings #-}---- |--- Module: Main--- Copyright: (c) 2025 Jared Tobin--- License: MIT--- Maintainer: Jared Tobin <jared@ppad.tech>------ Weigh allocation benchmarks for BOLT #2 message codecs.- module Main where -import qualified Data.ByteString as BS-import Lightning.Protocol.BOLT1 (TlvStream, unsafeTlvStream)+import Fixtures import Lightning.Protocol.BOLT2 import Weigh --- | Wrapper for encoding functions that return Either.-forceEncode :: Either EncodeError BS.ByteString -> BS.ByteString-forceEncode (Right bs) = bs-forceEncode (Left e) = error $ "forceEncode: " ++ show e-{-# INLINE forceEncode #-}---- Test data construction ---------------------------------------------------------- | 32 zero bytes for channel IDs, chain hashes, etc.-zeroBytes32 :: BS.ByteString-zeroBytes32 = BS.replicate 32 0x00-{-# NOINLINE zeroBytes32 #-}---- | 33-byte compressed public key (02 prefix + 32 zero bytes).-testPoint :: Point-testPoint = case point (BS.cons 0x02 zeroBytes32) of- Just p -> p- Nothing -> error "testPoint: invalid"-{-# NOINLINE testPoint #-}---- | 64-byte signature.-testSignature :: Signature-testSignature = case signature (BS.replicate 64 0x01) of- Just s -> s- Nothing -> error "testSignature: invalid"-{-# NOINLINE testSignature #-}---- | 32-byte channel ID.-testChannelId :: ChannelId-testChannelId = case channelId zeroBytes32 of- Just c -> c- Nothing -> error "testChannelId: invalid"-{-# NOINLINE testChannelId #-}---- | 32-byte chain hash.-testChainHash :: ChainHash-testChainHash = case chainHash zeroBytes32 of- Just h -> h- Nothing -> error "testChainHash: invalid"-{-# NOINLINE testChainHash #-}---- | 32-byte txid.-testTxId :: TxId-testTxId = case txId zeroBytes32 of- Just t -> t- Nothing -> error "testTxId: invalid"-{-# NOINLINE testTxId #-}---- | 32-byte payment hash.-testPaymentHash :: PaymentHash-testPaymentHash = case paymentHash zeroBytes32 of- Just h -> h- Nothing -> error "testPaymentHash: invalid"-{-# NOINLINE testPaymentHash #-}---- | 1366-byte onion packet.-testOnionPacket :: OnionPacket-testOnionPacket = case onionPacket (BS.replicate 1366 0x00) of- Just o -> o- Nothing -> error "testOnionPacket: invalid"-{-# NOINLINE testOnionPacket #-}---- | Empty TLV stream.-emptyTlvs :: TlvStream-emptyTlvs = unsafeTlvStream []-{-# NOINLINE emptyTlvs #-}---- Message constructors ------------------------------------------------------------ | Construct OpenChannel message.-mkOpenChannel :: ChainHash -> ChannelId -> Point -> TlvStream -> OpenChannel-mkOpenChannel !ch !cid !pt !tlvs = OpenChannel- { openChannelChainHash = ch- , openChannelTempChannelId = cid- , openChannelFundingSatoshis = Satoshis 1000000- , openChannelPushMsat = MilliSatoshis 0- , openChannelDustLimitSatoshis = Satoshis 546- , openChannelMaxHtlcValueInFlight = MilliSatoshis 1000000000- , openChannelChannelReserveSat = Satoshis 10000- , openChannelHtlcMinimumMsat = MilliSatoshis 1000- , openChannelFeeratePerKw = 250- , openChannelToSelfDelay = 144- , openChannelMaxAcceptedHtlcs = 30- , openChannelFundingPubkey = pt- , openChannelRevocationBasepoint = pt- , openChannelPaymentBasepoint = pt- , openChannelDelayedPaymentBase = pt- , openChannelHtlcBasepoint = pt- , openChannelFirstPerCommitPoint = pt- , openChannelChannelFlags = 0x00- , openChannelTlvs = tlvs- }---- | Construct OpenChannel2 message.-mkOpenChannel2 :: ChainHash -> ChannelId -> Point -> TlvStream -> OpenChannel2-mkOpenChannel2 !ch !cid !pt !tlvs = OpenChannel2- { openChannel2ChainHash = ch- , openChannel2TempChannelId = cid- , openChannel2FundingFeeratePerkw = 2500- , openChannel2CommitFeeratePerkw = 250- , openChannel2FundingSatoshis = Satoshis 1000000- , openChannel2DustLimitSatoshis = Satoshis 546- , openChannel2MaxHtlcValueInFlight = MilliSatoshis 1000000000- , openChannel2HtlcMinimumMsat = MilliSatoshis 1000- , openChannel2ToSelfDelay = 144- , openChannel2MaxAcceptedHtlcs = 30- , openChannel2Locktime = 0- , openChannel2FundingPubkey = pt- , openChannel2RevocationBasepoint = pt- , openChannel2PaymentBasepoint = pt- , openChannel2DelayedPaymentBase = pt- , openChannel2HtlcBasepoint = pt- , openChannel2FirstPerCommitPoint = pt- , openChannel2SecondPerCommitPoint = pt- , openChannel2ChannelFlags = 0x00- , openChannel2Tlvs = tlvs- }---- | Construct TxSignatures message.-mkTxSignatures :: ChannelId -> TxId -> [Witness] -> TxSignatures-mkTxSignatures !cid !tid !ws = TxSignatures- { txSignaturesChannelId = cid- , txSignaturesTxid = tid- , txSignaturesWitnesses = ws- }---- | Construct ClosingSigned message.-mkClosingSigned :: ChannelId -> Signature -> TlvStream -> ClosingSigned-mkClosingSigned !cid !sig !tlvs = ClosingSigned- { closingSignedChannelId = cid- , closingSignedFeeSatoshis = Satoshis 1000- , closingSignedSignature = sig- , closingSignedTlvs = tlvs- }---- | Construct UpdateAddHtlc message.-mkUpdateAddHtlc- :: ChannelId -> PaymentHash -> OnionPacket -> TlvStream -> UpdateAddHtlc-mkUpdateAddHtlc !cid !ph !onion !tlvs = UpdateAddHtlc- { updateAddHtlcChannelId = cid- , updateAddHtlcId = 0- , updateAddHtlcAmountMsat = MilliSatoshis 10000000- , updateAddHtlcPaymentHash = ph- , updateAddHtlcCltvExpiry = 800000- , updateAddHtlcOnionPacket = onion- , updateAddHtlcTlvs = tlvs- }---- | Construct CommitmentSigned message.-mkCommitmentSigned :: ChannelId -> Signature -> [Signature] -> CommitmentSigned-mkCommitmentSigned !cid !sig !htlcSigs = CommitmentSigned- { commitmentSignedChannelId = cid- , commitmentSignedSignature = sig- , commitmentSignedHtlcSignatures = htlcSigs- }---- Pre-constructed messages -------------------------------------------------------- | Test OpenChannel message.-testOpenChannel :: OpenChannel-testOpenChannel =- mkOpenChannel testChainHash testChannelId testPoint emptyTlvs-{-# NOINLINE testOpenChannel #-}---- | Encoded OpenChannel for decode benchmarks.-encodedOpenChannel :: BS.ByteString-encodedOpenChannel = encodeOpenChannel testOpenChannel-{-# NOINLINE encodedOpenChannel #-}---- | Test OpenChannel2 message.-testOpenChannel2 :: OpenChannel2-testOpenChannel2 =- mkOpenChannel2 testChainHash testChannelId testPoint emptyTlvs-{-# NOINLINE testOpenChannel2 #-}---- | Encoded OpenChannel2 for decode benchmarks.-encodedOpenChannel2 :: BS.ByteString-encodedOpenChannel2 = encodeOpenChannel2 testOpenChannel2-{-# NOINLINE encodedOpenChannel2 #-}---- | Test witness data.-testWitness :: Witness-testWitness = Witness (BS.replicate 107 0xab)-{-# NOINLINE testWitness #-}---- | Multiple witnesses for TxSignatures.-testWitnesses :: [Witness]-testWitnesses = replicate 5 testWitness-{-# NOINLINE testWitnesses #-}---- | Test TxSignatures message.-testTxSignatures :: TxSignatures-testTxSignatures = mkTxSignatures testChannelId testTxId testWitnesses-{-# NOINLINE testTxSignatures #-}---- | Encoded TxSignatures for decode benchmarks.-encodedTxSignatures :: BS.ByteString-encodedTxSignatures = case encodeTxSignatures testTxSignatures of- Right bs -> bs- Left e -> error $ "encodedTxSignatures: " ++ show e-{-# NOINLINE encodedTxSignatures #-}---- | Test ClosingSigned message.-testClosingSigned :: ClosingSigned-testClosingSigned = mkClosingSigned testChannelId testSignature emptyTlvs-{-# NOINLINE testClosingSigned #-}---- | Encoded ClosingSigned for decode benchmarks.-encodedClosingSigned :: BS.ByteString-encodedClosingSigned = encodeClosingSigned testClosingSigned-{-# NOINLINE encodedClosingSigned #-}---- | Test UpdateAddHtlc message.-testUpdateAddHtlc :: UpdateAddHtlc-testUpdateAddHtlc =- mkUpdateAddHtlc testChannelId testPaymentHash testOnionPacket emptyTlvs-{-# NOINLINE testUpdateAddHtlc #-}---- | Encoded UpdateAddHtlc for decode benchmarks.-encodedUpdateAddHtlc :: BS.ByteString-encodedUpdateAddHtlc = encodeUpdateAddHtlc testUpdateAddHtlc-{-# NOINLINE encodedUpdateAddHtlc #-}---- | HTLC signatures for CommitmentSigned.-testHtlcSigs :: [Signature]-testHtlcSigs = replicate 10 testSignature-{-# NOINLINE testHtlcSigs #-}---- | Test CommitmentSigned message.-testCommitmentSigned :: CommitmentSigned-testCommitmentSigned =- mkCommitmentSigned testChannelId testSignature testHtlcSigs-{-# NOINLINE testCommitmentSigned #-}---- | Encoded CommitmentSigned for decode benchmarks.-encodedCommitmentSigned :: BS.ByteString-encodedCommitmentSigned = case encodeCommitmentSigned testCommitmentSigned of- Right bs -> bs- Left e -> error $ "encodedCommitmentSigned: " ++ show e-{-# NOINLINE encodedCommitmentSigned #-}---- | Large HTLC signatures for CommitmentSigned (100).-testHtlcSigsLarge :: [Signature]-testHtlcSigsLarge = replicate 100 testSignature-{-# NOINLINE testHtlcSigsLarge #-}---- | Test CommitmentSigned message (100 sigs).-testCommitmentSignedLarge :: CommitmentSigned-testCommitmentSignedLarge =- mkCommitmentSigned testChannelId testSignature testHtlcSigsLarge-{-# NOINLINE testCommitmentSignedLarge #-}---- | Encoded large CommitmentSigned for decode benchmarks.-encodedCommitmentSignedLarge :: BS.ByteString-encodedCommitmentSignedLarge =- case encodeCommitmentSigned testCommitmentSignedLarge of- Right bs -> bs- Left e -> error $ "encodedCommitmentSignedLarge: " ++ show e-{-# NOINLINE encodedCommitmentSignedLarge #-}---- | Max HTLC signatures for CommitmentSigned (483).-testHtlcSigsMax :: [Signature]-testHtlcSigsMax = replicate 483 testSignature-{-# NOINLINE testHtlcSigsMax #-}---- | Test CommitmentSigned message (483 sigs).-testCommitmentSignedMax :: CommitmentSigned-testCommitmentSignedMax =- mkCommitmentSigned testChannelId testSignature testHtlcSigsMax-{-# NOINLINE testCommitmentSignedMax #-}---- | Encoded max CommitmentSigned for decode benchmarks.-encodedCommitmentSignedMax :: BS.ByteString-encodedCommitmentSignedMax =- case encodeCommitmentSigned testCommitmentSignedMax of- Right bs -> bs- Left e -> error $ "encodedCommitmentSignedMax: " ++ show e-{-# NOINLINE encodedCommitmentSignedMax #-}---- Weigh benchmarks ------------------------------------------------------------- main :: IO ()-main = mainWith $ do- -- V1 message construction and encoding- wgroup "v1/open_channel" $ do- func "construct" (mkOpenChannel testChainHash testChannelId testPoint)- emptyTlvs- func "encode" encodeOpenChannel testOpenChannel- func "decode" decodeOpenChannel encodedOpenChannel-- -- V2 message construction and encoding- wgroup "v2/open_channel2" $ do- func "construct" (mkOpenChannel2 testChainHash testChannelId testPoint)- emptyTlvs- func "encode" encodeOpenChannel2 testOpenChannel2- func "decode" decodeOpenChannel2 encodedOpenChannel2-- wgroup "v2/tx_signatures" $ do- func "construct" (mkTxSignatures testChannelId testTxId) testWitnesses- func "encode" (forceEncode . encodeTxSignatures) testTxSignatures- func "decode" decodeTxSignatures encodedTxSignatures-- -- Close messages- wgroup "close/closing_signed" $ do- func "construct" (mkClosingSigned testChannelId testSignature) emptyTlvs- func "encode" encodeClosingSigned testClosingSigned- func "decode" decodeClosingSigned encodedClosingSigned-- -- Normal operation (hot paths)- wgroup "normal/update_add_htlc" $ do- func "construct"- (mkUpdateAddHtlc testChannelId testPaymentHash testOnionPacket) emptyTlvs- func "encode" encodeUpdateAddHtlc testUpdateAddHtlc- func "decode" decodeUpdateAddHtlc encodedUpdateAddHtlc-- wgroup "normal/commitment_signed" $ do- func "construct" (mkCommitmentSigned testChannelId testSignature)- testHtlcSigs- func "encode" (forceEncode . encodeCommitmentSigned) testCommitmentSigned- func "decode" decodeCommitmentSigned encodedCommitmentSigned-- wgroup "normal/commitment_signed_100" $ do- func "decode" decodeCommitmentSigned encodedCommitmentSignedLarge-- wgroup "normal/commitment_signed_483" $ do- func "decode" decodeCommitmentSigned encodedCommitmentSignedMax+main = case fixtures of+ Nothing -> fail "invalid fixtures"+ Just fx -> mainWith $ do+ func "baseline (weigh overhead)" (+ (1 :: Int)) 1+ wgroup "open_channel" $ do+ func "encode" encode_open_channel (fx_open_channel fx)+ func "decode" decode_open_channel (fx_open_channel_bytes fx)+ wgroup "accept_channel2" $ do+ func "encode" encode_accept_channel2 (fx_accept_channel2 fx)+ func "decode" decode_accept_channel2 (fx_accept_channel2_bytes fx)+ wgroup "tx_signatures" $ do+ func "encode" encode_tx_signatures (fx_tx_signatures fx)+ func "decode" decode_tx_signatures (fx_tx_signatures_bytes fx)+ wgroup "closing_complete" $ do+ func "encode" encode_closing_complete (fx_closing_complete fx)+ func "decode" decode_closing_complete (fx_closing_complete_bytes fx)+ wgroup "update_add_htlc" $ do+ func "encode" encode_update_add_htlc (fx_update_add_htlc fx)+ func "decode" decode_update_add_htlc (fx_update_add_htlc_bytes fx)+ func "encode_message" encode_message+ (MsgUpdateAddHtlc (fx_update_add_htlc fx))+ func "decode_message" decode_message (fx_update_add_htlc_wire fx)+ wgroup "update_fulfill_htlc" $ do+ func "encode" encode_update_fulfill_htlc (fx_update_fulfill_htlc fx)+ func "decode" decode_update_fulfill_htlc+ (fx_update_fulfill_htlc_bytes fx)+ wgroup "commitment_signed" $ do+ func "encode (0 htlcs)" encode_commitment_signed+ (fx_commitment_signed fx)+ func "decode (0 htlcs)" decode_commitment_signed+ (fx_commitment_signed_bytes fx)+ func "encode (483 htlcs)" encode_commitment_signed+ (fx_commitment_signed_483 fx)+ func "decode (483 htlcs)" decode_commitment_signed+ (fx_commitment_signed_483_bytes fx)+ wgroup "revoke_and_ack" $ do+ func "encode" encode_revoke_and_ack (fx_revoke_and_ack fx)+ func "decode" decode_revoke_and_ack (fx_revoke_and_ack_bytes fx)+ wgroup "channel_reestablish" $ do+ func "encode" encode_channel_reestablish (fx_channel_reestablish fx)+ func "decode" decode_channel_reestablish+ (fx_channel_reestablish_bytes fx)
lib/Lightning/Protocol/BOLT2.hs view
@@ -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+ -- * Messages+ Message(..)+ , message_type - -- * Codec functions- -- | Re-exported from "Lightning.Protocol.BOLT2.Codec".- , module Lightning.Protocol.BOLT2.Codec+ -- ** Channel establishment v1+ , OpenChannel(..)+ , AcceptChannel(..)+ , FundingCreated(..)+ , FundingSigned(..)+ , ChannelReady(..) - -- $messagetypes+ -- ** Channel establishment v2+ , OpenChannel2(..)+ , AcceptChannel2(..) - -- ** Channel establishment (v1)- -- $v1establishment+ -- ** Interactive transaction construction+ , TxAddInput(..)+ , TxAddOutput(..)+ , TxRemoveInput(..)+ , TxRemoveOutput(..)+ , TxComplete(..)+ , TxSignatures(..)+ , TxInitRbf(..)+ , TxAckRbf(..)+ , TxAbort(..) - -- ** Channel establishment (v2)- -- $v2establishment+ -- ** Channel quiescence+ , Stfu(..) -- ** Channel close- -- $close+ , Shutdown(..)+ , ClosingComplete(..)+ , ClosingSig(..)+ , ClosingSigned(..) -- ** Normal operation- -- $normal+ , UpdateAddHtlc(..)+ , UpdateFulfillHtlc(..)+ , UpdateFailHtlc(..)+ , UpdateFailMalformedHtlc(..)+ , CommitmentSigned(..)+ , RevokeAndAck(..)+ , UpdateFee(..) - -- ** Message reestablishment- -- $reestablish+ -- ** 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)
lib/Lightning/Protocol/BOLT2/Codec.hs view
@@ -1,1347 +1,1388 @@-{-# 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)+{-# OPTIONS_HADDOCK hide #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveGeneric #-}++-- |+-- Module: Lightning.Protocol.BOLT2.Codec+-- Copyright: (c) 2025 Jared Tobin+-- License: MIT+-- Maintainer: Jared Tobin <jared@ppad.tech>+--+-- Encoding and decoding of BOLT #2 messages.++module Lightning.Protocol.BOLT2.Codec (+ EncodeError(..)+ , DecodeError(..)++ , 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, mk_txid, un_txid)+import Control.DeepSeq (NFData)+import qualified Data.ByteString as BS+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+ ( ChannelId, Signature, Point, TlvRecord(..), TlvStream, TlvError )+import qualified Lightning.Protocol.BOLT9 as BOLT9+import Lightning.Protocol.BOLT2.Messages+import Lightning.Protocol.BOLT2.Types++-- errors ---------------------------------------------------------------------++-- | Why a message failed to encode.+data EncodeError+ = 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++-- | Why a message failed to decode.+data DecodeError+ = DecodeInsufficientBytes+ -- ^ the input ended before a field did+ | DecodeInvalidPoint+ -- ^ 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+ -- ^ 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++-- 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 mk_txid+{-# 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 <- mk_txid (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 (BOLT1.encode_u16 (fromIntegral n))+ where+ !n = length xs+{-# INLINE count_prefix #-}++txid_bytes :: TxId -> BS.ByteString+txid_bytes = un_txid+{-# 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 #-}++opt :: Word64 -> (a -> BS.ByteString) -> Maybe a -> [TlvRecord]+opt t f = maybe [] (\a -> [TlvRecord t (f a)])+{-# INLINE opt #-}++opt_flag :: Word64 -> Bool -> [TlvRecord]+opt_flag t b = if b then [TlvRecord t BS.empty] else []+{-# INLINE opt_flag #-}++fee_range_bytes :: FeeRange -> BS.ByteString+fee_range_bytes (FeeRange lo hi) =+ BOLT1.encode_satoshi lo <> BOLT1.encode_satoshi hi++next_funding_bytes :: NextFunding -> BS.ByteString+next_funding_bytes (NextFunding t f) = txid_bytes t <> word8 f++-- messages -------------------------------------------------------------------++-- | Encode a BOLT #2 message, including its type. Fails if a field+-- can't be encoded or the result exceeds 65535 bytes.+--+-- >>> 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.+--+-- A type that BOLT #2 doesn't define (including the splicing+-- messages, which this library doesn't implement) yields+-- 'DecodeUnknownEvenType' or 'DecodeUnknownOddType'.+--+-- >>> 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 t'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 t'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 t'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 t'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 t'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 a t'FundingCreated' payload.+decode_funding_created :: BS.ByteString -> Either DecodeError FundingCreated+decode_funding_created = parse $+ FundingCreated <$> channel_id <*> txid <*> u16 <*> signature <*> tlvs []++-- | Encode a t'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 a t'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 t'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 t'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 t'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 an t'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 t'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 t'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 t'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 t'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 t'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 t'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 t'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 t'TxRemoveInput' payload.+decode_tx_remove_input :: BS.ByteString -> Either DecodeError TxRemoveInput+decode_tx_remove_input = parse $+ TxRemoveInput <$> channel_id <*> serial_id <*> tlvs []++-- | Encode a t'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 t'TxRemoveOutput' payload.+decode_tx_remove_output+ :: BS.ByteString -> Either DecodeError TxRemoveOutput+decode_tx_remove_output = parse $+ TxRemoveOutput <$> channel_id <*> serial_id <*> tlvs []++-- | Encode a t'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 t'TxComplete' payload.+decode_tx_complete :: BS.ByteString -> Either DecodeError TxComplete+decode_tx_complete = parse $ TxComplete <$> channel_id <*> tlvs []++-- | Encode a t'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 t'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+ wit = do+ b <- prefixed+ maybe (failure DecodeInsufficientBytes) pure (witness b)++rbf_known :: [Word64]+rbf_known = [0, 2]++-- | Encode a t'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 t'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 t'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 t'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 t'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 t'TxAbort' payload.+decode_tx_abort :: BS.ByteString -> Either DecodeError TxAbort+decode_tx_abort = parse $ TxAbort <$> channel_id <*> prefixed <*> tlvs []++-- stfu -----------------------------------------------------------------------++-- | Encode a t'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 t'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 t'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 t'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 t'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 t'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 t'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 a t'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 t'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 a t'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 t'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 t'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 t'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 t'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 t'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 an t'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 t'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 t'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 t'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 t'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 mk_txid s+ pure (CommitmentSigned cid sig sigs fund (unknown commitment_signed_known s))++-- revoke_and_ack, update_fee -------------------------------------------------++-- | Encode a t'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 a t'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 t'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 an t'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 t'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 t'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))
lib/Lightning/Protocol/BOLT2/Messages.hs view
@@ -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 @@ , TxAckRbf(..) , TxAbort(..) - -- * Channel close , Stfu(..)+ , Shutdown(..)- , ClosingSigned(..) , ClosingComplete(..) , ClosingSig(..)+ , ClosingSigned(..) - -- * Normal operation , UpdateAddHtlc(..) , UpdateFulfillHtlc(..) , UpdateFailHtlc(..)@@ -58,544 +46,556 @@ , 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 ----------------------------------------------------+-- channel establishment v1 --------------------------------------------------- --- | The open_channel message (type 32).------ Contains information about a node and indicates its desire to set up--- a new channel.+-- | The @open_channel@ message (type 32). data OpenChannel = OpenChannel- { openChannelChainHash :: !ChainHash- , openChannelTempChannelId :: !ChannelId- , openChannelFundingSatoshis :: {-# UNPACK #-} !Satoshis- , openChannelPushMsat :: {-# UNPACK #-} !MilliSatoshis- , openChannelDustLimitSatoshis :: {-# UNPACK #-} !Satoshis- , openChannelMaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshis- , openChannelChannelReserveSat :: {-# UNPACK #-} !Satoshis- , openChannelHtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshis- , 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- , acceptChannelDustLimitSatoshis :: {-# UNPACK #-} !Satoshis- , acceptChannelMaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshis- , acceptChannelChannelReserveSat :: {-# UNPACK #-} !Satoshis- , acceptChannelHtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshis- , 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- , openChannel2FundingSatoshis :: {-# UNPACK #-} !Satoshis- , openChannel2DustLimitSatoshis :: {-# UNPACK #-} !Satoshis- , openChannel2MaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshis- , openChannel2HtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshis- , 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- , acceptChannel2FundingSatoshis :: {-# UNPACK #-} !Satoshis- , acceptChannel2DustLimitSatoshis :: {-# UNPACK #-} !Satoshis- , acceptChannel2MaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshis- , acceptChannel2HtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshis- , 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 :: {-# UNPACK #-} !Word64- , 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 :: {-# UNPACK #-} !Word64- , txAddOutputSats :: {-# UNPACK #-} !Satoshis- , 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 :: {-# UNPACK #-} !Word64- } 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 :: {-# UNPACK #-} !Word64- } 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 :: {-# UNPACK #-} !Word8- } 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- , closingSignedFeeSatoshis :: {-# UNPACK #-} !Satoshis- , 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- , closingCompleteFeeSatoshis :: {-# UNPACK #-} !Satoshis- , 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- , closingSigFeeSatoshis :: {-# UNPACK #-} !Satoshis- , 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 :: {-# UNPACK #-} !Word64- , updateAddHtlcAmountMsat :: {-# UNPACK #-} !MilliSatoshis- , 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 :: {-# UNPACK #-} !Word64- , 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 :: {-# UNPACK #-} !Word64- , 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 :: {-# UNPACK #-} !Word64- , 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 :: !Secret- , 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 :: !Secret- , 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
lib/Lightning/Protocol/BOLT2/Types.hs view
@@ -1,8 +1,5 @@-{-# OPTIONS_HADDOCK prune #-}-{-# LANGUAGE BangPatterns #-}+{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-} -- | -- Module: Lightning.Protocol.BOLT2.Types@@ -10,492 +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- ChannelId- , channelId- , unChannelId-- -- * Amounts- , Satoshis(..)- , MilliSatoshis(..)- , satoshisToMsat- , msatToSatoshis-- -- * Cryptographic types- , Signature- , signature- , unSignature- , Point- , point- , unPoint- , PaymentHash- , paymentHash- , unPaymentHash- , PaymentPreimage- , paymentPreimage- , unPaymentPreimage- , Secret- , secret- , unSecret-- -- * Transaction types- , TxId- , txId- , unTxId- , Outpoint(..)+ HtlcId(..)+ , SerialId(..) , ScriptPubKey- , scriptPubKey- , unScriptPubKey-- -- * Chain types- , ChainHash- , chainHash- , unChainHash- , ShortChannelId(..)- , shortChannelId- , scidBlockHeight- , scidTxIndex- , scidOutputIndex-- -- * Protocol types- , FeatureBits- , featureBits- , unFeatureBits- , OnionPacket- , onionPacket- , unOnionPacket-- -- * Constants- , channelIdLen- , signatureLen- , pointLen- , txIdLen- , chainHashLen- , shortChannelIdLen- , paymentHashLen- , paymentPreimageLen- , onionPacketLen- , secretLen+ , 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) import Control.DeepSeq (NFData)-import Data.Bits (unsafeShiftL, unsafeShiftR, (.&.), (.|.)) import qualified Data.ByteString as BS-import Data.Word (Word16, Word32, Word64)+import Data.Word (Word8, Word64) import GHC.Generics (Generic)---- 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 transaction ID in bytes (32).-txIdLen :: Int-txIdLen = 32-{-# INLINE txIdLen #-}---- | 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).-secretLen :: Int-secretLen = 32-{-# INLINE secretLen #-}---- identifiers --------------------------------------------------------------------- | A 32-byte channel identifier.------ Derived from the funding transaction by XORing @funding_txid@ with--- @funding_output_index@ (big-endian, altering the last 2 bytes).------ For v2 channels, derived as @SHA256(lesser-revocation-basepoint ||--- greater-revocation-basepoint)@.-newtype ChannelId = ChannelId BS.ByteString- deriving stock (Eq, Ord, Show, Generic)- deriving newtype NFData---- | Construct a 'ChannelId' from a 32-byte 'BS.ByteString'.------ Returns 'Nothing' if the input is not exactly 32 bytes.------ >>> channelId (BS.replicate 32 0x00)--- Just (ChannelId ...)--- >>> channelId (BS.replicate 31 0x00)--- Nothing-channelId :: BS.ByteString -> Maybe ChannelId-channelId !bs- | BS.length bs == channelIdLen = Just $! ChannelId bs- | otherwise = Nothing-{-# INLINABLE channelId #-}---- | Extract the underlying 'BS.ByteString' from a 'ChannelId'.-unChannelId :: ChannelId -> BS.ByteString-unChannelId (ChannelId bs) = bs-{-# INLINE unChannelId #-}---- amounts ------------------------------------------------------------------------- | Amount in satoshis (1/100,000,000 of a bitcoin).------ Stored as a 'Word64'. Maximum valid value is 21,000,000 * 100,000,000--- = 2,100,000,000,000,000 satoshis.-newtype Satoshis = Satoshis { unSatoshis :: Word64 }- deriving stock (Eq, Ord, Show, Generic)- deriving newtype (NFData, Num, Enum, Real, Integral)---- | Amount in millisatoshis (1/1000 of a satoshi).------ Stored as a 'Word64'. Used for HTLC amounts and channel balances.-newtype MilliSatoshis = MilliSatoshis { unMilliSatoshis :: Word64 }- deriving stock (Eq, Ord, Show, Generic)- deriving newtype (NFData, Num, Enum, Real, Integral)---- | Convert 'Satoshis' to 'MilliSatoshis'.------ >>> satoshisToMsat (Satoshis 1)--- MilliSatoshis 1000-satoshisToMsat :: Satoshis -> MilliSatoshis-satoshisToMsat (Satoshis !s) = MilliSatoshis $! s * 1000-{-# INLINE satoshisToMsat #-}---- | Convert 'MilliSatoshis' to 'Satoshis', rounding down.------ >>> msatToSatoshis (MilliSatoshis 1500)--- Satoshis 1-msatToSatoshis :: MilliSatoshis -> Satoshis-msatToSatoshis (MilliSatoshis !m) = Satoshis $! m `div` 1000-{-# INLINE msatToSatoshis #-}---- cryptographic types ------------------------------------------------------------- | A 64-byte compact ECDSA signature.------ Used for commitment transaction signatures, HTLC signatures, and--- closing transaction signatures.-newtype Signature = Signature BS.ByteString- deriving stock (Eq, Ord, Show, Generic)- deriving newtype NFData---- | Construct a 'Signature' from a 64-byte 'BS.ByteString'.------ Returns 'Nothing' if the input is not exactly 64 bytes.-signature :: BS.ByteString -> Maybe Signature-signature !bs- | BS.length bs == signatureLen = Just $! Signature bs- | otherwise = Nothing-{-# INLINABLE signature #-}---- | Extract the underlying 'BS.ByteString' from a 'Signature'.-unSignature :: Signature -> BS.ByteString-unSignature (Signature bs) = bs-{-# INLINE unSignature #-}---- | A 33-byte compressed secp256k1 public key.------ Used for funding pubkeys, basepoints, and per-commitment points.-newtype Point = Point BS.ByteString- deriving stock (Eq, Ord, Show, Generic)- deriving newtype NFData---- | Construct a 'Point' from a 33-byte 'BS.ByteString'.------ Returns 'Nothing' if the input is not exactly 33 bytes.------ Note: This only validates the length. Use secp256k1 libraries for--- full point validation.-point :: BS.ByteString -> Maybe Point-point !bs- | BS.length bs == pointLen = Just $! Point bs- | otherwise = Nothing-{-# INLINABLE point #-}---- | Extract the underlying 'BS.ByteString' from a 'Point'.-unPoint :: Point -> BS.ByteString-unPoint (Point bs) = bs-{-# INLINE unPoint #-}---- | A 32-byte SHA256 payment hash.------ Used to identify HTLCs. The preimage that hashes to this value is--- required to claim the HTLC.-newtype PaymentHash = PaymentHash BS.ByteString- deriving stock (Eq, Ord, Show, Generic)- deriving newtype NFData---- | Construct a 'PaymentHash' from a 32-byte 'BS.ByteString'.------ Returns 'Nothing' if the input is not exactly 32 bytes.-paymentHash :: BS.ByteString -> Maybe PaymentHash-paymentHash !bs- | BS.length bs == paymentHashLen = Just $! PaymentHash bs- | otherwise = Nothing-{-# INLINABLE paymentHash #-}---- | Extract the underlying 'BS.ByteString' from a 'PaymentHash'.-unPaymentHash :: PaymentHash -> BS.ByteString-unPaymentHash (PaymentHash bs) = bs-{-# INLINE unPaymentHash #-}---- | A 32-byte payment preimage.------ The SHA256 hash of this value produces the corresponding 'PaymentHash'.--- Knowledge of the preimage allows claiming an HTLC.-newtype PaymentPreimage = PaymentPreimage BS.ByteString- deriving stock (Eq, Ord, Show, Generic)- deriving newtype NFData---- | Construct a 'PaymentPreimage' from a 32-byte 'BS.ByteString'.------ Returns 'Nothing' if the input is not exactly 32 bytes.-paymentPreimage :: BS.ByteString -> Maybe PaymentPreimage-paymentPreimage !bs- | BS.length bs == paymentPreimageLen = Just $! PaymentPreimage bs- | otherwise = Nothing-{-# INLINABLE paymentPreimage #-}+import Lightning.Protocol.BOLT1 (Satoshi) --- | Extract the underlying 'BS.ByteString' from a 'PaymentPreimage'.-unPaymentPreimage :: PaymentPreimage -> BS.ByteString-unPaymentPreimage (PaymentPreimage bs) = bs-{-# INLINE unPaymentPreimage #-}+-- | 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 (Eq, Ord, Show, Generic) --- | A 32-byte per-commitment secret.------ Used in revoke_and_ack and channel_reestablish messages to revoke--- old commitment transactions.-newtype Secret = Secret BS.ByteString- deriving stock (Eq, Ord, Show, Generic)- deriving newtype NFData+instance NFData HtlcId --- | Construct a 'Secret' from a 32-byte 'BS.ByteString'.------ Returns 'Nothing' if the input is not exactly 32 bytes.-secret :: BS.ByteString -> Maybe Secret-secret !bs- | BS.length bs == secretLen = Just $! Secret bs- | otherwise = Nothing-{-# INLINABLE secret #-}+-- | 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 (Eq, Ord, Show, Generic) --- | Extract the underlying 'BS.ByteString' from a 'Secret'.-unSecret :: Secret -> BS.ByteString-unSecret (Secret bs) = bs-{-# INLINE unSecret #-}+instance NFData SerialId --- transaction types -----------------------------------------------------------+-- | 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 32-byte transaction identifier.------ The double-SHA256 hash of a serialized transaction.-newtype TxId = TxId BS.ByteString- deriving stock (Eq, Ord, Show, Generic)- deriving newtype NFData+instance NFData ScriptPubKey --- | Construct a 'TxId' from a 32-byte 'BS.ByteString'.+-- | Construct a t'ScriptPubKey', failing above 65535 bytes. The script+-- itself isn't checked; the forms acceptable in @shutdown@ depend on+-- negotiated features. ----- Returns 'Nothing' if the input is not exactly 32 bytes.-txId :: BS.ByteString -> Maybe TxId-txId !bs- | BS.length bs == txIdLen = Just $! TxId bs- | otherwise = Nothing-{-# INLINABLE txId #-}---- | Extract the underlying 'BS.ByteString' from a 'TxId'.-unTxId :: TxId -> BS.ByteString-unTxId (TxId bs) = bs-{-# INLINE unTxId #-}+-- >>> 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 #-} --- | A transaction outpoint (txid + output index).------ Identifies a specific output of a transaction.-data Outpoint = Outpoint- { outpointTxId :: {-# UNPACK #-} !TxId- , outpointVout :: {-# UNPACK #-} !Word32- }- deriving stock (Eq, Ord, Show, Generic)+-- | The bytes of a t'ScriptPubKey'.+un_script_pubkey :: ScriptPubKey -> BS.ByteString+un_script_pubkey (ScriptPubKey bs) = bs+{-# INLINE un_script_pubkey #-} -instance NFData Outpoint+-- | 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) --- | A script pubkey (output script).------ Variable length; used in shutdown messages, closing transactions, etc.-newtype ScriptPubKey = ScriptPubKey BS.ByteString- deriving stock (Eq, Ord, Show, Generic)- deriving newtype NFData+instance NFData Witness --- | Construct a 'ScriptPubKey' from a 'BS.ByteString'.+-- | Construct a t'Witness', failing above 65535 bytes. The contents+-- aren't checked. ----- Accepts any length; validation of script structure is left to higher--- layers.-scriptPubKey :: BS.ByteString -> ScriptPubKey-scriptPubKey = ScriptPubKey-{-# INLINE scriptPubKey #-}+-- >>> 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 #-} --- | Extract the underlying 'BS.ByteString' from a 'ScriptPubKey'.-unScriptPubKey :: ScriptPubKey -> BS.ByteString-unScriptPubKey (ScriptPubKey bs) = bs-{-# INLINE unScriptPubKey #-}+-- | The bytes of a t'Witness'.+un_witness :: Witness -> BS.ByteString+un_witness (Witness bs) = bs+{-# INLINE un_witness #-} --- chain types -----------------------------------------------------------------+-- | 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) --- | A 32-byte chain hash.------ Identifies the blockchain (typically the genesis block hash).--- Used in @open_channel@ to specify which chain the channel will reside on.-newtype ChainHash = ChainHash BS.ByteString- deriving stock (Eq, Ord, Show, Generic)- deriving newtype NFData+instance NFData OnionRoutingPacket --- | Construct a 'ChainHash' from a 32-byte 'BS.ByteString'.+-- | Construct an t'OnionRoutingPacket' from exactly 1366 bytes. ----- Returns 'Nothing' if the input is not exactly 32 bytes.-chainHash :: BS.ByteString -> Maybe ChainHash-chainHash !bs- | BS.length bs == chainHashLen = Just $! ChainHash bs- | otherwise = Nothing-{-# INLINABLE chainHash #-}+-- >>> 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 #-} --- | Extract the underlying 'BS.ByteString' from a 'ChainHash'.-unChainHash :: ChainHash -> BS.ByteString-unChainHash (ChainHash bs) = bs-{-# INLINE unChainHash #-}+-- | The bytes of an t'OnionRoutingPacket'.+un_onion_routing_packet :: OnionRoutingPacket -> BS.ByteString+un_onion_routing_packet (OnionRoutingPacket bs) = bs+{-# INLINE un_onion_routing_packet #-} --- | A short channel identifier (8 bytes).------ Encodes the block height (3 bytes), transaction index (3 bytes), and--- output index (2 bytes) of the funding transaction output.------ This is a compact representation for referencing channels in gossip--- and routing.-data ShortChannelId = ShortChannelId- { scidBytes :: {-# UNPACK #-} !Word64- }- deriving stock (Eq, Ord, Show, Generic)+-- | 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 ShortChannelId+instance NFData OnionHash --- | Construct a 'ShortChannelId' from block height, tx index, and--- output index.------ Returns 'Nothing' if any component exceeds its maximum value:------ * block height: max 16,777,215 (2^24 - 1)--- * tx index: max 16,777,215 (2^24 - 1)--- * output index: max 65,535 (2^16 - 1)+-- | Construct an t'OnionHash' from exactly 32 bytes. ----- >>> shortChannelId 800000 1234 0--- Just (ShortChannelId ...)-shortChannelId- :: Word32 -- ^ Block height (24 bits max)- -> Word32 -- ^ Transaction index (24 bits max)- -> Word16 -- ^ Output index- -> Maybe ShortChannelId-shortChannelId !blockHeight !txIndex !outputIndex- | blockHeight > 0xFFFFFF = Nothing- | txIndex > 0xFFFFFF = Nothing- | otherwise = Just $! ShortChannelId scid- where- !scid = (fromIntegral blockHeight `unsafeShiftL` 40)- .|. (fromIntegral txIndex `unsafeShiftL` 16)- .|. fromIntegral outputIndex-{-# INLINABLE shortChannelId #-}---- | Extract the block height from a 'ShortChannelId'.-scidBlockHeight :: ShortChannelId -> Word32-scidBlockHeight (ShortChannelId !w) =- fromIntegral $! (w `unsafeShiftR` 40) .&. 0xFFFFFF-{-# INLINE scidBlockHeight #-}+-- >>> 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 #-} --- | Extract the transaction index from a 'ShortChannelId'.-scidTxIndex :: ShortChannelId -> Word32-scidTxIndex (ShortChannelId !w) =- fromIntegral $! (w `unsafeShiftR` 16) .&. 0xFFFFFF-{-# INLINE scidTxIndex #-}+-- | The bytes of an t'OnionHash'.+un_onion_hash :: OnionHash -> BS.ByteString+un_onion_hash (OnionHash bs) = bs+{-# INLINE un_onion_hash #-} --- | Extract the output index from a 'ShortChannelId'.-scidOutputIndex :: ShortChannelId -> Word16-scidOutputIndex (ShortChannelId !w) = fromIntegral $! w .&. 0xFFFF-{-# INLINE scidOutputIndex #-}+-- | 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) --- protocol types --------------------------------------------------------------+instance NFData AttributionData --- | Feature bits (variable length).+-- | Construct an t'AttributionData' from exactly 920 bytes. ----- Encodes supported/required features. Even bits indicate required--- features; odd bits indicate optional features.-newtype FeatureBits = FeatureBits BS.ByteString- deriving stock (Eq, Ord, Show, Generic)- deriving newtype NFData+-- >>> 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 #-} --- | Construct 'FeatureBits' from a 'BS.ByteString'.------ Accepts any length; feature bit parsing is left to higher layers.-featureBits :: BS.ByteString -> FeatureBits-featureBits = FeatureBits-{-# INLINE featureBits #-}+-- | The bytes of an t'AttributionData'.+un_attribution_data :: AttributionData -> BS.ByteString+un_attribution_data (AttributionData bs) = bs+{-# INLINE un_attribution_data #-} --- | Extract the underlying 'BS.ByteString' from 'FeatureBits'.-unFeatureBits :: FeatureBits -> BS.ByteString-unFeatureBits (FeatureBits bs) = bs-{-# INLINE unFeatureBits #-}+-- | 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) --- | A 1366-byte onion routing packet.------ Contains encrypted routing information for HTLC forwarding, as--- specified in BOLT #4.-newtype OnionPacket = OnionPacket BS.ByteString- deriving stock (Eq, Ord, Show, Generic)- deriving newtype NFData+instance NFData FeeRange --- | Construct an 'OnionPacket' from a 1366-byte 'BS.ByteString'.------ 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 #-}+-- | 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) --- | Extract the underlying 'BS.ByteString' from an 'OnionPacket'.-unOnionPacket :: OnionPacket -> BS.ByteString-unOnionPacket (OnionPacket bs) = bs-{-# INLINE unOnionPacket #-}+instance NFData NextFunding
ppad-bolt2.cabal view
@@ -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 @@ 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 @@ -Wall exposed-modules: Lightning.Protocol.BOLT2+ other-modules: Lightning.Protocol.BOLT2.Codec Lightning.Protocol.BOLT2.Messages Lightning.Protocol.BOLT2.Types@@ -32,7 +33,9 @@ base >= 4.9 && < 5 , bytestring >= 0.9 && < 0.13 , deepseq >= 1.4 && < 1.6- , ppad-bolt1 >= 0.0.1 && < 0.1+ , 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@@ -41,7 +44,7 @@ main-is: Main.hs ghc-options:- -rtsopts -Wall -O2+ -rtsopts -Wall build-depends: base@@ -49,6 +52,8 @@ , ppad-base16 , ppad-bolt1 , ppad-bolt2+ , ppad-bolt9+ , ppad-tx , tasty , tasty-hunit , tasty-quickcheck@@ -58,31 +63,35 @@ 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
test/Main.hs view
@@ -2,1291 +2,1307 @@ module Main where -import qualified Data.ByteString as BS-import qualified Data.ByteString.Base16 as B16-import Data.Maybe (fromJust)-import Data.Word (Word8, Word16, Word32, Word64)-import Lightning.Protocol.BOLT1 (TlvStream, unsafeTlvStream)-import Lightning.Protocol.BOLT2-import Test.Tasty-import Test.Tasty.HUnit-import Test.Tasty.QuickCheck--main :: IO ()-main = defaultMain $ testGroup "ppad-bolt2" [- v1_establishment_tests- , v2_establishment_tests- , close_tests- , normal_operation_tests- , reestablish_tests- , error_tests- , property_tests- ]---- Test data helpers --------------------------------------------------------------- | Create a valid ChannelId (32 bytes).-testChannelId :: ChannelId-testChannelId = fromJust $ channelId (BS.replicate 32 0xab)---- | Create a valid ChainHash (32 bytes).-testChainHash :: ChainHash-testChainHash = fromJust $ chainHash (BS.replicate 32 0x01)---- | Create a valid Point (33 bytes).-testPoint :: Point-testPoint = fromJust $ point (BS.pack $ 0x02 : replicate 32 0xff)---- | Create a second valid Point (33 bytes).-testPoint2 :: Point-testPoint2 = fromJust $ point (BS.pack $ 0x03 : replicate 32 0xee)---- | Create a valid Signature (64 bytes).-testSignature :: Signature-testSignature = fromJust $ signature (BS.replicate 64 0xcc)---- | Create a valid TxId (32 bytes).-testTxId :: TxId-testTxId = fromJust $ txId (BS.replicate 32 0xdd)---- | Create a valid PaymentHash (32 bytes).-testPaymentHash :: PaymentHash-testPaymentHash = fromJust $ paymentHash (BS.replicate 32 0xaa)---- | Create a valid PaymentPreimage (32 bytes).-testPaymentPreimage :: PaymentPreimage-testPaymentPreimage = fromJust $ paymentPreimage (BS.replicate 32 0xbb)---- | Create a valid OnionPacket (1366 bytes).-testOnionPacket :: OnionPacket-testOnionPacket = fromJust $ onionPacket (BS.replicate 1366 0x00)---- | Create a valid Secret (32 bytes).-testSecret :: Secret-testSecret = fromJust $ secret (BS.replicate 32 0x11)---- | Empty TLV stream for messages.-emptyTlvs :: TlvStream-emptyTlvs = unsafeTlvStream []---- V1 Channel Establishment Tests ------------------------------------------------v1_establishment_tests :: TestTree-v1_establishment_tests = testGroup "V1 Channel Establishment" [- testGroup "OpenChannel" [- testCase "encode/decode roundtrip" $ do- let msg = OpenChannel- { openChannelChainHash = testChainHash- , openChannelTempChannelId = testChannelId- , openChannelFundingSatoshis = Satoshis 1000000- , openChannelPushMsat = MilliSatoshis 500000- , openChannelDustLimitSatoshis = Satoshis 546- , openChannelMaxHtlcValueInFlight = MilliSatoshis 100000000- , openChannelChannelReserveSat = Satoshis 10000- , openChannelHtlcMinimumMsat = MilliSatoshis 1000- , openChannelFeeratePerKw = 2500- , openChannelToSelfDelay = 144- , openChannelMaxAcceptedHtlcs = 483- , openChannelFundingPubkey = testPoint- , openChannelRevocationBasepoint = testPoint- , openChannelPaymentBasepoint = testPoint- , openChannelDelayedPaymentBase = testPoint- , openChannelHtlcBasepoint = testPoint- , openChannelFirstPerCommitPoint = testPoint- , openChannelChannelFlags = 0x01- , openChannelTlvs = emptyTlvs- }- encoded = encodeOpenChannel msg- case decodeOpenChannel encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "AcceptChannel" [- testCase "encode/decode roundtrip" $ do- let msg = AcceptChannel- { acceptChannelTempChannelId = testChannelId- , acceptChannelDustLimitSatoshis = Satoshis 546- , acceptChannelMaxHtlcValueInFlight = MilliSatoshis 100000000- , acceptChannelChannelReserveSat = Satoshis 10000- , acceptChannelHtlcMinimumMsat = MilliSatoshis 1000- , acceptChannelMinimumDepth = 3- , acceptChannelToSelfDelay = 144- , acceptChannelMaxAcceptedHtlcs = 483- , acceptChannelFundingPubkey = testPoint- , acceptChannelRevocationBasepoint = testPoint- , acceptChannelPaymentBasepoint = testPoint- , acceptChannelDelayedPaymentBase = testPoint- , acceptChannelHtlcBasepoint = testPoint- , acceptChannelFirstPerCommitPoint = testPoint- , acceptChannelTlvs = emptyTlvs- }- encoded = encodeAcceptChannel msg- case decodeAcceptChannel encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "FundingCreated" [- testCase "encode/decode roundtrip" $ do- let msg = FundingCreated- { fundingCreatedTempChannelId = testChannelId- , fundingCreatedFundingTxid = testTxId- , fundingCreatedFundingOutIdx = 0- , fundingCreatedSignature = testSignature- }- encoded = encodeFundingCreated msg- case decodeFundingCreated encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- , testCase "roundtrip with non-zero output index" $ do- let msg = FundingCreated- { fundingCreatedTempChannelId = testChannelId- , fundingCreatedFundingTxid = testTxId- , fundingCreatedFundingOutIdx = 42- , fundingCreatedSignature = testSignature- }- encoded = encodeFundingCreated msg- case decodeFundingCreated encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "FundingSigned" [- testCase "encode/decode roundtrip" $ do- let msg = FundingSigned- { fundingSignedChannelId = testChannelId- , fundingSignedSignature = testSignature- }- encoded = encodeFundingSigned msg- case decodeFundingSigned encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "ChannelReady" [- testCase "encode/decode roundtrip" $ do- let msg = ChannelReady- { channelReadyChannelId = testChannelId- , channelReadySecondPerCommitPoint = testPoint- , channelReadyTlvs = emptyTlvs- }- encoded = encodeChannelReady msg- case decodeChannelReady encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- ]---- V2 Channel Establishment (Interactive-tx) Tests ------------------------------v2_establishment_tests :: TestTree-v2_establishment_tests = testGroup "V2 Channel Establishment" [- testGroup "OpenChannel2" [- testCase "encode/decode roundtrip" $ do- let msg = OpenChannel2- { openChannel2ChainHash = testChainHash- , openChannel2TempChannelId = testChannelId- , openChannel2FundingFeeratePerkw = 2500- , openChannel2CommitFeeratePerkw = 2000- , openChannel2FundingSatoshis = Satoshis 1000000- , openChannel2DustLimitSatoshis = Satoshis 546- , openChannel2MaxHtlcValueInFlight = MilliSatoshis 100000000- , openChannel2HtlcMinimumMsat = MilliSatoshis 1000- , openChannel2ToSelfDelay = 144- , openChannel2MaxAcceptedHtlcs = 483- , openChannel2Locktime = 0- , openChannel2FundingPubkey = testPoint- , openChannel2RevocationBasepoint = testPoint- , openChannel2PaymentBasepoint = testPoint- , openChannel2DelayedPaymentBase = testPoint- , openChannel2HtlcBasepoint = testPoint- , openChannel2FirstPerCommitPoint = testPoint- , openChannel2SecondPerCommitPoint = testPoint2- , openChannel2ChannelFlags = 0x00- , openChannel2Tlvs = emptyTlvs- }- encoded = encodeOpenChannel2 msg- case decodeOpenChannel2 encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "AcceptChannel2" [- testCase "encode/decode roundtrip" $ do- let msg = AcceptChannel2- { acceptChannel2TempChannelId = testChannelId- , acceptChannel2FundingSatoshis = Satoshis 500000- , acceptChannel2DustLimitSatoshis = Satoshis 546- , acceptChannel2MaxHtlcValueInFlight = MilliSatoshis 100000000- , acceptChannel2HtlcMinimumMsat = MilliSatoshis 1000- , acceptChannel2MinimumDepth = 3- , acceptChannel2ToSelfDelay = 144- , acceptChannel2MaxAcceptedHtlcs = 483- , acceptChannel2FundingPubkey = testPoint- , acceptChannel2RevocationBasepoint = testPoint- , acceptChannel2PaymentBasepoint = testPoint- , acceptChannel2DelayedPaymentBase = testPoint- , acceptChannel2HtlcBasepoint = testPoint- , acceptChannel2FirstPerCommitPoint = testPoint- , acceptChannel2SecondPerCommitPoint = testPoint2- , acceptChannel2Tlvs = emptyTlvs- }- encoded = encodeAcceptChannel2 msg- case decodeAcceptChannel2 encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "TxAddInput" [- testCase "encode/decode roundtrip" $ do- let msg = TxAddInput- { txAddInputChannelId = testChannelId- , txAddInputSerialId = 12345- , txAddInputPrevTx = BS.pack [0x01, 0x02, 0x03, 0x04]- , txAddInputPrevVout = 0- , txAddInputSequence = 0xfffffffe- }- case encodeTxAddInput msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeTxAddInput encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- , testCase "roundtrip with empty prevTx" $ do- let msg = TxAddInput- { txAddInputChannelId = testChannelId- , txAddInputSerialId = 0- , txAddInputPrevTx = BS.empty- , txAddInputPrevVout = 0- , txAddInputSequence = 0- }- case encodeTxAddInput msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeTxAddInput encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "TxAddOutput" [- testCase "encode/decode roundtrip" $ do- let msg = TxAddOutput- { txAddOutputChannelId = testChannelId- , txAddOutputSerialId = 54321- , txAddOutputSats = Satoshis 100000- , txAddOutputScript = scriptPubKey (BS.pack [0x00, 0x14] <>- BS.replicate 20 0xaa)- }- case encodeTxAddOutput msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeTxAddOutput encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "TxRemoveInput" [- testCase "encode/decode roundtrip" $ do- let msg = TxRemoveInput- { txRemoveInputChannelId = testChannelId- , txRemoveInputSerialId = 12345- }- encoded = encodeTxRemoveInput msg- case decodeTxRemoveInput encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "TxRemoveOutput" [- testCase "encode/decode roundtrip" $ do- let msg = TxRemoveOutput- { txRemoveOutputChannelId = testChannelId- , txRemoveOutputSerialId = 54321- }- encoded = encodeTxRemoveOutput msg- case decodeTxRemoveOutput encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "TxComplete" [- testCase "encode/decode roundtrip" $ do- let msg = TxComplete { txCompleteChannelId = testChannelId }- encoded = encodeTxComplete msg- case decodeTxComplete encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "TxSignatures" [- testCase "encode/decode with no witnesses" $ do- let msg = TxSignatures- { txSignaturesChannelId = testChannelId- , txSignaturesTxid = testTxId- , txSignaturesWitnesses = []- }- case encodeTxSignatures msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeTxSignatures encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- , testCase "encode/decode with multiple witnesses" $ do- let w1 = Witness (BS.pack [0x30, 0x44] <> BS.replicate 68 0xaa)- w2 = Witness (BS.pack [0x02] <> BS.replicate 32 0xbb)- msg = TxSignatures- { txSignaturesChannelId = testChannelId- , txSignaturesTxid = testTxId- , txSignaturesWitnesses = [w1, w2]- }- case encodeTxSignatures msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeTxSignatures encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "TxInitRbf" [- testCase "encode/decode roundtrip" $ do- let msg = TxInitRbf- { txInitRbfChannelId = testChannelId- , txInitRbfLocktime = 800000- , txInitRbfFeerate = 3000- , txInitRbfTlvs = emptyTlvs- }- encoded = encodeTxInitRbf msg- case decodeTxInitRbf encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "TxAckRbf" [- testCase "encode/decode roundtrip" $ do- let msg = TxAckRbf- { txAckRbfChannelId = testChannelId- , txAckRbfTlvs = emptyTlvs- }- encoded = encodeTxAckRbf msg- case decodeTxAckRbf encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "TxAbort" [- testCase "encode/decode roundtrip" $ do- let msg = TxAbort- { txAbortChannelId = testChannelId- , txAbortData = "transaction abort reason"- }- case encodeTxAbort msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeTxAbort encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- , testCase "roundtrip with empty data" $ do- let msg = TxAbort- { txAbortChannelId = testChannelId- , txAbortData = BS.empty- }- case encodeTxAbort msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeTxAbort encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- ]---- Channel Close Tests -----------------------------------------------------------close_tests :: TestTree-close_tests = testGroup "Channel Close" [- testGroup "Stfu" [- testCase "encode/decode initiator=1" $ do- let msg = Stfu- { stfuChannelId = testChannelId- , stfuInitiator = 1- }- encoded = encodeStfu msg- case decodeStfu encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- , testCase "encode/decode initiator=0" $ do- let msg = Stfu- { stfuChannelId = testChannelId- , stfuInitiator = 0- }- encoded = encodeStfu msg- case decodeStfu encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "Shutdown" [- testCase "encode/decode with P2WPKH script" $ do- let script = scriptPubKey (BS.pack [0x00, 0x14] <>- BS.replicate 20 0xaa)- msg = Shutdown- { shutdownChannelId = testChannelId- , shutdownScriptPubkey = script- }- case encodeShutdown msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeShutdown encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- , testCase "encode/decode with P2WSH script" $ do- let script = scriptPubKey (BS.pack [0x00, 0x20] <>- BS.replicate 32 0xbb)- msg = Shutdown- { shutdownChannelId = testChannelId- , shutdownScriptPubkey = script- }- case encodeShutdown msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeShutdown encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "ClosingSigned" [- testCase "encode/decode roundtrip" $ do- let msg = ClosingSigned- { closingSignedChannelId = testChannelId- , closingSignedFeeSatoshis = Satoshis 1000- , closingSignedSignature = testSignature- , closingSignedTlvs = emptyTlvs- }- encoded = encodeClosingSigned msg- case decodeClosingSigned encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "ClosingComplete" [- testCase "encode/decode roundtrip" $ do- let closerScript = scriptPubKey (BS.pack [0x00, 0x14] <>- BS.replicate 20 0xcc)- closeeScript = scriptPubKey (BS.pack [0x00, 0x14] <>- BS.replicate 20 0xdd)- msg = ClosingComplete- { closingCompleteChannelId = testChannelId- , closingCompleteCloserScript = closerScript- , closingCompleteCloseeScript = closeeScript- , closingCompleteFeeSatoshis = Satoshis 500- , closingCompleteLocktime = 0- , closingCompleteTlvs = emptyTlvs- }- case encodeClosingComplete msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeClosingComplete encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "ClosingSig" [- testCase "encode/decode roundtrip" $ do- let closerScript = scriptPubKey (BS.pack [0x00, 0x14] <>- BS.replicate 20 0xee)- closeeScript = scriptPubKey (BS.pack [0x00, 0x14] <>- BS.replicate 20 0xff)- msg = ClosingSig- { closingSigChannelId = testChannelId- , closingSigCloserScript = closerScript- , closingSigCloseeScript = closeeScript- , closingSigFeeSatoshis = Satoshis 500- , closingSigLocktime = 100- , closingSigTlvs = emptyTlvs- }- case encodeClosingSig msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeClosingSig encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- ]---- Normal Operation Tests --------------------------------------------------------normal_operation_tests :: TestTree-normal_operation_tests = testGroup "Normal Operation" [- testGroup "UpdateAddHtlc" [- testCase "encode/decode roundtrip" $ do- let msg = UpdateAddHtlc- { updateAddHtlcChannelId = testChannelId- , updateAddHtlcId = 0- , updateAddHtlcAmountMsat = MilliSatoshis 10000000- , updateAddHtlcPaymentHash = testPaymentHash- , updateAddHtlcCltvExpiry = 800144- , updateAddHtlcOnionPacket = testOnionPacket- , updateAddHtlcTlvs = emptyTlvs- }- encoded = encodeUpdateAddHtlc msg- case decodeUpdateAddHtlc encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "UpdateFulfillHtlc" [- testCase "encode/decode roundtrip" $ do- let msg = UpdateFulfillHtlc- { updateFulfillHtlcChannelId = testChannelId- , updateFulfillHtlcId = 42- , updateFulfillHtlcPaymentPreimage = testPaymentPreimage- , updateFulfillHtlcTlvs = emptyTlvs- }- encoded = encodeUpdateFulfillHtlc msg- case decodeUpdateFulfillHtlc encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "UpdateFailHtlc" [- testCase "encode/decode roundtrip" $ do- let msg = UpdateFailHtlc- { updateFailHtlcChannelId = testChannelId- , updateFailHtlcId = 42- , updateFailHtlcReason = BS.replicate 32 0xaa- , updateFailHtlcTlvs = emptyTlvs- }- case encodeUpdateFailHtlc msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeUpdateFailHtlc encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- , testCase "roundtrip with empty reason" $ do- let msg = UpdateFailHtlc- { updateFailHtlcChannelId = testChannelId- , updateFailHtlcId = 0- , updateFailHtlcReason = BS.empty- , updateFailHtlcTlvs = emptyTlvs- }- case encodeUpdateFailHtlc msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeUpdateFailHtlc encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "UpdateFailMalformedHtlc" [- testCase "encode/decode roundtrip" $ do- let msg = UpdateFailMalformedHtlc- { updateFailMalformedHtlcChannelId = testChannelId- , updateFailMalformedHtlcId = 42- , updateFailMalformedHtlcSha256Onion = testPaymentHash- , updateFailMalformedHtlcFailureCode = 0x8002- }- encoded = encodeUpdateFailMalformedHtlc msg- case decodeUpdateFailMalformedHtlc encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "CommitmentSigned" [- testCase "encode/decode with no HTLC signatures" $ do- let msg = CommitmentSigned- { commitmentSignedChannelId = testChannelId- , commitmentSignedSignature = testSignature- , commitmentSignedHtlcSignatures = []- }- case encodeCommitmentSigned msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeCommitmentSigned encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- , testCase "encode/decode with HTLC signatures" $ do- let sig2 = fromJust $ signature (BS.replicate 64 0xdd)- sig3 = fromJust $ signature (BS.replicate 64 0xee)- msg = CommitmentSigned- { commitmentSignedChannelId = testChannelId- , commitmentSignedSignature = testSignature- , commitmentSignedHtlcSignatures = [sig2, sig3]- }- case encodeCommitmentSigned msg of- Left e -> assertFailure $ "encode failed: " ++ show e- Right encoded -> case decodeCommitmentSigned encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "RevokeAndAck" [- testCase "encode/decode roundtrip" $ do- let msg = RevokeAndAck- { revokeAndAckChannelId = testChannelId- , revokeAndAckPerCommitmentSecret = testSecret- , revokeAndAckNextPerCommitPoint = testPoint- }- encoded = encodeRevokeAndAck msg- case decodeRevokeAndAck encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- , testGroup "UpdateFee" [- testCase "encode/decode roundtrip" $ do- let msg = UpdateFee- { updateFeeChannelId = testChannelId- , updateFeeFeeratePerKw = 5000- }- encoded = encodeUpdateFee msg- case decodeUpdateFee encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]- ]---- Reestablish Tests -------------------------------------------------------------reestablish_tests :: TestTree-reestablish_tests = testGroup "Channel Reestablish" [- testCase "encode/decode roundtrip" $ do- let sec = fromJust $ secret (BS.replicate 32 0x22)- msg = ChannelReestablish- { channelReestablishChannelId = testChannelId- , channelReestablishNextCommitNum = 5- , channelReestablishNextRevocationNum = 4- , channelReestablishYourLastCommitSecret = sec- , channelReestablishMyCurrentCommitPoint = testPoint- , channelReestablishTlvs = emptyTlvs- }- encoded = encodeChannelReestablish msg- case decodeChannelReestablish encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- , testCase "roundtrip with zero counters" $ do- let sec = fromJust $ secret (BS.replicate 32 0x00)- msg = ChannelReestablish- { channelReestablishChannelId = testChannelId- , channelReestablishNextCommitNum = 1- , channelReestablishNextRevocationNum = 0- , channelReestablishYourLastCommitSecret = sec- , channelReestablishMyCurrentCommitPoint = testPoint- , channelReestablishTlvs = emptyTlvs- }- encoded = encodeChannelReestablish msg- case decodeChannelReestablish encoded of- Right (decoded, _) -> decoded @?= msg- Left e -> assertFailure $ "decode failed: " ++ show e- ]---- Error Condition Tests ---------------------------------------------------------error_tests :: TestTree-error_tests = testGroup "Error Conditions" [- testGroup "Insufficient Bytes" [- testCase "decodeOpenChannel empty" $ do- case decodeOpenChannel BS.empty of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeOpenChannel too short" $ do- case decodeOpenChannel (BS.replicate 100 0x00) of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeAcceptChannel too short" $ do- case decodeAcceptChannel (BS.replicate 10 0x00) of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeFundingCreated too short" $ do- case decodeFundingCreated (BS.replicate 50 0x00) of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeFundingSigned too short" $ do- case decodeFundingSigned (BS.replicate 30 0x00) of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeChannelReady too short" $ do- case decodeChannelReady (BS.replicate 32 0x00) of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeStfu too short" $ do- case decodeStfu (BS.replicate 31 0x00) of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeShutdown too short" $ do- case decodeShutdown (BS.replicate 32 0x00) of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeUpdateAddHtlc too short" $ do- case decodeUpdateAddHtlc (BS.replicate 100 0x00) of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeCommitmentSigned too short" $ do- case decodeCommitmentSigned (BS.replicate 90 0x00) of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeRevokeAndAck too short" $ do- case decodeRevokeAndAck (BS.replicate 60 0x00) of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeTxSignatures too short" $ do- case decodeTxSignatures (BS.replicate 60 0x00) of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- ]- , testGroup "EncodeError - Length Overflow" [- testCase "encodeShutdown with oversized script" $ do- let script = scriptPubKey (BS.replicate 70000 0x00)- msg = Shutdown- { shutdownChannelId = testChannelId- , shutdownScriptPubkey = script- }- case encodeShutdown msg of- Left EncodeLengthOverflow -> pure ()- other -> assertFailure $ "expected overflow: " ++ show other- , testCase "encodeClosingComplete with oversized closer script" $ do- let oversizedScript = scriptPubKey (BS.replicate 70000 0x00)- normalScript = scriptPubKey (BS.replicate 22 0x00)- msg = ClosingComplete- { closingCompleteChannelId = testChannelId- , closingCompleteCloserScript = oversizedScript- , closingCompleteCloseeScript = normalScript- , closingCompleteFeeSatoshis = Satoshis 500- , closingCompleteLocktime = 0- , closingCompleteTlvs = emptyTlvs- }- case encodeClosingComplete msg of- Left EncodeLengthOverflow -> pure ()- other -> assertFailure $ "expected overflow: " ++ show other- , testCase "encodeClosingComplete with oversized closee script" $ do- let normalScript = scriptPubKey (BS.replicate 22 0x00)- oversizedScript = scriptPubKey (BS.replicate 70000 0x00)- msg = ClosingComplete- { closingCompleteChannelId = testChannelId- , closingCompleteCloserScript = normalScript- , closingCompleteCloseeScript = oversizedScript- , closingCompleteFeeSatoshis = Satoshis 500- , closingCompleteLocktime = 0- , closingCompleteTlvs = emptyTlvs- }- case encodeClosingComplete msg of- Left EncodeLengthOverflow -> pure ()- other -> assertFailure $ "expected overflow: " ++ show other- , testCase "encodeClosingSig with oversized script" $ do- let oversizedScript = scriptPubKey (BS.replicate 70000 0x00)- normalScript = scriptPubKey (BS.replicate 22 0x00)- msg = ClosingSig- { closingSigChannelId = testChannelId- , closingSigCloserScript = oversizedScript- , closingSigCloseeScript = normalScript- , closingSigFeeSatoshis = Satoshis 500- , closingSigLocktime = 0- , closingSigTlvs = emptyTlvs- }- case encodeClosingSig msg of- Left EncodeLengthOverflow -> pure ()- other -> assertFailure $ "expected overflow: " ++ show other- ]- , testGroup "Invalid Field Length" [- testCase "decodeShutdown with invalid script length" $ do- -- channel_id (32 bytes) + script length (2 bytes) claiming more- let encoded = BS.replicate 32 0xab <>- BS.pack [0xff, 0xff] <> -- claims 65535 bytes- BS.replicate 10 0x00 -- only 10 bytes- case decodeShutdown encoded of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeTxAddInput with invalid prevTx length" $ do- -- channel_id (32) + serial_id (8) + len (2) claiming more- let encoded = BS.replicate 32 0xab <>- BS.replicate 8 0x00 <>- BS.pack [0xff, 0xff] <> -- claims 65535 bytes- BS.replicate 10 0x00 -- only 10 bytes- case decodeTxAddInput encoded of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- , testCase "decodeUpdateFailHtlc with invalid reason length" $ do- -- channel_id (32) + htlc_id (8) + len (2) claiming more- let encoded = BS.replicate 32 0xab <>- BS.replicate 8 0x00 <>- BS.pack [0xff, 0xff] <> -- claims 65535 bytes- BS.replicate 10 0x00 -- only 10 bytes- case decodeUpdateFailHtlc encoded of- Left DecodeInsufficientBytes -> pure ()- other -> assertFailure $ "expected insufficient: " ++ show other- ]- ]---- Property Tests ----------------------------------------------------------------property_tests :: TestTree-property_tests = testGroup "Properties" [- testProperty "OpenChannel roundtrip" propOpenChannelRoundtrip- , testProperty "AcceptChannel roundtrip" propAcceptChannelRoundtrip- , testProperty "FundingCreated roundtrip" propFundingCreatedRoundtrip- , testProperty "FundingSigned roundtrip" propFundingSignedRoundtrip- , testProperty "ChannelReady roundtrip" propChannelReadyRoundtrip- , testProperty "OpenChannel2 roundtrip" propOpenChannel2Roundtrip- , testProperty "AcceptChannel2 roundtrip" propAcceptChannel2Roundtrip- , testProperty "TxAddInput roundtrip" propTxAddInputRoundtrip- , testProperty "TxAddOutput roundtrip" propTxAddOutputRoundtrip- , testProperty "TxRemoveInput roundtrip" propTxRemoveInputRoundtrip- , testProperty "TxRemoveOutput roundtrip" propTxRemoveOutputRoundtrip- , testProperty "TxComplete roundtrip" propTxCompleteRoundtrip- , testProperty "TxSignatures roundtrip" propTxSignaturesRoundtrip- , testProperty "TxInitRbf roundtrip" propTxInitRbfRoundtrip- , testProperty "TxAckRbf roundtrip" propTxAckRbfRoundtrip- , testProperty "TxAbort roundtrip" propTxAbortRoundtrip- , testProperty "Stfu roundtrip" propStfuRoundtrip- , testProperty "Shutdown roundtrip" propShutdownRoundtrip- , testProperty "ClosingSigned roundtrip" propClosingSignedRoundtrip- , testProperty "ClosingComplete roundtrip" propClosingCompleteRoundtrip- , testProperty "ClosingSig roundtrip" propClosingSigRoundtrip- , testProperty "UpdateAddHtlc roundtrip" propUpdateAddHtlcRoundtrip- , testProperty "UpdateFulfillHtlc roundtrip" propUpdateFulfillHtlcRoundtrip- , testProperty "UpdateFailHtlc roundtrip" propUpdateFailHtlcRoundtrip- , testProperty "UpdateFailMalformedHtlc roundtrip"- propUpdateFailMalformedHtlcRoundtrip- , testProperty "CommitmentSigned roundtrip" propCommitmentSignedRoundtrip- , testProperty "RevokeAndAck roundtrip" propRevokeAndAckRoundtrip- , testProperty "UpdateFee roundtrip" propUpdateFeeRoundtrip- , testProperty "ChannelReestablish roundtrip" propChannelReestablishRoundtrip- ]---- Property: OpenChannel roundtrip-propOpenChannelRoundtrip :: Property-propOpenChannelRoundtrip = property $ do- let msg = OpenChannel- { openChannelChainHash = testChainHash- , openChannelTempChannelId = testChannelId- , openChannelFundingSatoshis = Satoshis 1000000- , openChannelPushMsat = MilliSatoshis 500000- , openChannelDustLimitSatoshis = Satoshis 546- , openChannelMaxHtlcValueInFlight = MilliSatoshis 100000000- , openChannelChannelReserveSat = Satoshis 10000- , openChannelHtlcMinimumMsat = MilliSatoshis 1000- , openChannelFeeratePerKw = 2500- , openChannelToSelfDelay = 144- , openChannelMaxAcceptedHtlcs = 483- , openChannelFundingPubkey = testPoint- , openChannelRevocationBasepoint = testPoint- , openChannelPaymentBasepoint = testPoint- , openChannelDelayedPaymentBase = testPoint- , openChannelHtlcBasepoint = testPoint- , openChannelFirstPerCommitPoint = testPoint- , openChannelChannelFlags = 0x01- , openChannelTlvs = emptyTlvs- }- encoded = encodeOpenChannel msg- case decodeOpenChannel encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: AcceptChannel roundtrip-propAcceptChannelRoundtrip :: Property-propAcceptChannelRoundtrip = property $ do- let msg = AcceptChannel- { acceptChannelTempChannelId = testChannelId- , acceptChannelDustLimitSatoshis = Satoshis 546- , acceptChannelMaxHtlcValueInFlight = MilliSatoshis 100000000- , acceptChannelChannelReserveSat = Satoshis 10000- , acceptChannelHtlcMinimumMsat = MilliSatoshis 1000- , acceptChannelMinimumDepth = 3- , acceptChannelToSelfDelay = 144- , acceptChannelMaxAcceptedHtlcs = 483- , acceptChannelFundingPubkey = testPoint- , acceptChannelRevocationBasepoint = testPoint- , acceptChannelPaymentBasepoint = testPoint- , acceptChannelDelayedPaymentBase = testPoint- , acceptChannelHtlcBasepoint = testPoint- , acceptChannelFirstPerCommitPoint = testPoint- , acceptChannelTlvs = emptyTlvs- }- encoded = encodeAcceptChannel msg- case decodeAcceptChannel encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: FundingCreated roundtrip-propFundingCreatedRoundtrip :: Word16 -> Property-propFundingCreatedRoundtrip outIdx = property $ do- let msg = FundingCreated- { fundingCreatedTempChannelId = testChannelId- , fundingCreatedFundingTxid = testTxId- , fundingCreatedFundingOutIdx = outIdx- , fundingCreatedSignature = testSignature- }- encoded = encodeFundingCreated msg- case decodeFundingCreated encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: FundingSigned roundtrip-propFundingSignedRoundtrip :: Property-propFundingSignedRoundtrip = property $ do- let msg = FundingSigned- { fundingSignedChannelId = testChannelId- , fundingSignedSignature = testSignature- }- encoded = encodeFundingSigned msg- case decodeFundingSigned encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: ChannelReady roundtrip-propChannelReadyRoundtrip :: Property-propChannelReadyRoundtrip = property $ do- let msg = ChannelReady- { channelReadyChannelId = testChannelId- , channelReadySecondPerCommitPoint = testPoint- , channelReadyTlvs = emptyTlvs- }- encoded = encodeChannelReady msg- case decodeChannelReady encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: OpenChannel2 roundtrip-propOpenChannel2Roundtrip :: Property-propOpenChannel2Roundtrip = property $ do- let msg = OpenChannel2- { openChannel2ChainHash = testChainHash- , openChannel2TempChannelId = testChannelId- , openChannel2FundingFeeratePerkw = 2500- , openChannel2CommitFeeratePerkw = 2000- , openChannel2FundingSatoshis = Satoshis 1000000- , openChannel2DustLimitSatoshis = Satoshis 546- , openChannel2MaxHtlcValueInFlight = MilliSatoshis 100000000- , openChannel2HtlcMinimumMsat = MilliSatoshis 1000- , openChannel2ToSelfDelay = 144- , openChannel2MaxAcceptedHtlcs = 483- , openChannel2Locktime = 0- , openChannel2FundingPubkey = testPoint- , openChannel2RevocationBasepoint = testPoint- , openChannel2PaymentBasepoint = testPoint- , openChannel2DelayedPaymentBase = testPoint- , openChannel2HtlcBasepoint = testPoint- , openChannel2FirstPerCommitPoint = testPoint- , openChannel2SecondPerCommitPoint = testPoint2- , openChannel2ChannelFlags = 0x00- , openChannel2Tlvs = emptyTlvs- }- encoded = encodeOpenChannel2 msg- case decodeOpenChannel2 encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: AcceptChannel2 roundtrip-propAcceptChannel2Roundtrip :: Property-propAcceptChannel2Roundtrip = property $ do- let msg = AcceptChannel2- { acceptChannel2TempChannelId = testChannelId- , acceptChannel2FundingSatoshis = Satoshis 500000- , acceptChannel2DustLimitSatoshis = Satoshis 546- , acceptChannel2MaxHtlcValueInFlight = MilliSatoshis 100000000- , acceptChannel2HtlcMinimumMsat = MilliSatoshis 1000- , acceptChannel2MinimumDepth = 3- , acceptChannel2ToSelfDelay = 144- , acceptChannel2MaxAcceptedHtlcs = 483- , acceptChannel2FundingPubkey = testPoint- , acceptChannel2RevocationBasepoint = testPoint- , acceptChannel2PaymentBasepoint = testPoint- , acceptChannel2DelayedPaymentBase = testPoint- , acceptChannel2HtlcBasepoint = testPoint- , acceptChannel2FirstPerCommitPoint = testPoint- , acceptChannel2SecondPerCommitPoint = testPoint2- , acceptChannel2Tlvs = emptyTlvs- }- encoded = encodeAcceptChannel2 msg- case decodeAcceptChannel2 encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: TxAddInput roundtrip with varying data-propTxAddInputRoundtrip :: [Word8] -> Word32 -> Word32 -> Property-propTxAddInputRoundtrip prevTxBytes vout seqNum = property $ do- let prevTx = BS.pack (take 1000 prevTxBytes) -- limit size- msg = TxAddInput- { txAddInputChannelId = testChannelId- , txAddInputSerialId = 12345- , txAddInputPrevTx = prevTx- , txAddInputPrevVout = vout- , txAddInputSequence = seqNum- }- case encodeTxAddInput msg of- Left _ -> False- Right encoded -> case decodeTxAddInput encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: TxAddOutput roundtrip-propTxAddOutputRoundtrip :: Word64 -> [Word8] -> Property-propTxAddOutputRoundtrip sats scriptBytes = property $ do- let script = scriptPubKey (BS.pack (take 100 scriptBytes))- msg = TxAddOutput- { txAddOutputChannelId = testChannelId- , txAddOutputSerialId = 54321- , txAddOutputSats = Satoshis sats- , txAddOutputScript = script- }- case encodeTxAddOutput msg of- Left _ -> False- Right encoded -> case decodeTxAddOutput encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: TxRemoveInput roundtrip-propTxRemoveInputRoundtrip :: Word64 -> Property-propTxRemoveInputRoundtrip serialId = property $ do- let msg = TxRemoveInput- { txRemoveInputChannelId = testChannelId- , txRemoveInputSerialId = serialId- }- encoded = encodeTxRemoveInput msg- case decodeTxRemoveInput encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: TxRemoveOutput roundtrip-propTxRemoveOutputRoundtrip :: Word64 -> Property-propTxRemoveOutputRoundtrip serialId = property $ do- let msg = TxRemoveOutput- { txRemoveOutputChannelId = testChannelId- , txRemoveOutputSerialId = serialId- }- encoded = encodeTxRemoveOutput msg- case decodeTxRemoveOutput encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: TxComplete roundtrip-propTxCompleteRoundtrip :: Property-propTxCompleteRoundtrip = property $ do- let msg = TxComplete { txCompleteChannelId = testChannelId }- encoded = encodeTxComplete msg- case decodeTxComplete encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: TxSignatures roundtrip with varying witnesses-propTxSignaturesRoundtrip :: [[Word8]] -> Property-propTxSignaturesRoundtrip witnessList = property $ do- let wits = map (Witness . BS.pack . take 200) (take 10 witnessList)- msg = TxSignatures- { txSignaturesChannelId = testChannelId- , txSignaturesTxid = testTxId- , txSignaturesWitnesses = wits- }- case encodeTxSignatures msg of- Left _ -> False- Right encoded -> case decodeTxSignatures encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: TxInitRbf roundtrip-propTxInitRbfRoundtrip :: Word32 -> Word32 -> Property-propTxInitRbfRoundtrip locktime feerate = property $ do- let msg = TxInitRbf- { txInitRbfChannelId = testChannelId- , txInitRbfLocktime = locktime- , txInitRbfFeerate = feerate- , txInitRbfTlvs = emptyTlvs- }- encoded = encodeTxInitRbf msg- case decodeTxInitRbf encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: TxAckRbf roundtrip-propTxAckRbfRoundtrip :: Property-propTxAckRbfRoundtrip = property $ do- let msg = TxAckRbf- { txAckRbfChannelId = testChannelId- , txAckRbfTlvs = emptyTlvs- }- encoded = encodeTxAckRbf msg- case decodeTxAckRbf encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: TxAbort roundtrip-propTxAbortRoundtrip :: [Word8] -> Property-propTxAbortRoundtrip dataBytes = property $ do- let abortData = BS.pack (take 1000 dataBytes)- msg = TxAbort- { txAbortChannelId = testChannelId- , txAbortData = abortData- }- case encodeTxAbort msg of- Left _ -> False- Right encoded -> case decodeTxAbort encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: Stfu roundtrip-propStfuRoundtrip :: Word8 -> Property-propStfuRoundtrip initiator = property $ do- let msg = Stfu- { stfuChannelId = testChannelId- , stfuInitiator = initiator- }- encoded = encodeStfu msg- case decodeStfu encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: Shutdown roundtrip-propShutdownRoundtrip :: [Word8] -> Property-propShutdownRoundtrip scriptBytes = property $ do- let script = scriptPubKey (BS.pack (take 100 scriptBytes))- msg = Shutdown- { shutdownChannelId = testChannelId- , shutdownScriptPubkey = script- }- case encodeShutdown msg of- Left _ -> False- Right encoded -> case decodeShutdown encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: ClosingSigned roundtrip-propClosingSignedRoundtrip :: Word64 -> Property-propClosingSignedRoundtrip feeSats = property $ do- let msg = ClosingSigned- { closingSignedChannelId = testChannelId- , closingSignedFeeSatoshis = Satoshis feeSats- , closingSignedSignature = testSignature- , closingSignedTlvs = emptyTlvs- }- encoded = encodeClosingSigned msg- case decodeClosingSigned encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: ClosingComplete roundtrip-propClosingCompleteRoundtrip :: Word64 -> Word32 -> Property-propClosingCompleteRoundtrip feeSats locktime = property $ do- let closerScript = scriptPubKey (BS.pack [0x00, 0x14] <>- BS.replicate 20 0xcc)- closeeScript = scriptPubKey (BS.pack [0x00, 0x14] <>- BS.replicate 20 0xdd)- msg = ClosingComplete- { closingCompleteChannelId = testChannelId- , closingCompleteCloserScript = closerScript- , closingCompleteCloseeScript = closeeScript- , closingCompleteFeeSatoshis = Satoshis feeSats- , closingCompleteLocktime = locktime- , closingCompleteTlvs = emptyTlvs- }- case encodeClosingComplete msg of- Left _ -> False- Right encoded -> case decodeClosingComplete encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: ClosingSig roundtrip-propClosingSigRoundtrip :: Word64 -> Word32 -> Property-propClosingSigRoundtrip feeSats locktime = property $ do- let closerScript = scriptPubKey (BS.pack [0x00, 0x14] <>- BS.replicate 20 0xee)- closeeScript = scriptPubKey (BS.pack [0x00, 0x14] <>- BS.replicate 20 0xff)- msg = ClosingSig- { closingSigChannelId = testChannelId- , closingSigCloserScript = closerScript- , closingSigCloseeScript = closeeScript- , closingSigFeeSatoshis = Satoshis feeSats- , closingSigLocktime = locktime- , closingSigTlvs = emptyTlvs- }- case encodeClosingSig msg of- Left _ -> False- Right encoded -> case decodeClosingSig encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: UpdateAddHtlc roundtrip-propUpdateAddHtlcRoundtrip :: Word64 -> Word64 -> Word32 -> Property-propUpdateAddHtlcRoundtrip htlcId amountMsat cltvExpiry = property $ do- let msg = UpdateAddHtlc- { updateAddHtlcChannelId = testChannelId- , updateAddHtlcId = htlcId- , updateAddHtlcAmountMsat = MilliSatoshis amountMsat- , updateAddHtlcPaymentHash = testPaymentHash- , updateAddHtlcCltvExpiry = cltvExpiry- , updateAddHtlcOnionPacket = testOnionPacket- , updateAddHtlcTlvs = emptyTlvs- }- encoded = encodeUpdateAddHtlc msg- case decodeUpdateAddHtlc encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: UpdateFulfillHtlc roundtrip-propUpdateFulfillHtlcRoundtrip :: Word64 -> Property-propUpdateFulfillHtlcRoundtrip htlcId = property $ do- let msg = UpdateFulfillHtlc- { updateFulfillHtlcChannelId = testChannelId- , updateFulfillHtlcId = htlcId- , updateFulfillHtlcPaymentPreimage = testPaymentPreimage- , updateFulfillHtlcTlvs = emptyTlvs- }- encoded = encodeUpdateFulfillHtlc msg- case decodeUpdateFulfillHtlc encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: UpdateFailHtlc roundtrip-propUpdateFailHtlcRoundtrip :: Word64 -> [Word8] -> Property-propUpdateFailHtlcRoundtrip htlcId reasonBytes = property $ do- let failReason = BS.pack (take 1000 reasonBytes)- msg = UpdateFailHtlc- { updateFailHtlcChannelId = testChannelId- , updateFailHtlcId = htlcId- , updateFailHtlcReason = failReason- , updateFailHtlcTlvs = emptyTlvs- }- case encodeUpdateFailHtlc msg of- Left _ -> False- Right encoded -> case decodeUpdateFailHtlc encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: UpdateFailMalformedHtlc roundtrip-propUpdateFailMalformedHtlcRoundtrip :: Word64 -> Word16 -> Property-propUpdateFailMalformedHtlcRoundtrip htlcId failCode = property $ do- let msg = UpdateFailMalformedHtlc- { updateFailMalformedHtlcChannelId = testChannelId- , updateFailMalformedHtlcId = htlcId- , updateFailMalformedHtlcSha256Onion = testPaymentHash- , updateFailMalformedHtlcFailureCode = failCode- }- encoded = encodeUpdateFailMalformedHtlc msg- case decodeUpdateFailMalformedHtlc encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: CommitmentSigned roundtrip with varying HTLC count-propCommitmentSignedRoundtrip :: NonNegative Int -> Property-propCommitmentSignedRoundtrip (NonNegative n) = property $ do- let numHtlcs = n `mod` 10 -- limit to 10 HTLCs for test speed- htlcSigs = replicate numHtlcs testSignature- msg = CommitmentSigned- { commitmentSignedChannelId = testChannelId- , commitmentSignedSignature = testSignature- , commitmentSignedHtlcSignatures = htlcSigs- }- case encodeCommitmentSigned msg of- Left _ -> False- Right encoded -> case decodeCommitmentSigned encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: RevokeAndAck roundtrip-propRevokeAndAckRoundtrip :: Property-propRevokeAndAckRoundtrip = property $ do- let msg = RevokeAndAck- { revokeAndAckChannelId = testChannelId- , revokeAndAckPerCommitmentSecret = testSecret- , revokeAndAckNextPerCommitPoint = testPoint- }- encoded = encodeRevokeAndAck msg- case decodeRevokeAndAck encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: UpdateFee roundtrip-propUpdateFeeRoundtrip :: Word32 -> Property-propUpdateFeeRoundtrip feerate = property $ do- let msg = UpdateFee- { updateFeeChannelId = testChannelId- , updateFeeFeeratePerKw = feerate- }- encoded = encodeUpdateFee msg- case decodeUpdateFee encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Property: ChannelReestablish roundtrip-propChannelReestablishRoundtrip :: Word64 -> Word64 -> Property-propChannelReestablishRoundtrip nextCommit nextRevoke = property $ do- let sec = fromJust $ secret (BS.replicate 32 0x22)- msg = ChannelReestablish- { channelReestablishChannelId = testChannelId- , channelReestablishNextCommitNum = nextCommit- , channelReestablishNextRevocationNum = nextRevoke- , channelReestablishYourLastCommitSecret = sec- , channelReestablishMyCurrentCommitPoint = testPoint- , channelReestablishTlvs = emptyTlvs- }- encoded = encodeChannelReestablish msg- case decodeChannelReestablish encoded of- Right (decoded, _) -> decoded == msg- Left _ -> False---- Helpers ------------------------------------------------------------------------- | Decode hex string. Returns Nothing on invalid hex.-unhex :: BS.ByteString -> Maybe BS.ByteString-unhex = B16.decode+import qualified Bitcoin.Prim.Tx as Tx+import qualified Data.ByteString as BS+import qualified Data.ByteString.Base16 as B16+import qualified Data.ByteString.Char8 as B8+import Data.Int (Int64)+import Data.Word (Word8, Word64)+import qualified Lightning.Protocol.BOLT1 as BOLT1+import Lightning.Protocol.BOLT1 (TlvRecord(..), TlvError(..))+import Lightning.Protocol.BOLT2+import qualified Lightning.Protocol.BOLT9 as BOLT9+import Test.Tasty+import Test.Tasty.HUnit+import Test.Tasty.QuickCheck hiding (witness)++main :: IO ()+main = defaultMain $ testGroup "ppad-bolt2" [+ known_answers+ , tlv_handling+ , decoding_failures+ , encoding_failures+ , field_types+ , properties+ ]++-- helpers --------------------------------------------------------------------++rep :: Int -> String -> String+rep n = concat . replicate n++hx :: String -> Maybe BS.ByteString+hx = B16.decode . B8.pack++-- decode a hex literal, failing the test if it isn't valid hex+unhex :: String -> IO BS.ByteString+unhex s = maybe (assertFailure ("invalid hex literal: " ++ s)) pure (hx s)++-- unwrap a fixture, failing the test if it couldn't be constructed+just :: String -> Maybe a -> IO a+just what = maybe (assertFailure ("invalid fixture: " ++ what)) pure++empty :: BOLT1.TlvStream+empty = BOLT1.empty_tlv_stream++-- the unknown TLV records of a message+message_tlvs :: Message -> BOLT1.TlvStream+message_tlvs m = case m of+ MsgOpenChannel a -> open_channel_tlvs a+ MsgAcceptChannel a -> accept_channel_tlvs a+ MsgFundingCreated a -> funding_created_tlvs a+ MsgFundingSigned a -> funding_signed_tlvs a+ MsgChannelReady a -> channel_ready_tlvs a+ MsgOpenChannel2 a -> open_channel2_tlvs a+ MsgAcceptChannel2 a -> accept_channel2_tlvs a+ MsgTxAddInput a -> tx_add_input_tlvs a+ MsgTxAddOutput a -> tx_add_output_tlvs a+ MsgTxRemoveInput a -> tx_remove_input_tlvs a+ MsgTxRemoveOutput a -> tx_remove_output_tlvs a+ MsgTxComplete a -> tx_complete_tlvs a+ MsgTxSignatures a -> tx_signatures_tlvs a+ MsgTxInitRbf a -> tx_init_rbf_tlvs a+ MsgTxAckRbf a -> tx_ack_rbf_tlvs a+ MsgTxAbort a -> tx_abort_tlvs a+ MsgStfu a -> stfu_tlvs a+ MsgShutdown a -> shutdown_tlvs a+ MsgClosingComplete a -> closing_complete_tlvs a+ MsgClosingSig a -> closing_sig_tlvs a+ MsgClosingSigned a -> closing_signed_tlvs a+ MsgUpdateAddHtlc a -> update_add_htlc_tlvs a+ MsgUpdateFulfillHtlc a -> update_fulfill_htlc_tlvs a+ MsgUpdateFailHtlc a -> update_fail_htlc_tlvs a+ MsgUpdateFailMalformedHtlc a -> update_fail_malformed_htlc_tlvs a+ MsgCommitmentSigned a -> commitment_signed_tlvs a+ MsgRevokeAndAck a -> revoke_and_ack_tlvs a+ MsgUpdateFee a -> update_fee_tlvs a+ MsgChannelReestablish a -> channel_reestablish_tlvs a++-- field values ---------------------------------------------------------------++-- the bitcoin genesis block hash, in internal byte order+chain_h :: String+chain_h = "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000"++cid_h, tcid_h, txid_h, secret_h, preimage_h, phash_h :: String+cid_h = rep 32 "ab"+tcid_h = rep 32 "cd"+txid_h = rep 32 "7e"+secret_h = rep 32 "5e"+preimage_h = rep 32 "50"+phash_h = rep 32 "9a"++p1_h, p2_h, p3_h, p4_h, p5_h, p6_h, p7_h :: String+p1_h = "02" ++ rep 32 "11"+p2_h = "03" ++ rep 32 "22"+p3_h = "02" ++ rep 32 "33"+p4_h = "03" ++ rep 32 "44"+p5_h = "02" ++ rep 32 "55"+p6_h = "03" ++ rep 32 "66"+p7_h = "02" ++ rep 32 "77"++sig1_h, sig2_h, sig3_h :: String+sig1_h = rep 64 "a1"+sig2_h = rep 64 "b2"+sig3_h = rep 64 "c3"++-- version, ephemeral key, hop payloads, hmac+onion_h :: String+onion_h = "00" ++ p3_h ++ rep 1300 "44" ++ rep 32 "55"++-- twenty hold times of 100, then 210 truncated hmacs+attribution_h :: String+attribution_h = rep 20 "00000064" ++ rep 210 "0badf00d"++p2wpkh_h, p2wsh_h, p2tr_h :: String+p2wpkh_h = "0014" ++ rep 20 "88"+p2wsh_h = "0020" ++ rep 32 "99"+p2tr_h = "5120" ++ rep 32 "ee"++-- the sha256 of the empty string+onion_hash_h :: String+onion_hash_h =+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"++f_chain :: Maybe BOLT1.ChainHash+f_chain = BOLT1.chain_hash =<< hx chain_h++f_cid, f_tcid :: Maybe BOLT1.ChannelId+f_cid = BOLT1.channel_id =<< hx cid_h+f_tcid = BOLT1.channel_id =<< hx tcid_h++f_point :: String -> Maybe BOLT1.Point+f_point h = BOLT1.point =<< hx h++f_sig :: String -> Maybe BOLT1.Signature+f_sig h = BOLT1.signature =<< hx h++f_txid :: Maybe Tx.TxId+f_txid = Tx.mk_txid =<< hx txid_h++f_secret :: Maybe BOLT1.PerCommitmentSecret+f_secret = BOLT1.per_commitment_secret =<< hx secret_h++f_script :: String -> Maybe ScriptPubKey+f_script h = script_pubkey =<< hx h++f_attribution :: Maybe AttributionData+f_attribution = attribution_data =<< hx attribution_h++anchors :: BOLT9.FeatureVector+anchors = BOLT9.channel_type_features+ (BOLT9.ChannelType BOLT9.BasicAnchors False False)++sat :: Word64 -> Maybe BOLT1.Satoshi+sat = BOLT1.satoshi++msat :: Word64 -> Maybe BOLT1.MilliSatoshi+msat = BOLT1.milli_satoshi++-- message layouts ------------------------------------------------------------++-- A message's layout: its type and fixed fields (hex, assembled by hand+-- from the spec) and its known TLV types, each with a valid value and+-- some malformed ones.+data Layout = Layout+ { lay_name :: String+ , lay_type :: String+ , lay_fixed :: [String]+ , lay_known :: [(Word64, String, [String])]+ }++open_channel_lay :: Layout+open_channel_lay = Layout "open_channel" "0020" [+ chain_h+ , tcid_h+ , "00000000000f4240" -- funding_satoshis: 1000000+ , "00000000000003e8" -- push_msat: 1000+ , "0000000000000222" -- dust_limit_satoshis: 546+ , "ffffffffffffffff" -- max_htlc_value_in_flight_msat: u64 max+ , "0000000000002710" -- channel_reserve_satoshis: 10000+ , "0000000000000001" -- htlc_minimum_msat: 1+ , "000000fd" -- feerate_per_kw: 253+ , "0090" -- to_self_delay: 144+ , "01e3" -- max_accepted_htlcs: 483+ , p1_h, p2_h, p3_h, p4_h, p5_h, p6_h+ , "01" -- channel_flags+ ] [ (0, p2wpkh_h, []), (1, "401000", []) ]++accept_channel_lay :: Layout+accept_channel_lay = Layout "accept_channel" "0021" [+ tcid_h+ , "0000000000000222" -- dust_limit_satoshis: 546+ , "0000000005f5e100" -- max_htlc_value_in_flight_msat: 100000000+ , "0000000000002710" -- channel_reserve_satoshis: 10000+ , "00000000000003e8" -- htlc_minimum_msat: 1000+ , "00000003" -- minimum_depth: 3+ , "0090" -- to_self_delay: 144+ , "01e3" -- max_accepted_htlcs: 483+ , p1_h, p2_h, p3_h, p4_h, p5_h, p6_h+ ] [ (0, "", []), (1, "401000", []) ]++funding_created_lay :: Layout+funding_created_lay = Layout "funding_created" "0022" [+ tcid_h+ , txid_h+ , "0001" -- funding_output_index: 1+ , sig1_h+ ] []++funding_signed_lay :: Layout+funding_signed_lay = Layout "funding_signed" "0023" [ cid_h, sig1_h ] []++channel_ready_lay :: Layout+channel_ready_lay = Layout "channel_ready" "0024" [ cid_h, p1_h ]+ [ (1, "083a8400034d0001", ["083a8400034d00", "083a8400034d000100"]) ]++open_channel2_lay :: Layout+open_channel2_lay = Layout "open_channel2" "0040" [+ chain_h+ , tcid_h+ , "00000fa0" -- funding_feerate_perkw: 4000+ , "000000fd" -- commitment_feerate_perkw: 253+ , "0000000000030d40" -- funding_satoshis: 200000+ , "0000000000000162" -- dust_limit_satoshis: 354+ , "ffffffffffffffff" -- max_htlc_value_in_flight_msat: u64 max+ , "0000000000000001" -- htlc_minimum_msat: 1+ , "0090" -- to_self_delay: 144+ , "01e3" -- max_accepted_htlcs: 483+ , "000c3500" -- locktime: 800000+ , p1_h, p2_h, p3_h, p4_h, p5_h, p6_h, p7_h+ , "00" -- channel_flags+ ] [ (0, p2wpkh_h, []), (1, "401000", []), (2, "", ["00", "01"]) ]++accept_channel2_lay :: Layout+accept_channel2_lay = Layout "accept_channel2" "0041" [+ tcid_h+ , "0000000000000000" -- funding_satoshis: 0+ , "0000000000000162" -- dust_limit_satoshis: 354+ , "0000000005f5e100" -- max_htlc_value_in_flight_msat: 100000000+ , "00000000000003e8" -- htlc_minimum_msat: 1000+ , "00000006" -- minimum_depth: 6+ , "0090" -- to_self_delay: 144+ , "001e" -- max_accepted_htlcs: 30+ , p1_h, p2_h, p3_h, p4_h, p5_h, p6_h, p7_h+ ] [ (0, p2wsh_h, []), (1, "401000", []), (2, "", ["00"]) ]++tx_add_input_lay :: Layout+tx_add_input_lay = Layout "tx_add_input" "0042" [+ cid_h+ , "0000000000000002" -- serial_id: 2+ , "0005", "0102030405" -- prevtx+ , "00000001" -- prevtx_vout: 1+ , "fffffffd" -- sequence+ ] []++tx_add_output_lay :: Layout+tx_add_output_lay = Layout "tx_add_output" "0043" [+ cid_h+ , "0000000000000004" -- serial_id: 4+ , "0000000000030d40" -- sats: 200000+ , "0022", p2wsh_h -- script+ ] []++tx_remove_input_lay :: Layout+tx_remove_input_lay = Layout "tx_remove_input" "0044"+ [ cid_h, "0000000000000002" ] []++tx_remove_output_lay :: Layout+tx_remove_output_lay = Layout "tx_remove_output" "0045"+ [ cid_h, "0000000000000005" ] []++tx_complete_lay :: Layout+tx_complete_lay = Layout "tx_complete" "0046" [ cid_h ] []++tx_signatures_lay :: Layout+tx_signatures_lay = Layout "tx_signatures" "0047" [+ cid_h+ , txid_h+ , "0002" -- num_witnesses+ , "0006", "0202aaaa01bb" -- two stack items+ , "0003", "0101cc" -- one stack item+ ] []++tx_init_rbf_lay :: Layout+tx_init_rbf_lay = Layout "tx_init_rbf" "0048" [+ cid_h+ , "000c3500" -- locktime: 800000+ , "00001046" -- feerate: 4166+ ] [ (0, "0000000000030d40", ["00030d40", "000000000000030d40"])+ , (2, "", ["00"]) ]++tx_ack_rbf_lay :: Layout+tx_ack_rbf_lay = Layout "tx_ack_rbf" "0049" [ cid_h ]+ [ (0, "fffffffffffe7960", ["ff"]), (2, "", ["2a2a"]) ]++tx_abort_lay :: Layout+tx_abort_lay = Layout "tx_abort" "004a" [+ cid_h+ , "000c", "6661696c656420636865636b" -- "failed check"+ ] []++stfu_lay :: Layout+stfu_lay = Layout "stfu" "0002" [ cid_h, "01" ] []++shutdown_lay :: Layout+shutdown_lay = Layout "shutdown" "0026" [ cid_h, "0016", p2wpkh_h ] []++closing_complete_lay :: Layout+closing_complete_lay = Layout "closing_complete" "0028" [+ cid_h+ , "0016", p2wpkh_h -- closer_scriptpubkey+ , "0022", p2tr_h -- closee_scriptpubkey+ , "00000000000001f4" -- fee_satoshis: 500+ , "00000000" -- locktime: 0+ ] [ (t, sig1_h, [rep 63 "a1", rep 65 "a1"]) | t <- [1, 2, 3] ]++closing_sig_lay :: Layout+closing_sig_lay = Layout "closing_sig" "0029" [+ cid_h+ , "0016", p2wpkh_h -- closer_scriptpubkey+ , "0022", p2tr_h -- closee_scriptpubkey+ , "00000000000001f4" -- fee_satoshis: 500+ , "000c3500" -- locktime: 800000+ ] [ (t, sig3_h, [rep 63 "c3", ""]) | t <- [1, 2, 3] ]++closing_signed_lay :: Layout+closing_signed_lay = Layout "closing_signed" "0027" [+ cid_h+ , "00000000000001f4" -- fee_satoshis: 500+ , sig1_h+ ] [ (1, "000000000000006400000000000003e8", [+ "000000000000006400000000000003"+ , "000000000000006400000000000003e800"+ , "0000000000000064ffffffffffffffff" -- max fee above 21M BTC+ ]) ]++update_add_htlc_lay :: Layout+update_add_htlc_lay = Layout "update_add_htlc" "0080" [+ cid_h+ , "0000000000000000" -- id: 0+ , "00000000000186a0" -- amount_msat: 100000+ , phash_h+ , "000c3550" -- cltv_expiry: 800080+ , onion_h+ ] [ (0, p2_h, [ rep 32 "22", p2_h ++ "00", "04" ++ rep 32 "22" ]) ]++update_fulfill_htlc_lay :: Layout+update_fulfill_htlc_lay = Layout "update_fulfill_htlc" "0082" [+ cid_h+ , "0000000000000007" -- id: 7+ , preimage_h+ ] [ (1, attribution_h, [ drop 2 attribution_h, attribution_h ++ "00" ])+ , (3, "deadbeef", []) ]++update_fail_htlc_lay :: Layout+update_fail_htlc_lay = Layout "update_fail_htlc" "0083" [+ cid_h+ , "0000000000000007" -- id: 7+ , "0004", "01020304" -- reason+ ] [ (1, attribution_h, [ "" ]) ]++update_fail_malformed_htlc_lay :: Layout+update_fail_malformed_htlc_lay =+ Layout "update_fail_malformed_htlc" "0087" [+ cid_h+ , "0000000000000003" -- id: 3+ , onion_hash_h+ , "c005" -- failure_code: BADONION | PERM | 5+ ] []++commitment_signed_lay :: Layout+commitment_signed_lay = Layout "commitment_signed" "0084" [+ cid_h+ , sig1_h+ , "0002" -- num_htlcs+ , sig2_h, sig3_h+ ] [ (1, txid_h, [ rep 31 "7e", rep 33 "7e" ]) ]++revoke_and_ack_lay :: Layout+revoke_and_ack_lay = Layout "revoke_and_ack" "0085"+ [ cid_h, secret_h, p1_h ] []++update_fee_lay :: Layout+update_fee_lay = Layout "update_fee" "0086"+ [ cid_h, "000009c4" ] [] -- feerate_per_kw: 2500++channel_reestablish_lay :: Layout+channel_reestablish_lay = Layout "channel_reestablish" "0088" [+ cid_h+ , "0000000000000005" -- next_commitment_number: 5+ , "0000000000000004" -- next_revocation_number: 4+ , secret_h+ , p1_h+ ] [ (1, txid_h ++ "01", [ txid_h, txid_h ++ "0100" ]) ]++layouts :: [Layout]+layouts = [+ open_channel_lay, accept_channel_lay, funding_created_lay+ , funding_signed_lay, channel_ready_lay, open_channel2_lay+ , accept_channel2_lay, tx_add_input_lay, tx_add_output_lay+ , tx_remove_input_lay, tx_remove_output_lay, tx_complete_lay+ , tx_signatures_lay, tx_init_rbf_lay, tx_ack_rbf_lay, tx_abort_lay+ , stfu_lay, shutdown_lay, closing_complete_lay, closing_sig_lay+ , closing_signed_lay, update_add_htlc_lay, update_fulfill_htlc_lay+ , update_fail_htlc_lay, update_fail_malformed_htlc_lay+ , commitment_signed_lay, revoke_and_ack_lay, update_fee_lay+ , channel_reestablish_lay+ ]++-- a TLV record, in hex (for types below 253 and values below 65536+-- bytes)+tlv_h :: Word64 -> String -> String+tlv_h t v = hex2 t ++ len ++ v+ where+ n = fromIntegral (length v `div` 2) :: Word64+ len | n < 253 = hex2 n+ | otherwise = "fd" ++ hex2 (n `div` 256) ++ hex2 (n `mod` 256)++-- a byte, in hex+hex2 :: Word64 -> String+hex2 w = [digit (w `div` 16), digit (w `mod` 16)]+ where+ digit d = maybe '?' id (lookup d (zip [0 ..] "0123456789abcdef"))++-- known answers --------------------------------------------------------------++-- Check a message against wire bytes assembled by hand: its payload+-- decodes to the expected value and re-encodes to the same bytes, and+-- likewise for the full message.+kat+ :: (Eq a, Show a)+ => String+ -> Layout+ -> [String] -- TLV records, hex+ -> (BS.ByteString -> Either DecodeError a)+ -> (a -> Either EncodeError BS.ByteString)+ -> (a -> Message)+ -> Maybe a+ -> TestTree+kat name lay recs dec enc wrap expected = testCase name $ do+ payload <- unhex (concat (lay_fixed lay ++ recs))+ wire <- unhex (lay_type lay ++ concat (lay_fixed lay ++ recs))+ m <- just name expected+ dec payload @?= Right m+ enc m @?= Right payload+ decode_message wire @?= Right (wrap m)+ encode_message (wrap m) @?= Right wire++known_answers :: TestTree+known_answers = testGroup "known answers" [+ kat "open_channel" open_channel_lay+ [ tlv_h 0 p2wpkh_h, tlv_h 1 "401000" ]+ decode_open_channel encode_open_channel MsgOpenChannel $ do+ ch <- f_chain+ tcid <- f_tcid+ fund <- sat 1000000+ push <- msat 1000+ dust <- sat 546+ res <- sat 10000+ hmin <- msat 1+ [a, b, c, d, e, f] <- traverse f_point+ [p1_h, p2_h, p3_h, p4_h, p5_h, p6_h]+ spk <- f_script p2wpkh_h+ pure (OpenChannel ch tcid fund push dust maxBound res hmin 253 144+ 483 a b c d e f 1 (Just spk) (Just anchors) empty)++ , kat "open_channel (no TLVs)" open_channel_lay []+ decode_open_channel encode_open_channel MsgOpenChannel $ do+ ch <- f_chain+ tcid <- f_tcid+ fund <- sat 1000000+ push <- msat 1000+ dust <- sat 546+ res <- sat 10000+ hmin <- msat 1+ [a, b, c, d, e, f] <- traverse f_point+ [p1_h, p2_h, p3_h, p4_h, p5_h, p6_h]+ pure (OpenChannel ch tcid fund push dust maxBound res hmin 253 144+ 483 a b c d e f 1 Nothing Nothing empty)++ , kat "accept_channel" accept_channel_lay+ [ tlv_h 0 "", tlv_h 1 "401000" ]+ decode_accept_channel encode_accept_channel MsgAcceptChannel $ do+ tcid <- f_tcid+ dust <- sat 546+ res <- sat 10000+ hmin <- msat 1000+ [a, b, c, d, e, f] <- traverse f_point+ [p1_h, p2_h, p3_h, p4_h, p5_h, p6_h]+ spk <- script_pubkey ""+ pure (AcceptChannel tcid dust 100000000 res hmin 3 144 483+ a b c d e f (Just spk) (Just anchors) empty)++ , kat "funding_created" funding_created_lay []+ decode_funding_created (Right . encode_funding_created)+ MsgFundingCreated $ do+ tcid <- f_tcid+ t <- f_txid+ s <- f_sig sig1_h+ pure (FundingCreated tcid t 1 s empty)++ , kat "funding_signed" funding_signed_lay []+ decode_funding_signed (Right . encode_funding_signed)+ MsgFundingSigned $ do+ cid <- f_cid+ s <- f_sig sig1_h+ pure (FundingSigned cid s empty)++ , kat "channel_ready" channel_ready_lay+ [ tlv_h 1 "083a8400034d0001" ]+ decode_channel_ready encode_channel_ready MsgChannelReady $ do+ cid <- f_cid+ pcp <- f_point p1_h+ alias <- BOLT1.short_channel_id 539268 845 1+ pure (ChannelReady cid pcp (Just alias) empty)++ , kat "open_channel2" open_channel2_lay+ [ tlv_h 0 p2wpkh_h, tlv_h 1 "401000", tlv_h 2 "" ]+ decode_open_channel2 encode_open_channel2 MsgOpenChannel2 $ do+ ch <- f_chain+ tcid <- f_tcid+ fund <- sat 200000+ dust <- sat 354+ hmin <- msat 1+ [a, b, c, d, e, f, g] <- traverse f_point+ [p1_h, p2_h, p3_h, p4_h, p5_h, p6_h, p7_h]+ spk <- f_script p2wpkh_h+ pure (OpenChannel2 ch tcid 4000 253 fund dust maxBound hmin 144 483+ 800000 a b c d e f g 0 (Just spk) (Just anchors) True+ empty)++ , kat "accept_channel2" accept_channel2_lay+ [ tlv_h 0 p2wsh_h, tlv_h 1 "401000", tlv_h 2 "" ]+ decode_accept_channel2 encode_accept_channel2 MsgAcceptChannel2 $ do+ tcid <- f_tcid+ fund <- sat 0+ dust <- sat 354+ hmin <- msat 1000+ [a, b, c, d, e, f, g] <- traverse f_point+ [p1_h, p2_h, p3_h, p4_h, p5_h, p6_h, p7_h]+ spk <- f_script p2wsh_h+ pure (AcceptChannel2 tcid fund dust 100000000 hmin 6 144 30+ a b c d e f g (Just spk) (Just anchors) True empty)++ , kat "tx_add_input" tx_add_input_lay []+ decode_tx_add_input encode_tx_add_input MsgTxAddInput $ do+ cid <- f_cid+ pure (TxAddInput cid (SerialId 2) "\x01\x02\x03\x04\x05" 1+ 0xfffffffd empty)++ , kat "tx_add_output" tx_add_output_lay []+ decode_tx_add_output (Right . encode_tx_add_output)+ MsgTxAddOutput $ do+ cid <- f_cid+ amt <- sat 200000+ spk <- f_script p2wsh_h+ pure (TxAddOutput cid (SerialId 4) amt spk empty)++ , kat "tx_remove_input" tx_remove_input_lay []+ decode_tx_remove_input (Right . encode_tx_remove_input)+ MsgTxRemoveInput $ do+ cid <- f_cid+ pure (TxRemoveInput cid (SerialId 2) empty)++ , kat "tx_remove_output" tx_remove_output_lay []+ decode_tx_remove_output (Right . encode_tx_remove_output)+ MsgTxRemoveOutput $ do+ cid <- f_cid+ pure (TxRemoveOutput cid (SerialId 5) empty)++ , kat "tx_complete" tx_complete_lay []+ decode_tx_complete (Right . encode_tx_complete) MsgTxComplete $ do+ cid <- f_cid+ pure (TxComplete cid empty)++ , kat "tx_signatures" tx_signatures_lay []+ decode_tx_signatures encode_tx_signatures MsgTxSignatures $ do+ cid <- f_cid+ t <- f_txid+ w1 <- witness "\x02\x02\xaa\xaa\x01\xbb"+ w2 <- witness "\x01\x01\xcc"+ pure (TxSignatures cid t [w1, w2] empty)++ , kat "tx_init_rbf" tx_init_rbf_lay+ [ tlv_h 0 "0000000000030d40", tlv_h 2 "" ]+ decode_tx_init_rbf encode_tx_init_rbf MsgTxInitRbf $ do+ cid <- f_cid+ pure (TxInitRbf cid 800000 4166 (Just 200000) True empty)++ , kat "tx_ack_rbf" tx_ack_rbf_lay+ [ tlv_h 0 "fffffffffffe7960", tlv_h 2 "" ]+ decode_tx_ack_rbf encode_tx_ack_rbf MsgTxAckRbf $ do+ cid <- f_cid+ pure (TxAckRbf cid (Just (-100000)) True empty)++ , kat "tx_abort" tx_abort_lay []+ decode_tx_abort encode_tx_abort MsgTxAbort $ do+ cid <- f_cid+ pure (TxAbort cid "failed check" empty)++ , kat "stfu" stfu_lay []+ decode_stfu (Right . encode_stfu) MsgStfu $ do+ cid <- f_cid+ pure (Stfu cid True empty)++ , kat "shutdown" shutdown_lay []+ decode_shutdown (Right . encode_shutdown) MsgShutdown $ do+ cid <- f_cid+ spk <- f_script p2wpkh_h+ pure (Shutdown cid spk empty)++ , kat "closing_complete" closing_complete_lay+ [ tlv_h 1 sig1_h, tlv_h 3 sig2_h ]+ decode_closing_complete encode_closing_complete+ MsgClosingComplete $ do+ cid <- f_cid+ closer <- f_script p2wpkh_h+ closee <- f_script p2tr_h+ fee <- sat 500+ s1 <- f_sig sig1_h+ s2 <- f_sig sig2_h+ pure (ClosingComplete cid closer closee fee 0 (Just s1) Nothing+ (Just s2) empty)++ , kat "closing_complete (closee output only)" closing_complete_lay+ [ tlv_h 2 sig1_h ]+ decode_closing_complete encode_closing_complete+ MsgClosingComplete $ do+ cid <- f_cid+ closer <- f_script p2wpkh_h+ closee <- f_script p2tr_h+ fee <- sat 500+ s1 <- f_sig sig1_h+ pure (ClosingComplete cid closer closee fee 0 Nothing (Just s1)+ Nothing empty)++ , kat "closing_sig" closing_sig_lay [ tlv_h 3 sig3_h ]+ decode_closing_sig encode_closing_sig MsgClosingSig $ do+ cid <- f_cid+ closer <- f_script p2wpkh_h+ closee <- f_script p2tr_h+ fee <- sat 500+ s3 <- f_sig sig3_h+ pure (ClosingSig cid closer closee fee 800000 Nothing Nothing+ (Just s3) empty)++ , kat "closing_signed" closing_signed_lay+ [ tlv_h 1 "000000000000006400000000000003e8" ]+ decode_closing_signed encode_closing_signed MsgClosingSigned $ do+ cid <- f_cid+ fee <- sat 500+ s <- f_sig sig1_h+ lo <- sat 100+ hi <- sat 1000+ pure (ClosingSigned cid fee s (Just (FeeRange lo hi)) empty)++ , kat "update_add_htlc" update_add_htlc_lay [ tlv_h 0 p2_h ]+ decode_update_add_htlc encode_update_add_htlc MsgUpdateAddHtlc $ do+ cid <- f_cid+ amt <- msat 100000+ ph <- BOLT1.payment_hash =<< hx phash_h+ onion <- onion_routing_packet =<< hx onion_h+ pk <- f_point p2_h+ pure (UpdateAddHtlc cid (HtlcId 0) amt ph 800080 onion (Just pk)+ empty)++ , kat "update_fulfill_htlc" update_fulfill_htlc_lay+ [ tlv_h 1 attribution_h, tlv_h 3 "deadbeef" ]+ decode_update_fulfill_htlc encode_update_fulfill_htlc+ MsgUpdateFulfillHtlc $ do+ cid <- f_cid+ pre <- BOLT1.payment_preimage =<< hx preimage_h+ att <- f_attribution+ pure (UpdateFulfillHtlc cid (HtlcId 7) pre (Just att)+ (Just "\xde\xad\xbe\xef") empty)++ , kat "update_fail_htlc" update_fail_htlc_lay [ tlv_h 1 attribution_h ]+ decode_update_fail_htlc encode_update_fail_htlc MsgUpdateFailHtlc $ do+ cid <- f_cid+ att <- f_attribution+ pure (UpdateFailHtlc cid (HtlcId 7) "\x01\x02\x03\x04" (Just att)+ empty)++ , kat "update_fail_malformed_htlc" update_fail_malformed_htlc_lay []+ decode_update_fail_malformed_htlc+ (Right . encode_update_fail_malformed_htlc)+ MsgUpdateFailMalformedHtlc $ do+ cid <- f_cid+ oh <- onion_hash =<< hx onion_hash_h+ pure (UpdateFailMalformedHtlc cid (HtlcId 3) oh 0xc005 empty)++ , kat "commitment_signed" commitment_signed_lay [ tlv_h 1 txid_h ]+ decode_commitment_signed encode_commitment_signed+ MsgCommitmentSigned $ do+ cid <- f_cid+ sigs <- traverse f_sig [sig1_h, sig2_h, sig3_h]+ t <- f_txid+ case sigs of+ (s : hs) -> pure (CommitmentSigned cid s hs (Just t) empty)+ [] -> Nothing++ , kat "revoke_and_ack" revoke_and_ack_lay []+ decode_revoke_and_ack (Right . encode_revoke_and_ack)+ MsgRevokeAndAck $ do+ cid <- f_cid+ sec <- f_secret+ pcp <- f_point p1_h+ pure (RevokeAndAck cid sec pcp empty)++ , kat "update_fee" update_fee_lay []+ decode_update_fee (Right . encode_update_fee) MsgUpdateFee $ do+ cid <- f_cid+ pure (UpdateFee cid 2500 empty)++ , kat "channel_reestablish" channel_reestablish_lay+ [ tlv_h 1 (txid_h ++ "01") ]+ decode_channel_reestablish encode_channel_reestablish+ MsgChannelReestablish $ do+ cid <- f_cid+ sec <- f_secret+ pcp <- f_point p1_h+ t <- f_txid+ pure (ChannelReestablish cid 5 4 sec pcp (Just (NextFunding t 1))+ empty)+ ]++-- TLV handling ---------------------------------------------------------------++-- decode a message (type, fixed fields and TLV records in hex), check+-- its unknown records, and check that it re-encodes exactly+reencodes :: Layout -> [String] -> [TlvRecord] -> Assertion+reencodes lay recs extra = do+ wire <- unhex (lay_type lay ++ concat (lay_fixed lay ++ recs))+ case decode_message wire of+ Left e -> assertFailure ("decode failed: " ++ show e)+ Right m -> do+ BOLT1.un_tlv_stream (message_tlvs m) @?= extra+ encode_message m @?= Right wire++rejects :: Layout -> [String] -> DecodeError -> Assertion+rejects lay recs err = do+ wire <- unhex (lay_type lay ++ concat (lay_fixed lay ++ recs))+ decode_message wire @?= Left err++-- the smallest even type a message doesn't know+first_unknown_even :: Layout -> Word64+first_unknown_even lay = case filter (`notElem` known) [0, 2 ..] of+ (t:_) -> t+ [] -> 0+ where+ known = [ t | (t, _, _) <- lay_known lay ]++tlv_cases :: Layout -> TestTree+tlv_cases lay = testGroup (lay_name lay) $ [+ testCase "unknown odd records are preserved" $+ reencodes lay (valid ++ [tlv_h 43 "2a", tlv_h 201 ""])+ [TlvRecord 43 "\x2a", TlvRecord 201 ""]+ , testCase "unknown even records are rejected" $ do+ let t = first_unknown_even lay+ rejects lay [tlv_h t ""] (DecodeTlvError (TlvUnknownEvenType t))+ rejects lay (valid ++ [tlv_h 42 "00"])+ (DecodeTlvError (TlvUnknownEvenType 42))+ , testCase "unordered records are rejected" $+ rejects lay [tlv_h 45 "", tlv_h 43 ""]+ (DecodeTlvError TlvNotStrictlyIncreasing)+ , testCase "a huge record length is rejected" $ do+ -- the length 2^64 - 1 must not wrap+ rejects lay ["2bffffffffffffffffff2b"] (DecodeTlvError TlvTruncated)+ ] ++ [+ testCase ("type " ++ show t ++ " is typed") $ reencodes lay [tlv_h t v] []+ | (t, v, _) <- lay_known lay+ ] ++ [+ testCase ("malformed type " ++ show t ++ " is rejected") $+ mapM_ (\b -> rejects lay [tlv_h t b] (DecodeInvalidTlvValue t)) bad+ | (t, _, bad) <- lay_known lay, not (null bad)+ ]+ where+ valid = [ tlv_h t v | (t, v, _) <- lay_known lay ]++tlv_handling :: TestTree+tlv_handling = testGroup "TLV handling" $ map tlv_cases layouts ++ [+ testGroup "splicing records" [+ testCase "tx_add_input shared_input_txid is rejected" $+ rejects tx_add_input_lay [tlv_h 0 txid_h]+ (DecodeTlvError (TlvUnknownEvenType 0))+ , testCase "tx_signatures shared_input_signature is rejected" $+ rejects tx_signatures_lay [tlv_h 0 sig1_h]+ (DecodeTlvError (TlvUnknownEvenType 0))+ , testCase "channel_reestablish my_current_funding_locked is kept" $ do+ v <- unhex (txid_h ++ "01")+ reencodes channel_reestablish_lay+ [tlv_h 1 (txid_h ++ "00"), tlv_h 5 (txid_h ++ "01")]+ [TlvRecord 5 v]+ ]+ , testCase "a non-minimal type is rejected" $+ rejects update_fee_lay ["fd002b00"]+ (DecodeTlvError TlvNonMinimalBigSize)+ , testCase "a repeated type is rejected" $+ rejects update_fee_lay [tlv_h 43 "", tlv_h 43 ""]+ (DecodeTlvError TlvNotStrictlyIncreasing)+ , testCase "trailing bytes that aren't a TLV record are rejected" $ do+ rejects update_fee_lay ["fd"] (DecodeTlvError TlvTruncated)+ rejects update_fee_lay ["2b"] (DecodeTlvError TlvTruncated)+ rejects update_fee_lay ["2b02aa"] (DecodeTlvError TlvTruncated)+ , testCase "an empty upfront_shutdown_script is kept" $ do+ wire <- unhex (concat (lay_fixed open_channel_lay ++ [tlv_h 0 ""]))+ fmap open_channel_upfront_shutdown_script (decode_open_channel wire)+ @?= Right (script_pubkey "")+ , testCase "an oversized upfront_shutdown_script is rejected" $ do+ fixed <- unhex (concat (lay_fixed open_channel_lay))+ let big = BS.replicate 65536 0x00+ rec = "\x00\xfe\x00\x01\x00\x00" <> big+ decode_open_channel (fixed <> rec) @?= Left (DecodeInvalidTlvValue 0)+ , testCase "channel_type bytes are kept as received" $ do+ wire <- unhex (concat (lay_fixed open_channel_lay+ ++ [tlv_h 1 "00401000"]))+ case decode_open_channel wire of+ Left e -> assertFailure (show e)+ Right m -> do+ fmap BOLT9.render (open_channel_channel_type m)+ @?= Just "\x00\x40\x10\x00"+ (BOLT9.channel_type =<< open_channel_channel_type m)+ @?= Just (BOLT9.ChannelType BOLT9.BasicAnchors False False)+ encode_open_channel m @?= Right wire+ ]++-- decoding failures ----------------------------------------------------------++decoding_failures :: TestTree+decoding_failures = testGroup "decoding failures" [+ testGroup "truncated payloads" [+ testCase (lay_name lay) $ do+ wire <- unhex (lay_type lay ++ concat (lay_fixed lay))+ decode_message (BS.take (BS.length wire - 1) wire)+ @?= Left DecodeInsufficientBytes+ decode_message (BS.take 2 wire) @?= Left DecodeInsufficientBytes+ | lay <- layouts ]+ , testCase "a message without a type" $ do+ decode_message "" @?= Left DecodeInsufficientBytes+ decode_message "\x00" @?= Left DecodeInsufficientBytes+ , testCase "message types BOLT #2 doesn't define" $ do+ decode_message "\x00\x50" @?= Left (DecodeUnknownEvenType 80)+ decode_message "\x00\x51" @?= Left (DecodeUnknownOddType 81)+ decode_message "\x00\x4d" @?= Left (DecodeUnknownOddType 77)+ decode_message "\x00\x7f" @?= Left (DecodeUnknownOddType 127)+ decode_message "\x00\x10\x00\x00\x00\x00"+ @?= Left (DecodeUnknownEvenType 16)+ , testCase "an invalid point" $ do+ let bad = "04" ++ rep 32 "11"+ wire <- unhex (concat (open_channel_fields 11 bad))+ decode_open_channel wire @?= Left DecodeInvalidPoint+ wire' <- unhex (cid_h ++ secret_h ++ bad)+ decode_revoke_and_ack wire' @?= Left DecodeInvalidPoint+ , testCase "amounts above 21M BTC" $ do+ -- funding_satoshis of 21M BTC, then one satoshi more+ ok <- unhex (concat (open_channel_fields 2 "000775f05a074000"))+ bad <- unhex (concat (open_channel_fields 2 "000775f05a074001"))+ assertBool "21M BTC" (either (const False) (const True)+ (decode_open_channel ok))+ decode_open_channel bad @?= Left DecodeInvalidAmount+ htlc <- unhex (cid_h ++ "0000000000000000" ++ "1d24b2dfac520001"+ ++ phash_h ++ "000c3550" ++ onion_h)+ decode_update_add_htlc htlc @?= Left DecodeInvalidAmount+ out <- unhex (cid_h ++ "0000000000000004" ++ "ffffffffffffffff"+ ++ "0000")+ decode_tx_add_output out @?= Left DecodeInvalidAmount+ , testCase "stfu initiator byte" $ do+ off <- unhex (cid_h ++ "00")+ fmap stfu_initiator (decode_stfu off) @?= Right False+ bad <- unhex (cid_h ++ "02")+ decode_stfu bad @?= Left DecodeInvalidInitiator+ , testCase "a list longer than its payload" $ do+ wire <- unhex (cid_h ++ sig1_h ++ "0003" ++ sig2_h ++ sig3_h)+ decode_commitment_signed wire @?= Left DecodeInsufficientBytes+ wire' <- unhex (cid_h ++ txid_h ++ "0001" ++ "0004" ++ "0101")+ decode_tx_signatures wire' @?= Left DecodeInsufficientBytes+ , testCase "a short onion_routing_packet" $ do+ wire <- unhex (concat (take 5 (lay_fixed update_add_htlc_lay))+ ++ drop 2 onion_h)+ decode_update_add_htlc wire @?= Left DecodeInsufficientBytes+ ]+ where+ -- open_channel's fixed fields with field i replaced+ open_channel_fields :: Int -> String -> [String]+ open_channel_fields i v =+ let fs = lay_fixed open_channel_lay+ in take i fs ++ [v] ++ drop (i + 1) fs++-- encoding failures ----------------------------------------------------------++encoding_failures :: TestTree+encoding_failures = testGroup "encoding failures" [+ testCase "u16 length prefixes" $ do+ cid <- just "cid" f_cid+ let big = BS.replicate 65536 0x00+ max_ok = BS.replicate 65535 0x00+ encode_tx_add_input (TxAddInput cid (SerialId 0) big 0 0 empty)+ @?= Left EncodeLengthOverflow+ assertBool "65535-byte prevtx" $ either (const False) (const True)+ (encode_tx_add_input (TxAddInput cid (SerialId 0) max_ok 0 0 empty))+ encode_tx_abort (TxAbort cid big empty) @?= Left EncodeLengthOverflow+ encode_update_fail_htlc+ (UpdateFailHtlc cid (HtlcId 0) big Nothing empty)+ @?= Left EncodeLengthOverflow+ , testCase "u16 counts" $ do+ cid <- just "cid" f_cid+ s <- just "sig" (f_sig sig1_h)+ t <- just "txid" f_txid+ w <- just "witness" (witness "\x00")+ encode_commitment_signed+ (CommitmentSigned cid s (replicate 65536 s) Nothing empty)+ @?= Left EncodeLengthOverflow+ encode_tx_signatures (TxSignatures cid t (replicate 65536 w) empty)+ @?= Left EncodeLengthOverflow+ , testCase "_tlvs fields can't hold known types" $ do+ cid <- just "cid" f_cid+ pcp <- just "point" (f_point p1_h)+ s <- just "sig" (f_sig sig1_h)+ spk <- just "script" (f_script p2wpkh_h)+ fee <- just "fee" (sat 500)+ one <- just "tlvs" (BOLT1.tlv_stream [TlvRecord 1 "\x00"])+ two <- just "tlvs" (BOLT1.tlv_stream [TlvRecord 2 ""])+ odd' <- just "tlvs" (BOLT1.tlv_stream [TlvRecord 43 ""])+ encode_channel_ready (ChannelReady cid pcp Nothing one)+ @?= Left EncodeInvalidTlvs+ encode_closing_complete+ (ClosingComplete cid spk spk fee 0 (Just s) Nothing Nothing two)+ @?= Left EncodeInvalidTlvs+ encode_tx_ack_rbf (TxAckRbf cid Nothing False two)+ @?= Left EncodeInvalidTlvs+ assertBool "unknown odd records encode" $+ either (const False) (const True)+ (encode_channel_ready (ChannelReady cid pcp Nothing odd'))+ , testCase "the message size limit" $ do+ cid <- just "cid" f_cid+ -- a 65533-byte payload fits; one more byte doesn't+ let at n = TxAbort cid (BS.replicate n 0x00) empty+ fmap BS.length (encode_message (MsgTxAbort (at 65499)))+ @?= Right 65535+ encode_message (MsgTxAbort (at 65500)) @?= Left EncodeMessageTooLarge+ fmap BS.length (encode_tx_abort (at 65500)) @?= Right 65534+ ]++-- field types ----------------------------------------------------------------++field_types :: TestTree+field_types = testGroup "field types" [+ testCase "script_pubkey" $ do+ fmap un_script_pubkey (script_pubkey (BS.replicate 65535 0x51))+ @?= Just (BS.replicate 65535 0x51)+ script_pubkey (BS.replicate 65536 0x51) @?= Nothing+ , testCase "witness" $ do+ fmap un_witness (witness "") @?= Just ""+ witness (BS.replicate 65536 0x00) @?= Nothing+ , testCase "onion_routing_packet" $ do+ let bs = BS.replicate 1366 0x00+ fmap un_onion_routing_packet (onion_routing_packet bs) @?= Just bs+ onion_routing_packet (BS.take 1365 bs) @?= Nothing+ onion_routing_packet (BS.cons 0x00 bs) @?= Nothing+ , testCase "onion_hash" $ do+ fmap un_onion_hash (onion_hash (BS.replicate 32 0x01))+ @?= Just (BS.replicate 32 0x01)+ onion_hash (BS.replicate 33 0x01) @?= Nothing+ , testCase "attribution_data" $ do+ let bs = BS.replicate 920 0x00+ fmap un_attribution_data (attribution_data bs) @?= Just bs+ attribution_data (BS.take 919 bs) @?= Nothing+ , testCase "message types" $ do+ cid <- just "cid" f_cid+ message_type (MsgStfu (Stfu cid False empty)) @?= 2+ message_type (MsgUpdateFee (UpdateFee cid 0 empty)) @?= 134+ ]++-- generators -----------------------------------------------------------------++gen_bytes :: Int -> Gen BS.ByteString+gen_bytes n = BS.pack <$> vectorOf n arbitrary++gen_var_bytes :: Int -> Gen BS.ByteString+gen_var_bytes hi = choose (0, hi) >>= gen_bytes++gen_cid :: Gen BOLT1.ChannelId+gen_cid = gen_bytes 32 `suchThatMap` BOLT1.channel_id++gen_chain :: Gen BOLT1.ChainHash+gen_chain = gen_bytes 32 `suchThatMap` BOLT1.chain_hash++gen_point :: Gen BOLT1.Point+gen_point = do+ p <- elements [0x02, 0x03]+ (BS.cons p <$> gen_bytes 32) `suchThatMap` BOLT1.point++gen_sig :: Gen BOLT1.Signature+gen_sig = gen_bytes 64 `suchThatMap` BOLT1.signature++gen_txid :: Gen Tx.TxId+gen_txid = gen_bytes 32 `suchThatMap` Tx.mk_txid++gen_secret :: Gen BOLT1.PerCommitmentSecret+gen_secret = gen_bytes 32 `suchThatMap` BOLT1.per_commitment_secret++gen_sat :: Gen BOLT1.Satoshi+gen_sat = choose (0, 2100000000000000) `suchThatMap` BOLT1.satoshi++gen_msat :: Gen BOLT1.MilliSatoshi+gen_msat = choose (0, 2100000000000000000) `suchThatMap` BOLT1.milli_satoshi++gen_script :: Gen ScriptPubKey+gen_script = gen_var_bytes 40 `suchThatMap` script_pubkey++gen_fv :: Gen BOLT9.FeatureVector+gen_fv = BOLT9.parse <$> gen_var_bytes 8++gen_maybe :: Gen a -> Gen (Maybe a)+gen_maybe g = oneof [pure Nothing, Just <$> g]++-- unknown odd records, avoiding a message's known types+gen_tlvs :: [Word64] -> Gen BOLT1.TlvStream+gen_tlvs known = do+ ts <- sublistOf (filter (`notElem` known) candidates)+ rs <- traverse (\t -> TlvRecord t <$> gen_var_bytes 12) ts+ pure (maybe empty id (BOLT1.tlv_stream rs))+ where+ candidates = [1, 3, 5, 7, 43, 201, 253, 65537, 4294967297]++gen_open_channel :: Gen OpenChannel+gen_open_channel = OpenChannel <$> gen_chain <*> gen_cid <*> gen_sat+ <*> gen_msat <*> gen_sat <*> arbitrary <*> gen_sat <*> gen_msat+ <*> arbitrary <*> arbitrary <*> arbitrary <*> gen_point <*> gen_point+ <*> gen_point <*> gen_point <*> gen_point <*> gen_point <*> arbitrary+ <*> gen_maybe gen_script <*> gen_maybe gen_fv <*> gen_tlvs [0, 1]++gen_accept_channel :: Gen AcceptChannel+gen_accept_channel = AcceptChannel <$> gen_cid <*> gen_sat <*> arbitrary+ <*> gen_sat <*> gen_msat <*> arbitrary <*> arbitrary <*> arbitrary+ <*> gen_point <*> gen_point <*> gen_point <*> gen_point <*> gen_point+ <*> gen_point <*> gen_maybe gen_script <*> gen_maybe gen_fv+ <*> gen_tlvs [0, 1]++gen_funding_created :: Gen FundingCreated+gen_funding_created = FundingCreated <$> gen_cid <*> gen_txid <*> arbitrary+ <*> gen_sig <*> gen_tlvs []++gen_funding_signed :: Gen FundingSigned+gen_funding_signed = FundingSigned <$> gen_cid <*> gen_sig <*> gen_tlvs []++gen_channel_ready :: Gen ChannelReady+gen_channel_ready = ChannelReady <$> gen_cid <*> gen_point+ <*> gen_maybe (BOLT1.ShortChannelId <$> arbitrary) <*> gen_tlvs [1]++gen_open_channel2 :: Gen OpenChannel2+gen_open_channel2 = OpenChannel2 <$> gen_chain <*> gen_cid <*> arbitrary+ <*> arbitrary <*> gen_sat <*> gen_sat <*> arbitrary <*> gen_msat+ <*> arbitrary <*> arbitrary <*> arbitrary <*> gen_point <*> gen_point+ <*> gen_point <*> gen_point <*> gen_point <*> gen_point <*> gen_point+ <*> arbitrary <*> gen_maybe gen_script <*> gen_maybe gen_fv+ <*> arbitrary <*> gen_tlvs [0, 1, 2]++gen_accept_channel2 :: Gen AcceptChannel2+gen_accept_channel2 = AcceptChannel2 <$> gen_cid <*> gen_sat <*> gen_sat+ <*> arbitrary <*> gen_msat <*> arbitrary <*> arbitrary <*> arbitrary+ <*> gen_point <*> gen_point <*> gen_point <*> gen_point <*> gen_point+ <*> gen_point <*> gen_point <*> gen_maybe gen_script+ <*> gen_maybe gen_fv <*> arbitrary <*> gen_tlvs [0, 1, 2]++gen_tx_add_input :: Gen TxAddInput+gen_tx_add_input = TxAddInput <$> gen_cid <*> (SerialId <$> arbitrary)+ <*> gen_var_bytes 64 <*> arbitrary <*> arbitrary <*> gen_tlvs []++gen_tx_add_output :: Gen TxAddOutput+gen_tx_add_output = TxAddOutput <$> gen_cid <*> (SerialId <$> arbitrary)+ <*> gen_sat <*> gen_script <*> gen_tlvs []++gen_tx_remove_input :: Gen TxRemoveInput+gen_tx_remove_input = TxRemoveInput <$> gen_cid <*> (SerialId <$> arbitrary)+ <*> gen_tlvs []++gen_tx_remove_output :: Gen TxRemoveOutput+gen_tx_remove_output = TxRemoveOutput <$> gen_cid+ <*> (SerialId <$> arbitrary) <*> gen_tlvs []++gen_tx_complete :: Gen TxComplete+gen_tx_complete = TxComplete <$> gen_cid <*> gen_tlvs []++gen_tx_signatures :: Gen TxSignatures+gen_tx_signatures = TxSignatures <$> gen_cid <*> gen_txid+ <*> listOf (gen_var_bytes 32 `suchThatMap` witness) <*> gen_tlvs []++gen_tx_init_rbf :: Gen TxInitRbf+gen_tx_init_rbf = TxInitRbf <$> gen_cid <*> arbitrary <*> arbitrary+ <*> gen_maybe (arbitrary :: Gen Int64) <*> arbitrary <*> gen_tlvs [0, 2]++gen_tx_ack_rbf :: Gen TxAckRbf+gen_tx_ack_rbf = TxAckRbf <$> gen_cid <*> gen_maybe arbitrary <*> arbitrary+ <*> gen_tlvs [0, 2]++gen_tx_abort :: Gen TxAbort+gen_tx_abort = TxAbort <$> gen_cid <*> gen_var_bytes 64 <*> gen_tlvs []++gen_stfu :: Gen Stfu+gen_stfu = Stfu <$> gen_cid <*> arbitrary <*> gen_tlvs []++gen_shutdown :: Gen Shutdown+gen_shutdown = Shutdown <$> gen_cid <*> gen_script <*> gen_tlvs []++gen_closing_complete :: Gen ClosingComplete+gen_closing_complete = ClosingComplete <$> gen_cid <*> gen_script+ <*> gen_script <*> gen_sat <*> arbitrary <*> gen_maybe gen_sig+ <*> gen_maybe gen_sig <*> gen_maybe gen_sig <*> gen_tlvs [1, 2, 3]++gen_closing_sig :: Gen ClosingSig+gen_closing_sig = ClosingSig <$> gen_cid <*> gen_script <*> gen_script+ <*> gen_sat <*> arbitrary <*> gen_maybe gen_sig <*> gen_maybe gen_sig+ <*> gen_maybe gen_sig <*> gen_tlvs [1, 2, 3]++gen_closing_signed :: Gen ClosingSigned+gen_closing_signed = ClosingSigned <$> gen_cid <*> gen_sat <*> gen_sig+ <*> gen_maybe (FeeRange <$> gen_sat <*> gen_sat) <*> gen_tlvs [1]++gen_update_add_htlc :: Gen UpdateAddHtlc+gen_update_add_htlc = UpdateAddHtlc <$> gen_cid <*> (HtlcId <$> arbitrary)+ <*> gen_msat+ <*> (gen_bytes 32 `suchThatMap` BOLT1.payment_hash)+ <*> arbitrary+ <*> (gen_bytes 1366 `suchThatMap` onion_routing_packet)+ <*> gen_maybe gen_point <*> gen_tlvs [0]++gen_update_fulfill_htlc :: Gen UpdateFulfillHtlc+gen_update_fulfill_htlc = UpdateFulfillHtlc <$> gen_cid+ <*> (HtlcId <$> arbitrary)+ <*> (gen_bytes 32 `suchThatMap` BOLT1.payment_preimage)+ <*> gen_maybe (gen_bytes 920 `suchThatMap` attribution_data)+ <*> gen_maybe (gen_var_bytes 64) <*> gen_tlvs [1, 3]++gen_update_fail_htlc :: Gen UpdateFailHtlc+gen_update_fail_htlc = UpdateFailHtlc <$> gen_cid <*> (HtlcId <$> arbitrary)+ <*> gen_var_bytes 300+ <*> gen_maybe (gen_bytes 920 `suchThatMap` attribution_data)+ <*> gen_tlvs [1]++gen_update_fail_malformed_htlc :: Gen UpdateFailMalformedHtlc+gen_update_fail_malformed_htlc = UpdateFailMalformedHtlc <$> gen_cid+ <*> (HtlcId <$> arbitrary)+ <*> (gen_bytes 32 `suchThatMap` onion_hash)+ <*> arbitrary <*> gen_tlvs []++gen_commitment_signed :: Gen CommitmentSigned+gen_commitment_signed = CommitmentSigned <$> gen_cid <*> gen_sig+ <*> listOf gen_sig <*> gen_maybe gen_txid <*> gen_tlvs [1]++gen_revoke_and_ack :: Gen RevokeAndAck+gen_revoke_and_ack = RevokeAndAck <$> gen_cid <*> gen_secret <*> gen_point+ <*> gen_tlvs []++gen_update_fee :: Gen UpdateFee+gen_update_fee = UpdateFee <$> gen_cid <*> arbitrary <*> gen_tlvs []++gen_channel_reestablish :: Gen ChannelReestablish+gen_channel_reestablish = ChannelReestablish <$> gen_cid <*> arbitrary+ <*> arbitrary <*> gen_secret <*> gen_point+ <*> gen_maybe (NextFunding <$> gen_txid <*> arbitrary) <*> gen_tlvs [1]++gen_message :: Gen Message+gen_message = oneof [+ MsgOpenChannel <$> gen_open_channel+ , MsgAcceptChannel <$> gen_accept_channel+ , MsgFundingCreated <$> gen_funding_created+ , MsgFundingSigned <$> gen_funding_signed+ , MsgChannelReady <$> gen_channel_ready+ , MsgOpenChannel2 <$> gen_open_channel2+ , MsgAcceptChannel2 <$> gen_accept_channel2+ , MsgTxAddInput <$> gen_tx_add_input+ , MsgTxAddOutput <$> gen_tx_add_output+ , MsgTxRemoveInput <$> gen_tx_remove_input+ , MsgTxRemoveOutput <$> gen_tx_remove_output+ , MsgTxComplete <$> gen_tx_complete+ , MsgTxSignatures <$> gen_tx_signatures+ , MsgTxInitRbf <$> gen_tx_init_rbf+ , MsgTxAckRbf <$> gen_tx_ack_rbf+ , MsgTxAbort <$> gen_tx_abort+ , MsgStfu <$> gen_stfu+ , MsgShutdown <$> gen_shutdown+ , MsgClosingComplete <$> gen_closing_complete+ , MsgClosingSig <$> gen_closing_sig+ , MsgClosingSigned <$> gen_closing_signed+ , MsgUpdateAddHtlc <$> gen_update_add_htlc+ , MsgUpdateFulfillHtlc <$> gen_update_fulfill_htlc+ , MsgUpdateFailHtlc <$> gen_update_fail_htlc+ , MsgUpdateFailMalformedHtlc <$> gen_update_fail_malformed_htlc+ , MsgCommitmentSigned <$> gen_commitment_signed+ , MsgRevokeAndAck <$> gen_revoke_and_ack+ , MsgUpdateFee <$> gen_update_fee+ , MsgChannelReestablish <$> gen_channel_reestablish+ ]++-- properties -----------------------------------------------------------------++-- decoding an encoded payload gives back the value+roundtrip+ :: (Eq a, Show a)+ => String+ -> Gen a+ -> (a -> Either EncodeError BS.ByteString)+ -> (BS.ByteString -> Either DecodeError a)+ -> TestTree+roundtrip name gen enc dec = testProperty name $ forAll gen $ \m ->+ case enc m of+ Left e -> counterexample ("encode failed: " ++ show e) False+ Right w -> dec w === Right m++-- byte strings derived from a valid encoding+data Edit = Replace !Int !Word8 | Truncate !Int | Append !BS.ByteString+ deriving Show++gen_edit :: Gen Edit+gen_edit = oneof [+ Replace <$> arbitrary <*> arbitrary+ , Truncate <$> arbitrary+ , Append <$> gen_var_bytes 8+ ]++apply_edit :: Edit -> BS.ByteString -> BS.ByteString+apply_edit e bs = case e of+ Replace i b+ | BS.null bs -> bs+ | otherwise ->+ let j = i `mod` BS.length bs+ in BS.take j bs <> BS.singleton b <> BS.drop (j + 1) bs+ Truncate i+ | BS.null bs -> bs+ | otherwise -> BS.take (i `mod` BS.length bs) bs+ Append x -> bs <> x++properties :: TestTree+properties = testGroup "properties" [+ testGroup "payloads round-trip" [+ roundtrip "open_channel" gen_open_channel+ encode_open_channel decode_open_channel+ , roundtrip "accept_channel" gen_accept_channel+ encode_accept_channel decode_accept_channel+ , roundtrip "funding_created" gen_funding_created+ (Right . encode_funding_created) decode_funding_created+ , roundtrip "funding_signed" gen_funding_signed+ (Right . encode_funding_signed) decode_funding_signed+ , roundtrip "channel_ready" gen_channel_ready+ encode_channel_ready decode_channel_ready+ , roundtrip "open_channel2" gen_open_channel2+ encode_open_channel2 decode_open_channel2+ , roundtrip "accept_channel2" gen_accept_channel2+ encode_accept_channel2 decode_accept_channel2+ , roundtrip "tx_add_input" gen_tx_add_input+ encode_tx_add_input decode_tx_add_input+ , roundtrip "tx_add_output" gen_tx_add_output+ (Right . encode_tx_add_output) decode_tx_add_output+ , roundtrip "tx_remove_input" gen_tx_remove_input+ (Right . encode_tx_remove_input) decode_tx_remove_input+ , roundtrip "tx_remove_output" gen_tx_remove_output+ (Right . encode_tx_remove_output) decode_tx_remove_output+ , roundtrip "tx_complete" gen_tx_complete+ (Right . encode_tx_complete) decode_tx_complete+ , roundtrip "tx_signatures" gen_tx_signatures+ encode_tx_signatures decode_tx_signatures+ , roundtrip "tx_init_rbf" gen_tx_init_rbf+ encode_tx_init_rbf decode_tx_init_rbf+ , roundtrip "tx_ack_rbf" gen_tx_ack_rbf+ encode_tx_ack_rbf decode_tx_ack_rbf+ , roundtrip "tx_abort" gen_tx_abort encode_tx_abort decode_tx_abort+ , roundtrip "stfu" gen_stfu (Right . encode_stfu) decode_stfu+ , roundtrip "shutdown" gen_shutdown+ (Right . encode_shutdown) decode_shutdown+ , roundtrip "closing_complete" gen_closing_complete+ encode_closing_complete decode_closing_complete+ , roundtrip "closing_sig" gen_closing_sig+ encode_closing_sig decode_closing_sig+ , roundtrip "closing_signed" gen_closing_signed+ encode_closing_signed decode_closing_signed+ , roundtrip "update_add_htlc" gen_update_add_htlc+ encode_update_add_htlc decode_update_add_htlc+ , roundtrip "update_fulfill_htlc" gen_update_fulfill_htlc+ encode_update_fulfill_htlc decode_update_fulfill_htlc+ , roundtrip "update_fail_htlc" gen_update_fail_htlc+ encode_update_fail_htlc decode_update_fail_htlc+ , roundtrip "update_fail_malformed_htlc" gen_update_fail_malformed_htlc+ (Right . encode_update_fail_malformed_htlc)+ decode_update_fail_malformed_htlc+ , roundtrip "commitment_signed" gen_commitment_signed+ encode_commitment_signed decode_commitment_signed+ , roundtrip "revoke_and_ack" gen_revoke_and_ack+ (Right . encode_revoke_and_ack) decode_revoke_and_ack+ , roundtrip "update_fee" gen_update_fee+ (Right . encode_update_fee) decode_update_fee+ , roundtrip "channel_reestablish" gen_channel_reestablish+ encode_channel_reestablish decode_channel_reestablish+ ]+ , roundtrip "messages round-trip" gen_message encode_message decode_message+ , testProperty "decoded messages re-encode exactly" $+ withMaxSuccess 2000 $+ forAll gen_message $ \m -> forAll gen_edit $ \e ->+ case encode_message m of+ Left err -> counterexample ("encode failed: " ++ show err) False+ Right w ->+ let w' = apply_edit e w+ in case decode_message w' of+ Left _ -> property True+ Right m' -> encode_message m' === Right w'+ ]