commit 20dea434be34eee354da2b7acd7365ba9de68b30
parent 7aa54cabff49e52ca9f4ea94f4e430eb18fd3cc7
Author: Jared Tobin <jared@jtobin.io>
Date: Sun, 19 Apr 2026 12:45:58 +0800
lib: use shared types from ppad-bolt1
Import ChainHash, ShortChannelId, ChannelId, Signature, and Point
from BOLT1.Prim instead of defining them locally. Add scidFromBytes
and scidToBytes helpers for wire-format conversion of the now
Word64-backed ShortChannelId. Update all accessor references
(getX -> unX pattern) in Codec.hs and Validate.hs.
Diffstat:
4 files changed, 86 insertions(+), 167 deletions(-)
diff --git a/flake.lock b/flake.lock
@@ -120,11 +120,11 @@
]
},
"locked": {
- "lastModified": 1776481687,
- "narHash": "sha256-1oT11gu84v1wEmOrigp6FTP1DIG7JkD1OVdgOCCPQFs=",
+ "lastModified": 1776570879,
+ "narHash": "sha256-XsgGBvYWL+sD7pDZoPPi4l39DE7GH7maNnhm8iUeB/E=",
"ref": "master",
- "rev": "0a19559d878ad6701d9d10fd08a32b736bcee662",
- "revCount": 26,
+ "rev": "20ea43188d781368e5e64c7c646285a6b0aaeb94",
+ "revCount": 27,
"type": "git",
"url": "git://git.ppad.tech/bolt1.git"
},
diff --git a/lib/Lightning/Protocol/BOLT7/Codec.hs b/lib/Lightning/Protocol/BOLT7/Codec.hs
@@ -165,7 +165,7 @@ decodeChainHash = decodeFixed chainHashLen DecodeInvalidChainHash chainHash
decodeShortChannelId :: ByteString
-> Either DecodeError (ShortChannelId, ByteString)
decodeShortChannelId =
- decodeFixed shortChannelIdLen DecodeInvalidShortChannelId shortChannelId
+ decodeFixed shortChannelIdLen DecodeInvalidShortChannelId scidFromBytes
{-# INLINE decodeShortChannelId #-}
-- | Decode ChannelId (32 bytes).
@@ -249,17 +249,17 @@ decodeAddresses bs = do
-- | Encode channel_announcement message.
encodeChannelAnnouncement :: ChannelAnnouncement -> ByteString
encodeChannelAnnouncement msg = mconcat
- [ getSignature (channelAnnNodeSig1 msg)
- , getSignature (channelAnnNodeSig2 msg)
- , getSignature (channelAnnBitcoinSig1 msg)
- , getSignature (channelAnnBitcoinSig2 msg)
+ [ unSignature (channelAnnNodeSig1 msg)
+ , unSignature (channelAnnNodeSig2 msg)
+ , unSignature (channelAnnBitcoinSig1 msg)
+ , unSignature (channelAnnBitcoinSig2 msg)
, encodeLenPrefixed (getFeatureBits (channelAnnFeatures msg))
- , getChainHash (channelAnnChainHash msg)
- , getShortChannelId (channelAnnShortChanId msg)
+ , unChainHash (channelAnnChainHash msg)
+ , scidToBytes (channelAnnShortChanId msg)
, getNodeId (channelAnnNodeId1 msg)
, getNodeId (channelAnnNodeId2 msg)
- , getPoint (channelAnnBitcoinKey1 msg)
- , getPoint (channelAnnBitcoinKey2 msg)
+ , unPoint (channelAnnBitcoinKey1 msg)
+ , unPoint (channelAnnBitcoinKey2 msg)
]
-- | Decode channel_announcement message.
@@ -302,7 +302,7 @@ encodeNodeAnnouncement msg = do
if BS.length features > 65535
then Left EncodeLengthOverflow
else Right $ mconcat
- [ getSignature (nodeAnnSignature msg)
+ [ unSignature (nodeAnnSignature msg)
, encodeLenPrefixed features
, Prim.encodeU32 (nodeAnnTimestamp msg)
, getNodeId (nodeAnnNodeId msg)
@@ -365,9 +365,9 @@ decodeNodeAnnouncement bs = do
-- | Encode channel_update message.
encodeChannelUpdate :: ChannelUpdate -> ByteString
encodeChannelUpdate msg = mconcat
- [ getSignature (chanUpdateSignature msg)
- , getChainHash (chanUpdateChainHash msg)
- , getShortChannelId (chanUpdateShortChanId msg)
+ [ unSignature (chanUpdateSignature msg)
+ , unChainHash (chanUpdateChainHash msg)
+ , scidToBytes (chanUpdateShortChanId msg)
, Prim.encodeU32 (chanUpdateTimestamp msg)
, BS.singleton (encodeMessageFlags (chanUpdateMsgFlags msg))
, BS.singleton (encodeChannelFlags (chanUpdateChanFlags msg))
@@ -422,10 +422,10 @@ decodeChannelUpdate bs = do
-- | Encode announcement_signatures message.
encodeAnnouncementSignatures :: AnnouncementSignatures -> ByteString
encodeAnnouncementSignatures msg = mconcat
- [ getChannelId (annSigChannelId msg)
- , getShortChannelId (annSigShortChanId msg)
- , getSignature (annSigNodeSig msg)
- , getSignature (annSigBitcoinSig msg)
+ [ unChannelId (annSigChannelId msg)
+ , scidToBytes (annSigShortChanId msg)
+ , unSignature (annSigNodeSig msg)
+ , unSignature (annSigBitcoinSig msg)
]
-- | Decode announcement_signatures message.
@@ -455,7 +455,7 @@ encodeQueryShortChannelIds msg = do
if BS.length scidData > 65535
then Left EncodeLengthOverflow
else Right $ mconcat
- [ getChainHash (queryScidsChainHash msg)
+ [ unChainHash (queryScidsChainHash msg)
, encodeLenPrefixed scidData
, TLV.encodeTlvStream (queryScidsTlvs msg)
]
@@ -480,7 +480,7 @@ decodeQueryShortChannelIds bs = do
-- | Encode reply_short_channel_ids_end message.
encodeReplyShortChannelIdsEnd :: ReplyShortChannelIdsEnd -> ByteString
encodeReplyShortChannelIdsEnd msg = mconcat
- [ getChainHash (replyScidsChainHash msg)
+ [ unChainHash (replyScidsChainHash msg)
, BS.singleton (replyScidsFullInfo msg)
]
@@ -500,7 +500,7 @@ decodeReplyShortChannelIdsEnd bs = do
-- | Encode query_channel_range message.
encodeQueryChannelRange :: QueryChannelRange -> ByteString
encodeQueryChannelRange msg = mconcat
- [ getChainHash (queryRangeChainHash msg)
+ [ unChainHash (queryRangeChainHash msg)
, Prim.encodeU32 (queryRangeFirstBlock msg)
, Prim.encodeU32 (queryRangeNumBlocks msg)
, TLV.encodeTlvStream (queryRangeTlvs msg)
@@ -531,7 +531,7 @@ encodeReplyChannelRange msg = do
if BS.length rangeData > 65535
then Left EncodeLengthOverflow
else Right $ mconcat
- [ getChainHash (replyRangeChainHash msg)
+ [ unChainHash (replyRangeChainHash msg)
, Prim.encodeU32 (replyRangeFirstBlock msg)
, Prim.encodeU32 (replyRangeNumBlocks msg)
, BS.singleton (replyRangeSyncComplete msg)
@@ -564,7 +564,7 @@ decodeReplyChannelRange bs = do
-- | Encode gossip_timestamp_filter message.
encodeGossipTimestampFilter :: GossipTimestampFilter -> ByteString
encodeGossipTimestampFilter msg = mconcat
- [ getChainHash (gossipFilterChainHash msg)
+ [ unChainHash (gossipFilterChainHash msg)
, Prim.encodeU32 (gossipFilterFirstTimestamp msg)
, Prim.encodeU32 (gossipFilterTimestampRange msg)
]
@@ -595,7 +595,7 @@ decodeGossipTimestampFilter bs = do
-- ascending order if that's required by the protocol context.
encodeShortChannelIdList :: [ShortChannelId] -> ByteString
encodeShortChannelIdList scids = BS.cons 0 $
- mconcat (map getShortChannelId scids)
+ mconcat (map scidToBytes scids)
{-# INLINE encodeShortChannelIdList #-}
-- | Decode a list of short channel IDs from encoded_short_ids data.
@@ -618,7 +618,7 @@ decodeShortChannelIdList bs
| BS.length d < shortChannelIdLen = Left DecodeInsufficientBytes
| otherwise = do
let (scidBytes, rest) = BS.splitAt shortChannelIdLen d
- case shortChannelId scidBytes of
+ case scidFromBytes scidBytes of
Nothing -> Left DecodeInvalidShortChannelId
Just scid -> do
scids <- decodeUncompressedScids rest
diff --git a/lib/Lightning/Protocol/BOLT7/Types.hs b/lib/Lightning/Protocol/BOLT7/Types.hs
@@ -12,30 +12,31 @@
-- Core types for BOLT #7 routing gossip.
module Lightning.Protocol.BOLT7.Types (
- -- * Identifiers
- ChainHash
+ -- * Identifiers (re-exported from BOLT1)
+ ChainHash(..)
, chainHash
- , getChainHash
+ , unChainHash
, mainnetChainHash
- , ShortChannelId
+ , ShortChannelId(..)
, shortChannelId
- , mkShortChannelId
- , getShortChannelId
, scidBlockHeight
, scidTxIndex
, scidOutputIndex
+ , scidWord64
+ , scidFromBytes
+ , scidToBytes
, formatScid
- , ChannelId
+ , ChannelId(..)
, channelId
- , getChannelId
+ , unChannelId
- -- * Cryptographic types
- , Signature
+ -- * Cryptographic types (re-exported from BOLT1)
+ , Signature(..)
, signature
- , getSignature
- , Point
+ , unSignature
+ , Point(..)
, point
- , getPoint
+ , unPoint
, NodeId
, nodeId
, getNodeId
@@ -99,6 +100,14 @@ import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.Word (Word8, Word16, Word32, Word64)
import GHC.Generics (Generic)
+import Lightning.Protocol.BOLT1.Prim
+ ( ChainHash(..), unChainHash, chainHash
+ , ShortChannelId(..), shortChannelId
+ , scidBlockHeight, scidTxIndex, scidOutputIndex, scidWord64
+ , ChannelId(..), unChannelId, channelId
+ , Signature(..), unSignature, signature
+ , Point(..), unPoint, point
+ )
-- Constants -------------------------------------------------------------------
@@ -159,23 +168,7 @@ torV3AddrLen = 35
-- Identifiers -----------------------------------------------------------------
--- | Chain hash identifying the blockchain (32 bytes).
-newtype ChainHash = ChainHash { getChainHash :: ByteString }
- deriving (Eq, Show, Generic)
-
-instance NFData ChainHash
-
--- | Smart constructor for ChainHash. Returns Nothing if not 32 bytes.
-chainHash :: ByteString -> Maybe ChainHash
-chainHash !bs
- | BS.length bs == chainHashLen = Just (ChainHash bs)
- | otherwise = Nothing
-{-# INLINE chainHash #-}
-
-- | Bitcoin mainnet chain hash (genesis block hash, little-endian).
---
--- This is the double-SHA256 of the mainnet genesis block header, reversed
--- to little-endian byte order as used in the protocol.
mainnetChainHash :: ChainHash
mainnetChainHash = ChainHash $ BS.pack
[ 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72
@@ -184,122 +177,48 @@ mainnetChainHash = ChainHash $ BS.pack
, 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00
]
--- | Short channel ID (8 bytes): block height (3) + tx index (3) + output (2).
-newtype ShortChannelId = ShortChannelId { getShortChannelId :: ByteString }
- deriving (Eq, Show, Generic)
-
-instance NFData ShortChannelId
-
--- | Smart constructor for ShortChannelId. Returns Nothing if not 8 bytes.
-shortChannelId :: ByteString -> Maybe ShortChannelId
-shortChannelId !bs
- | BS.length bs == shortChannelIdLen = Just (ShortChannelId bs)
- | otherwise = Nothing
-{-# INLINE shortChannelId #-}
-
--- | Construct ShortChannelId from components.
---
--- Block height and tx index are truncated to 24 bits.
---
--- >>> mkShortChannelId 539268 845 1
--- ShortChannelId {getShortChannelId = "\NUL\131\132\NUL\ETX-\NUL\SOH"}
-mkShortChannelId
- :: Word32 -- ^ Block height (24 bits)
- -> Word32 -- ^ Transaction index (24 bits)
- -> Word16 -- ^ Output index
- -> ShortChannelId
-mkShortChannelId !block !txIdx !outIdx = ShortChannelId $ BS.pack
- [ fromIntegral ((block `shiftR` 16) .&. 0xff) :: Word8
- , fromIntegral ((block `shiftR` 8) .&. 0xff)
- , fromIntegral (block .&. 0xff)
- , fromIntegral ((txIdx `shiftR` 16) .&. 0xff)
- , fromIntegral ((txIdx `shiftR` 8) .&. 0xff)
- , fromIntegral (txIdx .&. 0xff)
- , fromIntegral ((outIdx `shiftR` 8) .&. 0xff)
- , fromIntegral (outIdx .&. 0xff)
- ]
-{-# INLINE mkShortChannelId #-}
-
--- | Extract block height from short channel ID (first 3 bytes, big-endian).
-scidBlockHeight :: ShortChannelId -> Word32
-scidBlockHeight (ShortChannelId bs) =
- let b0 = fromIntegral (BS.index bs 0)
- b1 = fromIntegral (BS.index bs 1)
- b2 = fromIntegral (BS.index bs 2)
- in (b0 `shiftL` 16) .|. (b1 `shiftL` 8) .|. b2
-{-# INLINE scidBlockHeight #-}
-
--- | Extract transaction index from short channel ID (bytes 3-5, big-endian).
-scidTxIndex :: ShortChannelId -> Word32
-scidTxIndex (ShortChannelId bs) =
- let b3 = fromIntegral (BS.index bs 3)
- b4 = fromIntegral (BS.index bs 4)
- b5 = fromIntegral (BS.index bs 5)
- in (b3 `shiftL` 16) .|. (b4 `shiftL` 8) .|. b5
-{-# INLINE scidTxIndex #-}
-
--- | Extract output index from short channel ID (last 2 bytes, big-endian).
-scidOutputIndex :: ShortChannelId -> Word16
-scidOutputIndex (ShortChannelId bs) =
- let b6 = fromIntegral (BS.index bs 6)
- b7 = fromIntegral (BS.index bs 7)
- in (b6 `shiftL` 8) .|. b7
-{-# INLINE scidOutputIndex #-}
+-- | Parse ShortChannelId from 8 big-endian bytes.
+scidFromBytes :: ByteString -> Maybe ShortChannelId
+scidFromBytes !bs
+ | BS.length bs /= shortChannelIdLen = Nothing
+ | otherwise =
+ let !w = (fromIntegral (BS.index bs 0) `shiftL` 56)
+ .|. (fromIntegral (BS.index bs 1) `shiftL` 48)
+ .|. (fromIntegral (BS.index bs 2) `shiftL` 40)
+ .|. (fromIntegral (BS.index bs 3) `shiftL` 32)
+ .|. (fromIntegral (BS.index bs 4) `shiftL` 24)
+ .|. (fromIntegral (BS.index bs 5) `shiftL` 16)
+ .|. (fromIntegral (BS.index bs 6) `shiftL` 8)
+ .|. fromIntegral (BS.index bs 7) :: Word64
+ in Just (ShortChannelId w)
+{-# INLINE scidFromBytes #-}
+
+-- | Encode ShortChannelId as 8 big-endian bytes.
+scidToBytes :: ShortChannelId -> ByteString
+scidToBytes !sci =
+ let !w = scidWord64 sci
+ in BS.pack
+ [ fromIntegral (w `shiftR` 56)
+ , fromIntegral (w `shiftR` 48)
+ , fromIntegral (w `shiftR` 40)
+ , fromIntegral (w `shiftR` 32)
+ , fromIntegral (w `shiftR` 24)
+ , fromIntegral (w `shiftR` 16)
+ , fromIntegral (w `shiftR` 8)
+ , fromIntegral w
+ ]
+{-# INLINE scidToBytes #-}
-- | Format short channel ID as human-readable string.
---
--- Uses the standard "block x tx x output" notation.
---
--- >>> formatScid (mkShortChannelId 539268 845 1)
--- "539268x845x1"
formatScid :: ShortChannelId -> String
-formatScid scid =
- show (scidBlockHeight scid) ++ "x" ++
- show (scidTxIndex scid) ++ "x" ++
- show (scidOutputIndex scid)
+formatScid sci =
+ show (scidBlockHeight sci) ++ "x" ++
+ show (scidTxIndex sci) ++ "x" ++
+ show (scidOutputIndex sci)
{-# INLINE formatScid #-}
--- | Channel ID (32 bytes).
-newtype ChannelId = ChannelId { getChannelId :: ByteString }
- deriving (Eq, Show, Generic)
-
-instance NFData ChannelId
-
--- | Smart constructor for ChannelId. Returns Nothing if not 32 bytes.
-channelId :: ByteString -> Maybe ChannelId
-channelId !bs
- | BS.length bs == channelIdLen = Just (ChannelId bs)
- | otherwise = Nothing
-{-# INLINE channelId #-}
-
-- Cryptographic types ---------------------------------------------------------
--- | Signature (64 bytes).
-newtype Signature = Signature { getSignature :: ByteString }
- deriving (Eq, Show, Generic)
-
-instance NFData Signature
-
--- | Smart constructor for Signature. Returns Nothing if not 64 bytes.
-signature :: ByteString -> Maybe Signature
-signature !bs
- | BS.length bs == signatureLen = Just (Signature bs)
- | otherwise = Nothing
-{-# INLINE signature #-}
-
--- | Compressed public key (33 bytes).
-newtype Point = Point { getPoint :: ByteString }
- deriving (Eq, Show, Generic)
-
-instance NFData Point
-
--- | Smart constructor for Point. Returns Nothing if not 33 bytes.
-point :: ByteString -> Maybe Point
-point !bs
- | BS.length bs == pointLen = Just (Point bs)
- | otherwise = Nothing
-{-# INLINE point #-}
-
-- | Node ID (33 bytes, same as compressed public key).
--
-- Has Ord instance for lexicographic comparison (required by spec for
diff --git a/lib/Lightning/Protocol/BOLT7/Validate.hs b/lib/Lightning/Protocol/BOLT7/Validate.hs
@@ -121,7 +121,7 @@ validateReplyChannelRange msg =
checkAscending [] = Right ()
checkAscending [_] = Right ()
checkAscending (a:b:rest)
- | getShortChannelId a < getShortChannelId b = checkAscending (b:rest)
+ | a < b = checkAscending (b:rest)
| otherwise = Left ValidateScidNotAscending
-- Internal helpers -----------------------------------------------------------