ppad-bolt2-0.1.0: lib/Lightning/Protocol/BOLT2/Types.hs
{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE DeriveGeneric #-}
-- |
-- Module: Lightning.Protocol.BOLT2.Types
-- Copyright: (c) 2025 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
-- Field types specific to BOLT #2.
module Lightning.Protocol.BOLT2.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(..)
) where
import Bitcoin.Prim.Tx (TxId)
import Control.DeepSeq (NFData)
import qualified Data.ByteString as BS
import Data.Word (Word8, Word64)
import GHC.Generics (Generic)
import Lightning.Protocol.BOLT1 (Satoshi)
-- | 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)
instance NFData HtlcId
-- | 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)
instance NFData SerialId
-- | A scriptPubKey, at most 65535 bytes (the most a u16 length prefix
-- can describe).
newtype ScriptPubKey = ScriptPubKey BS.ByteString
deriving (Eq, Ord, Show, Generic)
instance NFData ScriptPubKey
-- | Construct a t'ScriptPubKey', failing above 65535 bytes. The script
-- itself isn't checked; the forms acceptable in @shutdown@ depend on
-- negotiated features.
--
-- >>> script_pubkey "\x51\x02\x4e\x73"
-- Just (ScriptPubKey "Q\STXNs")
-- >>> script_pubkey (BS.replicate 65536 0x00)
-- Nothing
script_pubkey :: BS.ByteString -> Maybe ScriptPubKey
script_pubkey bs
| BS.length bs <= 65535 = Just (ScriptPubKey bs)
| otherwise = Nothing
{-# INLINE script_pubkey #-}
-- | The bytes of a t'ScriptPubKey'.
un_script_pubkey :: ScriptPubKey -> BS.ByteString
un_script_pubkey (ScriptPubKey bs) = bs
{-# INLINE un_script_pubkey #-}
-- | The serialized witness of one input in @tx_signatures@ (encoded as
-- in Bitcoin's wire protocol), at most 65535 bytes.
newtype Witness = Witness BS.ByteString
deriving (Eq, Ord, Show, Generic)
instance NFData Witness
-- | Construct a t'Witness', failing above 65535 bytes. The contents
-- aren't checked.
--
-- >>> witness "\x01\x01\x2a"
-- Just (Witness "\SOH\SOH*")
witness :: BS.ByteString -> Maybe Witness
witness bs
| BS.length bs <= 65535 = Just (Witness bs)
| otherwise = Nothing
{-# INLINE witness #-}
-- | The bytes of a t'Witness'.
un_witness :: Witness -> BS.ByteString
un_witness (Witness bs) = bs
{-# INLINE un_witness #-}
-- | The 1366-byte @onion_routing_packet@ of @update_add_htlc@, kept
-- opaque (BOLT #4 defines its structure).
newtype OnionRoutingPacket = OnionRoutingPacket BS.ByteString
deriving (Eq, Ord, Show, Generic)
instance NFData OnionRoutingPacket
-- | Construct an t'OnionRoutingPacket' from exactly 1366 bytes.
--
-- >>> let bs = BS.replicate 1366 0x00
-- >>> fmap un_onion_routing_packet (onion_routing_packet bs) == Just bs
-- True
-- >>> onion_routing_packet (BS.take 1365 bs)
-- Nothing
onion_routing_packet :: BS.ByteString -> Maybe OnionRoutingPacket
onion_routing_packet bs
| BS.length bs == 1366 = Just (OnionRoutingPacket bs)
| otherwise = Nothing
{-# INLINE onion_routing_packet #-}
-- | The bytes of an t'OnionRoutingPacket'.
un_onion_routing_packet :: OnionRoutingPacket -> BS.ByteString
un_onion_routing_packet (OnionRoutingPacket bs) = bs
{-# INLINE un_onion_routing_packet #-}
-- | The SHA256 hash of an onion routing packet (the @sha256_of_onion@
-- field of @update_fail_malformed_htlc@).
newtype OnionHash = OnionHash BS.ByteString
deriving (Eq, Ord, Show, Generic)
instance NFData OnionHash
-- | Construct an t'OnionHash' from exactly 32 bytes.
--
-- >>> onion_hash (BS.replicate 31 0x00)
-- Nothing
onion_hash :: BS.ByteString -> Maybe OnionHash
onion_hash bs
| BS.length bs == 32 = Just (OnionHash bs)
| otherwise = Nothing
{-# INLINE onion_hash #-}
-- | The bytes of an t'OnionHash'.
un_onion_hash :: OnionHash -> BS.ByteString
un_onion_hash (OnionHash bs) = bs
{-# INLINE un_onion_hash #-}
-- | The 920-byte @attribution_data@ of @update_fulfill_htlc@ and
-- @update_fail_htlc@: twenty u32 HTLC hold times followed by 210
-- four-byte truncated HMACs. Kept opaque (BOLT #4 defines its use).
newtype AttributionData = AttributionData BS.ByteString
deriving (Eq, Ord, Show, Generic)
instance NFData AttributionData
-- | Construct an t'AttributionData' from exactly 920 bytes.
--
-- >>> let bs = BS.replicate 920 0x00
-- >>> fmap un_attribution_data (attribution_data bs) == Just bs
-- True
-- >>> attribution_data (BS.drop 1 bs)
-- Nothing
attribution_data :: BS.ByteString -> Maybe AttributionData
attribution_data bs
| BS.length bs == 920 = Just (AttributionData bs)
| otherwise = Nothing
{-# INLINE attribution_data #-}
-- | The bytes of an t'AttributionData'.
un_attribution_data :: AttributionData -> BS.ByteString
un_attribution_data (AttributionData bs) = bs
{-# INLINE un_attribution_data #-}
-- | The @fee_range@ of @closing_signed@: the fees the sender is
-- prepared to pay for the closing transaction.
data FeeRange = FeeRange
{ fee_range_min_fee_satoshis :: {-# UNPACK #-} !Satoshi
, fee_range_max_fee_satoshis :: {-# UNPACK #-} !Satoshi
} deriving (Eq, Show, Generic)
instance NFData FeeRange
-- | The @next_funding@ record of @channel_reestablish@: an interactive
-- funding transaction whose signatures are still being exchanged.
data NextFunding = NextFunding
{ next_funding_txid :: !TxId
, next_funding_retransmit_flags :: {-# UNPACK #-} !Word8
-- ^ bit 0: the sender wants @commitment_signed@ retransmitted
} deriving (Eq, Show, Generic)
instance NFData NextFunding