{-# OPTIONS_HADDOCK prune #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

-- |
-- Module: Lightning.Protocol.BOLT2.Types
-- Copyright: (c) 2025 Jared Tobin
-- 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.

module Lightning.Protocol.BOLT2.Types (
  -- * Identifiers (re-exported from BOLT1)
    ChannelId(..)
  , channelId
  , unChannelId

  -- * Amounts (re-exported from BOLT1)
  , Satoshi(..)
  , MilliSatoshi(..)
  , satToMsat
  , msatToSat

  -- * Cryptographic types (re-exported from BOLT1)
  , Signature(..)
  , signature
  , unSignature
  , Point(..)
  , point
  , unPoint
  , PaymentHash(..)
  , paymentHash
  , unPaymentHash
  , PaymentPreimage(..)
  , paymentPreimage
  , unPaymentPreimage
  , PerCommitmentSecret(..)
  , perCommitmentSecret
  , unPerCommitmentSecret

  -- * Chain types (re-exported from BOLT1)
  , ChainHash(..)
  , chainHash
  , unChainHash
  , ShortChannelId(..)
  , shortChannelId
  , scidBlockHeight
  , scidTxIndex
  , scidOutputIndex

  -- * Transaction types
  , TxId(..)
  , mkTxId
  , OutPoint(..)
  , ScriptPubKey
  , scriptPubKey
  , unScriptPubKey

  -- * Protocol types
  , FeatureBits
  , featureBits
  , unFeatureBits
  , OnionPacket
  , onionPacket
  , unOnionPacket

  -- * Constants
  , channelIdLen
  , signatureLen
  , pointLen
  , chainHashLen
  , shortChannelIdLen
  , paymentHashLen
  , paymentPreimageLen
  , onionPacketLen
  , perCommitmentSecretLen
  ) where

import Bitcoin.Prim.Tx (TxId(..), mkTxId, OutPoint(..))
import Control.DeepSeq (NFData)
import qualified Data.ByteString as BS
import GHC.Generics (Generic)
import Lightning.Protocol.BOLT1.Prim
  ( ChannelId(..), channelId, unChannelId
  , Satoshi(..), MilliSatoshi(..), satToMsat, msatToSat
  , Signature(..), signature, unSignature
  , Point(..), point, unPoint
  , PaymentHash(..), paymentHash, unPaymentHash
  , PaymentPreimage(..), paymentPreimage, unPaymentPreimage
  , PerCommitmentSecret(..), perCommitmentSecret
  , unPerCommitmentSecret
  , ChainHash(..), chainHash, unChainHash
  , ShortChannelId(..), shortChannelId
  , scidBlockHeight, scidTxIndex, scidOutputIndex
  )

-- constants -------------------------------------------------------------------

-- | Length of a channel_id in bytes (32).
channelIdLen :: Int
channelIdLen :: Int
channelIdLen = Int
32
{-# INLINE channelIdLen #-}

-- | Length of a signature in bytes (64, compact format).
signatureLen :: Int
signatureLen :: Int
signatureLen = Int
64
{-# INLINE signatureLen #-}

-- | Length of a compressed secp256k1 public key in bytes (33).
pointLen :: Int
pointLen :: Int
pointLen = Int
33
{-# INLINE pointLen #-}

-- | Length of a chain hash in bytes (32).
chainHashLen :: Int
chainHashLen :: Int
chainHashLen = Int
32
{-# INLINE chainHashLen #-}

-- | Length of a short_channel_id in bytes (8).
shortChannelIdLen :: Int
shortChannelIdLen :: Int
shortChannelIdLen = Int
8
{-# INLINE shortChannelIdLen #-}

-- | Length of a payment hash in bytes (32).
paymentHashLen :: Int
paymentHashLen :: Int
paymentHashLen = Int
32
{-# INLINE paymentHashLen #-}

-- | Length of a payment preimage in bytes (32).
paymentPreimageLen :: Int
paymentPreimageLen :: Int
paymentPreimageLen = Int
32
{-# INLINE paymentPreimageLen #-}

-- | Length of an onion routing packet in bytes (1366).
onionPacketLen :: Int
onionPacketLen :: Int
onionPacketLen = Int
1366
{-# INLINE onionPacketLen #-}

-- | Length of a per-commitment secret in bytes (32).
perCommitmentSecretLen :: Int
perCommitmentSecretLen :: Int
perCommitmentSecretLen = Int
32
{-# INLINE perCommitmentSecretLen #-}

-- transaction types -----------------------------------------------------------

-- | A script pubkey (output script).
newtype ScriptPubKey = ScriptPubKey BS.ByteString
  deriving stock (ScriptPubKey -> ScriptPubKey -> Bool
(ScriptPubKey -> ScriptPubKey -> Bool)
-> (ScriptPubKey -> ScriptPubKey -> Bool) -> Eq ScriptPubKey
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ScriptPubKey -> ScriptPubKey -> Bool
== :: ScriptPubKey -> ScriptPubKey -> Bool
$c/= :: ScriptPubKey -> ScriptPubKey -> Bool
/= :: ScriptPubKey -> ScriptPubKey -> Bool
Eq, Eq ScriptPubKey
Eq ScriptPubKey =>
(ScriptPubKey -> ScriptPubKey -> Ordering)
-> (ScriptPubKey -> ScriptPubKey -> Bool)
-> (ScriptPubKey -> ScriptPubKey -> Bool)
-> (ScriptPubKey -> ScriptPubKey -> Bool)
-> (ScriptPubKey -> ScriptPubKey -> Bool)
-> (ScriptPubKey -> ScriptPubKey -> ScriptPubKey)
-> (ScriptPubKey -> ScriptPubKey -> ScriptPubKey)
-> Ord ScriptPubKey
ScriptPubKey -> ScriptPubKey -> Bool
ScriptPubKey -> ScriptPubKey -> Ordering
ScriptPubKey -> ScriptPubKey -> ScriptPubKey
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: ScriptPubKey -> ScriptPubKey -> Ordering
compare :: ScriptPubKey -> ScriptPubKey -> Ordering
$c< :: ScriptPubKey -> ScriptPubKey -> Bool
< :: ScriptPubKey -> ScriptPubKey -> Bool
$c<= :: ScriptPubKey -> ScriptPubKey -> Bool
<= :: ScriptPubKey -> ScriptPubKey -> Bool
$c> :: ScriptPubKey -> ScriptPubKey -> Bool
> :: ScriptPubKey -> ScriptPubKey -> Bool
$c>= :: ScriptPubKey -> ScriptPubKey -> Bool
>= :: ScriptPubKey -> ScriptPubKey -> Bool
$cmax :: ScriptPubKey -> ScriptPubKey -> ScriptPubKey
max :: ScriptPubKey -> ScriptPubKey -> ScriptPubKey
$cmin :: ScriptPubKey -> ScriptPubKey -> ScriptPubKey
min :: ScriptPubKey -> ScriptPubKey -> ScriptPubKey
Ord, Int -> ScriptPubKey -> ShowS
[ScriptPubKey] -> ShowS
ScriptPubKey -> String
(Int -> ScriptPubKey -> ShowS)
-> (ScriptPubKey -> String)
-> ([ScriptPubKey] -> ShowS)
-> Show ScriptPubKey
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ScriptPubKey -> ShowS
showsPrec :: Int -> ScriptPubKey -> ShowS
$cshow :: ScriptPubKey -> String
show :: ScriptPubKey -> String
$cshowList :: [ScriptPubKey] -> ShowS
showList :: [ScriptPubKey] -> ShowS
Show, (forall x. ScriptPubKey -> Rep ScriptPubKey x)
-> (forall x. Rep ScriptPubKey x -> ScriptPubKey)
-> Generic ScriptPubKey
forall x. Rep ScriptPubKey x -> ScriptPubKey
forall x. ScriptPubKey -> Rep ScriptPubKey x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ScriptPubKey -> Rep ScriptPubKey x
from :: forall x. ScriptPubKey -> Rep ScriptPubKey x
$cto :: forall x. Rep ScriptPubKey x -> ScriptPubKey
to :: forall x. Rep ScriptPubKey x -> ScriptPubKey
Generic)
  deriving newtype ScriptPubKey -> ()
(ScriptPubKey -> ()) -> NFData ScriptPubKey
forall a. (a -> ()) -> NFData a
$crnf :: ScriptPubKey -> ()
rnf :: ScriptPubKey -> ()
NFData

-- | Construct a 'ScriptPubKey' from a 'BS.ByteString'.
scriptPubKey :: BS.ByteString -> ScriptPubKey
scriptPubKey :: ByteString -> ScriptPubKey
scriptPubKey = ByteString -> ScriptPubKey
ScriptPubKey
{-# INLINE scriptPubKey #-}

-- | Extract the underlying 'BS.ByteString' from a 'ScriptPubKey'.
unScriptPubKey :: ScriptPubKey -> BS.ByteString
unScriptPubKey :: ScriptPubKey -> ByteString
unScriptPubKey (ScriptPubKey ByteString
bs) = ByteString
bs
{-# INLINE unScriptPubKey #-}

-- protocol types --------------------------------------------------------------

-- | Feature bits (variable length).
newtype FeatureBits = FeatureBits BS.ByteString
  deriving stock (FeatureBits -> FeatureBits -> Bool
(FeatureBits -> FeatureBits -> Bool)
-> (FeatureBits -> FeatureBits -> Bool) -> Eq FeatureBits
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FeatureBits -> FeatureBits -> Bool
== :: FeatureBits -> FeatureBits -> Bool
$c/= :: FeatureBits -> FeatureBits -> Bool
/= :: FeatureBits -> FeatureBits -> Bool
Eq, Eq FeatureBits
Eq FeatureBits =>
(FeatureBits -> FeatureBits -> Ordering)
-> (FeatureBits -> FeatureBits -> Bool)
-> (FeatureBits -> FeatureBits -> Bool)
-> (FeatureBits -> FeatureBits -> Bool)
-> (FeatureBits -> FeatureBits -> Bool)
-> (FeatureBits -> FeatureBits -> FeatureBits)
-> (FeatureBits -> FeatureBits -> FeatureBits)
-> Ord FeatureBits
FeatureBits -> FeatureBits -> Bool
FeatureBits -> FeatureBits -> Ordering
FeatureBits -> FeatureBits -> FeatureBits
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: FeatureBits -> FeatureBits -> Ordering
compare :: FeatureBits -> FeatureBits -> Ordering
$c< :: FeatureBits -> FeatureBits -> Bool
< :: FeatureBits -> FeatureBits -> Bool
$c<= :: FeatureBits -> FeatureBits -> Bool
<= :: FeatureBits -> FeatureBits -> Bool
$c> :: FeatureBits -> FeatureBits -> Bool
> :: FeatureBits -> FeatureBits -> Bool
$c>= :: FeatureBits -> FeatureBits -> Bool
>= :: FeatureBits -> FeatureBits -> Bool
$cmax :: FeatureBits -> FeatureBits -> FeatureBits
max :: FeatureBits -> FeatureBits -> FeatureBits
$cmin :: FeatureBits -> FeatureBits -> FeatureBits
min :: FeatureBits -> FeatureBits -> FeatureBits
Ord, Int -> FeatureBits -> ShowS
[FeatureBits] -> ShowS
FeatureBits -> String
(Int -> FeatureBits -> ShowS)
-> (FeatureBits -> String)
-> ([FeatureBits] -> ShowS)
-> Show FeatureBits
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FeatureBits -> ShowS
showsPrec :: Int -> FeatureBits -> ShowS
$cshow :: FeatureBits -> String
show :: FeatureBits -> String
$cshowList :: [FeatureBits] -> ShowS
showList :: [FeatureBits] -> ShowS
Show, (forall x. FeatureBits -> Rep FeatureBits x)
-> (forall x. Rep FeatureBits x -> FeatureBits)
-> Generic FeatureBits
forall x. Rep FeatureBits x -> FeatureBits
forall x. FeatureBits -> Rep FeatureBits x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. FeatureBits -> Rep FeatureBits x
from :: forall x. FeatureBits -> Rep FeatureBits x
$cto :: forall x. Rep FeatureBits x -> FeatureBits
to :: forall x. Rep FeatureBits x -> FeatureBits
Generic)
  deriving newtype FeatureBits -> ()
(FeatureBits -> ()) -> NFData FeatureBits
forall a. (a -> ()) -> NFData a
$crnf :: FeatureBits -> ()
rnf :: FeatureBits -> ()
NFData

-- | Construct 'FeatureBits' from a 'BS.ByteString'.
featureBits :: BS.ByteString -> FeatureBits
featureBits :: ByteString -> FeatureBits
featureBits = ByteString -> FeatureBits
FeatureBits
{-# INLINE featureBits #-}

-- | Extract the underlying 'BS.ByteString' from 'FeatureBits'.
unFeatureBits :: FeatureBits -> BS.ByteString
unFeatureBits :: FeatureBits -> ByteString
unFeatureBits (FeatureBits ByteString
bs) = ByteString
bs
{-# INLINE unFeatureBits #-}

-- | A 1366-byte onion routing packet.
newtype OnionPacket = OnionPacket BS.ByteString
  deriving stock (OnionPacket -> OnionPacket -> Bool
(OnionPacket -> OnionPacket -> Bool)
-> (OnionPacket -> OnionPacket -> Bool) -> Eq OnionPacket
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: OnionPacket -> OnionPacket -> Bool
== :: OnionPacket -> OnionPacket -> Bool
$c/= :: OnionPacket -> OnionPacket -> Bool
/= :: OnionPacket -> OnionPacket -> Bool
Eq, Eq OnionPacket
Eq OnionPacket =>
(OnionPacket -> OnionPacket -> Ordering)
-> (OnionPacket -> OnionPacket -> Bool)
-> (OnionPacket -> OnionPacket -> Bool)
-> (OnionPacket -> OnionPacket -> Bool)
-> (OnionPacket -> OnionPacket -> Bool)
-> (OnionPacket -> OnionPacket -> OnionPacket)
-> (OnionPacket -> OnionPacket -> OnionPacket)
-> Ord OnionPacket
OnionPacket -> OnionPacket -> Bool
OnionPacket -> OnionPacket -> Ordering
OnionPacket -> OnionPacket -> OnionPacket
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: OnionPacket -> OnionPacket -> Ordering
compare :: OnionPacket -> OnionPacket -> Ordering
$c< :: OnionPacket -> OnionPacket -> Bool
< :: OnionPacket -> OnionPacket -> Bool
$c<= :: OnionPacket -> OnionPacket -> Bool
<= :: OnionPacket -> OnionPacket -> Bool
$c> :: OnionPacket -> OnionPacket -> Bool
> :: OnionPacket -> OnionPacket -> Bool
$c>= :: OnionPacket -> OnionPacket -> Bool
>= :: OnionPacket -> OnionPacket -> Bool
$cmax :: OnionPacket -> OnionPacket -> OnionPacket
max :: OnionPacket -> OnionPacket -> OnionPacket
$cmin :: OnionPacket -> OnionPacket -> OnionPacket
min :: OnionPacket -> OnionPacket -> OnionPacket
Ord, Int -> OnionPacket -> ShowS
[OnionPacket] -> ShowS
OnionPacket -> String
(Int -> OnionPacket -> ShowS)
-> (OnionPacket -> String)
-> ([OnionPacket] -> ShowS)
-> Show OnionPacket
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> OnionPacket -> ShowS
showsPrec :: Int -> OnionPacket -> ShowS
$cshow :: OnionPacket -> String
show :: OnionPacket -> String
$cshowList :: [OnionPacket] -> ShowS
showList :: [OnionPacket] -> ShowS
Show, (forall x. OnionPacket -> Rep OnionPacket x)
-> (forall x. Rep OnionPacket x -> OnionPacket)
-> Generic OnionPacket
forall x. Rep OnionPacket x -> OnionPacket
forall x. OnionPacket -> Rep OnionPacket x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. OnionPacket -> Rep OnionPacket x
from :: forall x. OnionPacket -> Rep OnionPacket x
$cto :: forall x. Rep OnionPacket x -> OnionPacket
to :: forall x. Rep OnionPacket x -> OnionPacket
Generic)
  deriving newtype OnionPacket -> ()
(OnionPacket -> ()) -> NFData OnionPacket
forall a. (a -> ()) -> NFData a
$crnf :: OnionPacket -> ()
rnf :: OnionPacket -> ()
NFData

-- | 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 :: ByteString -> Maybe OnionPacket
onionPacket !ByteString
bs
  | ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
onionPacketLen = OnionPacket -> Maybe OnionPacket
forall a. a -> Maybe a
Just (OnionPacket -> Maybe OnionPacket)
-> OnionPacket -> Maybe OnionPacket
forall a b. (a -> b) -> a -> b
$! ByteString -> OnionPacket
OnionPacket ByteString
bs
  | Bool
otherwise                      = Maybe OnionPacket
forall a. Maybe a
Nothing
{-# INLINABLE onionPacket #-}

-- | Extract the underlying 'BS.ByteString' from an 'OnionPacket'.
unOnionPacket :: OnionPacket -> BS.ByteString
unOnionPacket :: OnionPacket -> ByteString
unOnionPacket (OnionPacket ByteString
bs) = ByteString
bs
{-# INLINE unOnionPacket #-}