commit bf284caaf7687fc8a09aa796bd781b89dd36002e
parent b4ddfa7b4e40812d0f62082d531f88792620e8ab
Author: Jared Tobin <jared@jtobin.io>
Date: Sun, 25 Jan 2026 16:07:15 +0400
Merge impl/flags-adt: use ADTs for channel update flags
Diffstat:
5 files changed, 450 insertions(+), 37 deletions(-)
diff --git a/lib/Lightning/Protocol/BOLT7/Codec.hs b/lib/Lightning/Protocol/BOLT7/Codec.hs
@@ -50,7 +50,6 @@ module Lightning.Protocol.BOLT7.Codec (
) where
import Control.DeepSeq (NFData)
-import Data.Bits ((.&.))
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.Word (Word8, Word16, Word32, Word64)
@@ -370,8 +369,8 @@ encodeChannelUpdate msg = mconcat
, getChainHash (chanUpdateChainHash msg)
, getShortChannelId (chanUpdateShortChanId msg)
, Prim.encodeU32 (chanUpdateTimestamp msg)
- , BS.singleton (chanUpdateMsgFlags msg)
- , BS.singleton (chanUpdateChanFlags msg)
+ , BS.singleton (encodeMessageFlags (chanUpdateMsgFlags msg))
+ , BS.singleton (encodeChannelFlags (chanUpdateChanFlags msg))
, Prim.encodeU16 (getCltvExpiryDelta (chanUpdateCltvExpDelta msg))
, Prim.encodeU64 (getHtlcMinimumMsat (chanUpdateHtlcMinMsat msg))
, Prim.encodeU32 (getFeeBaseMsat (chanUpdateFeeBaseMsat msg))
@@ -385,18 +384,20 @@ encodeChannelUpdate msg = mconcat
decodeChannelUpdate :: ByteString
-> Either DecodeError (ChannelUpdate, ByteString)
decodeChannelUpdate bs = do
- (sig, bs1) <- decodeSignature bs
- (chainH, bs2) <- decodeChainHash bs1
- (scid, bs3) <- decodeShortChannelId bs2
- (timestamp, bs4) <- decodeU32 bs3
- (msgFlags, bs5) <- decodeU8 bs4
- (chanFlags, bs6) <- decodeU8 bs5
- (cltvDelta, bs7) <- decodeU16 bs6
- (htlcMin, bs8) <- decodeU64 bs7
- (feeBase, bs9) <- decodeU32 bs8
- (feeProp, bs10) <- decodeU32 bs9
+ (sig, bs1) <- decodeSignature bs
+ (chainH, bs2) <- decodeChainHash bs1
+ (scid, bs3) <- decodeShortChannelId bs2
+ (timestamp, bs4) <- decodeU32 bs3
+ (msgFlagsRaw, bs5) <- decodeU8 bs4
+ (chanFlagsRaw, bs6) <- decodeU8 bs5
+ (cltvDelta, bs7) <- decodeU16 bs6
+ (htlcMin, bs8) <- decodeU64 bs7
+ (feeBase, bs9) <- decodeU32 bs8
+ (feeProp, bs10) <- decodeU32 bs9
+ let msgFlags' = decodeMessageFlags msgFlagsRaw
+ chanFlags' = decodeChannelFlags chanFlagsRaw
-- htlc_maximum_msat is present if message_flags bit 0 is set
- (htlcMax, rest) <- if msgFlags .&. 0x01 /= 0
+ (htlcMax, rest) <- if mfHtlcMaxPresent msgFlags'
then do
(m, r) <- decodeU64 bs10
Right (Just (HtlcMaximumMsat m), r)
@@ -406,8 +407,8 @@ decodeChannelUpdate bs = do
, chanUpdateChainHash = chainH
, chanUpdateShortChanId = scid
, chanUpdateTimestamp = timestamp
- , chanUpdateMsgFlags = msgFlags
- , chanUpdateChanFlags = chanFlags
+ , chanUpdateMsgFlags = msgFlags'
+ , chanUpdateChanFlags = chanFlags'
, chanUpdateCltvExpDelta = CltvExpiryDelta cltvDelta
, chanUpdateHtlcMinMsat = HtlcMinimumMsat htlcMin
, chanUpdateFeeBaseMsat = FeeBaseMsat feeBase
diff --git a/lib/Lightning/Protocol/BOLT7/Messages.hs b/lib/Lightning/Protocol/BOLT7/Messages.hs
@@ -41,7 +41,7 @@ module Lightning.Protocol.BOLT7.Messages (
import Control.DeepSeq (NFData)
import Data.ByteString (ByteString)
-import Data.Word (Word8, Word16, Word32)
+import Data.Word (Word8, Word16, Word32) -- Word8 still used by other messages
import GHC.Generics (Generic)
import Lightning.Protocol.BOLT1 (TlvStream)
import Lightning.Protocol.BOLT7.Types
@@ -126,8 +126,8 @@ data ChannelUpdate = ChannelUpdate
, chanUpdateChainHash :: !ChainHash -- ^ Chain identifier
, chanUpdateShortChanId :: !ShortChannelId -- ^ Short channel ID
, chanUpdateTimestamp :: !Timestamp -- ^ Unix timestamp
- , chanUpdateMsgFlags :: !Word8 -- ^ Message flags
- , chanUpdateChanFlags :: !Word8 -- ^ Channel flags
+ , chanUpdateMsgFlags :: !MessageFlags -- ^ Message flags
+ , chanUpdateChanFlags :: !ChannelFlags -- ^ Channel flags
, chanUpdateCltvExpDelta :: !CltvExpiryDelta -- ^ CLTV expiry delta
, chanUpdateHtlcMinMsat :: !HtlcMinimumMsat -- ^ Minimum HTLC msat
, chanUpdateFeeBaseMsat :: !FeeBaseMsat -- ^ Base fee msat
diff --git a/lib/Lightning/Protocol/BOLT7/Types.hs b/lib/Lightning/Protocol/BOLT7/Types.hs
@@ -64,6 +64,14 @@ module Lightning.Protocol.BOLT7.Types (
, torV3Addr
, getTorV3Addr
+ -- * Channel update flags
+ , MessageFlags(..)
+ , encodeMessageFlags
+ , decodeMessageFlags
+ , ChannelFlags(..)
+ , encodeChannelFlags
+ , decodeChannelFlags
+
-- * Routing parameters
, CltvExpiryDelta(..)
, FeeBaseMsat(..)
@@ -401,6 +409,55 @@ data Address
instance NFData Address
+-- Channel update flags --------------------------------------------------------
+
+-- | Message flags for channel_update.
+--
+-- Bit 0: htlc_maximum_msat field is present.
+data MessageFlags = MessageFlags
+ { mfHtlcMaxPresent :: !Bool -- ^ htlc_maximum_msat is present
+ }
+ deriving (Eq, Show, Generic)
+
+instance NFData MessageFlags
+
+-- | Encode MessageFlags to Word8.
+encodeMessageFlags :: MessageFlags -> Word8
+encodeMessageFlags mf = if mfHtlcMaxPresent mf then 0x01 else 0x00
+{-# INLINE encodeMessageFlags #-}
+
+-- | Decode Word8 to MessageFlags.
+decodeMessageFlags :: Word8 -> MessageFlags
+decodeMessageFlags w = MessageFlags { mfHtlcMaxPresent = w .&. 0x01 /= 0 }
+{-# INLINE decodeMessageFlags #-}
+
+-- | Channel flags for channel_update.
+--
+-- Bit 0: direction (0 = node_id_1 is origin, 1 = node_id_2 is origin).
+-- Bit 1: disabled (1 = channel disabled).
+data ChannelFlags = ChannelFlags
+ { cfDirection :: !Bool -- ^ True = node_id_2 is origin
+ , cfDisabled :: !Bool -- ^ True = channel is disabled
+ }
+ deriving (Eq, Show, Generic)
+
+instance NFData ChannelFlags
+
+-- | Encode ChannelFlags to Word8.
+encodeChannelFlags :: ChannelFlags -> Word8
+encodeChannelFlags cf =
+ (if cfDirection cf then 0x01 else 0x00) .|.
+ (if cfDisabled cf then 0x02 else 0x00)
+{-# INLINE encodeChannelFlags #-}
+
+-- | Decode Word8 to ChannelFlags.
+decodeChannelFlags :: Word8 -> ChannelFlags
+decodeChannelFlags w = ChannelFlags
+ { cfDirection = w .&. 0x01 /= 0
+ , cfDisabled = w .&. 0x02 /= 0
+ }
+{-# INLINE decodeChannelFlags #-}
+
-- Routing parameters ----------------------------------------------------------
-- | CLTV expiry delta.
diff --git a/plans/IMPL2.md b/plans/IMPL2.md
@@ -0,0 +1,346 @@
+# IMPL2: Refactoring and Type Safety Improvements
+
+## Overview
+
+Internal refactoring to reduce code duplication and improve type safety.
+These changes are purely internal - no API changes to exported functions.
+
+## Phase 1: Decoder Combinator (Codec.hs)
+
+**Goal:** Extract common decoder pattern into reusable combinator.
+
+**Files:** `lib/Lightning/Protocol/BOLT7/Codec.hs`
+
+**Current state:** Lines 140-211 contain 8 nearly-identical decoders:
+
+```haskell
+decodeSignature bs = do
+ (bytes, rest) <- decodeBytes signatureLen bs
+ case signature bytes of
+ Nothing -> Left DecodeInvalidSignature
+ Just s -> Right (s, rest)
+```
+
+**Tasks:**
+1. Add `decodeFixed` combinator in "Primitive helpers" section (~line 90):
+ ```haskell
+ decodeFixed :: Int -> DecodeError -> (ByteString -> Maybe a)
+ -> ByteString -> Either DecodeError (a, ByteString)
+ decodeFixed len err mkVal bs = do
+ (bytes, rest) <- decodeBytes len bs
+ case mkVal bytes of
+ Nothing -> Left err
+ Just v -> Right (v, rest)
+ {-# INLINE decodeFixed #-}
+ ```
+
+2. Rewrite type-specific decoders (lines 140-211) using `decodeFixed`:
+ ```haskell
+ decodeSignature :: ByteString -> Either DecodeError (Signature, ByteString)
+ decodeSignature = decodeFixed signatureLen DecodeInvalidSignature signature
+ {-# INLINE decodeSignature #-}
+ ```
+
+3. Apply to all 8 decoders:
+ - decodeSignature
+ - decodeChainHash
+ - decodeShortChannelId
+ - decodeChannelId
+ - decodeNodeId
+ - decodePoint
+ - decodeRgbColor
+ - decodeAlias
+
+**Verification:**
+- `cabal build` succeeds
+- `cabal test` passes (roundtrip tests verify correctness)
+
+**Dependencies:** None (can start immediately)
+
+---
+
+## Phase 2: Double-SHA256 Helper (Hash.hs)
+
+**Goal:** Extract repeated double-hash pattern.
+
+**Files:** `lib/Lightning/Protocol/BOLT7/Hash.hs`
+
+**Current state:** Lines 45, 56, 67 all contain:
+```haskell
+SHA256.hash (SHA256.hash payload)
+```
+
+**Tasks:**
+1. Add internal helper after imports (~line 32):
+ ```haskell
+ -- | Double SHA-256 hash (used for Lightning message signing).
+ doubleSha256 :: ByteString -> ByteString
+ doubleSha256 = SHA256.hash . SHA256.hash
+ {-# INLINE doubleSha256 #-}
+ ```
+
+2. Update `channelAnnouncementHash` (line 45):
+ ```haskell
+ in doubleSha256 payload
+ ```
+
+3. Update `nodeAnnouncementHash` (line 56):
+ ```haskell
+ in doubleSha256 payload
+ ```
+
+4. Update `channelUpdateHash` (line 67):
+ ```haskell
+ in doubleSha256 payload
+ ```
+
+**Verification:**
+- `cabal build` succeeds
+- `cabal test` passes
+
+**Dependencies:** None (can start immediately)
+
+---
+
+## Phase 3: Length-Prefixed Encoding Helper (Codec.hs)
+
+**Goal:** Extract repeated length-prefix encoding pattern.
+
+**Files:** `lib/Lightning/Protocol/BOLT7/Codec.hs`
+
+**Current state:** Pattern appears in 5 encoders:
+```haskell
+Prim.encodeU16 (fromIntegral $ BS.length features) <> features
+```
+
+Locations:
+- Line 273-274 (encodeChannelAnnouncement)
+- Line 326-327 (encodeNodeAnnouncement, features)
+- Line 332-333 (encodeNodeAnnouncement, addresses)
+- Line 479 (encodeQueryShortChannelIds)
+- Line 559 (encodeReplyChannelRange)
+
+**Tasks:**
+1. Add `encodeLenPrefixed` helper in "Primitive helpers" section (~line 90):
+ ```haskell
+ -- | Encode with u16 length prefix.
+ encodeLenPrefixed :: ByteString -> ByteString
+ encodeLenPrefixed bs =
+ Prim.encodeU16 (fromIntegral $ BS.length bs) <> bs
+ {-# INLINE encodeLenPrefixed #-}
+ ```
+
+2. Update all 5 locations to use the helper.
+
+**Verification:**
+- `cabal build` succeeds
+- `cabal test` passes
+
+**Dependencies:** None (can start immediately)
+
+---
+
+## Phase 4: Routing Parameter Newtypes (Types.hs)
+
+**Goal:** Replace type aliases with newtypes to prevent accidental mixing.
+
+**Files:**
+- `lib/Lightning/Protocol/BOLT7/Types.hs`
+- `lib/Lightning/Protocol/BOLT7/Messages.hs`
+- `lib/Lightning/Protocol/BOLT7/Codec.hs`
+
+**Current state (Types.hs:407-419):**
+```haskell
+type CltvExpiryDelta = Word16
+type FeeBaseMsat = Word32
+type FeeProportionalMillionths = Word32
+type HtlcMinimumMsat = Word64
+type HtlcMaximumMsat = Word64
+```
+
+**Tasks:**
+1. Convert type aliases to newtypes in Types.hs:
+ ```haskell
+ newtype CltvExpiryDelta = CltvExpiryDelta
+ { getCltvExpiryDelta :: Word16 }
+ deriving (Eq, Ord, Show, Generic)
+
+ instance NFData CltvExpiryDelta
+
+ newtype FeeBaseMsat = FeeBaseMsat
+ { getFeeBaseMsat :: Word32 }
+ deriving (Eq, Ord, Show, Generic)
+
+ instance NFData FeeBaseMsat
+
+ -- etc. for all 5 types
+ ```
+
+2. Update exports in Types.hs to include constructors and accessors.
+
+3. Update ChannelUpdate record in Messages.hs - no changes needed,
+ field types remain the same names.
+
+4. Update Codec.hs encode/decode:
+ - `encodeChannelUpdate`: wrap primitives in constructors
+ - `decodeChannelUpdate`: use constructors when building record
+
+5. Update Validate.hs if needed (comparison of HtlcMinimumMsat vs
+ HtlcMaximumMsat may need unwrapping).
+
+**Verification:**
+- `cabal build` succeeds
+- `cabal test` passes
+
+**Dependencies:** None (can start immediately)
+
+**Note:** This is the most invasive change. Consider whether the type
+safety benefit outweighs the additional unwrapping boilerplate.
+
+---
+
+## Phase 5: Channel Flags ADT (Optional)
+
+**Goal:** Replace raw Word8 flags with structured ADT.
+
+**Files:**
+- `lib/Lightning/Protocol/BOLT7/Types.hs`
+- `lib/Lightning/Protocol/BOLT7/Messages.hs`
+- `lib/Lightning/Protocol/BOLT7/Codec.hs`
+
+**Current state (Messages.hs:129-130):**
+```haskell
+chanUpdateMsgFlags :: !Word8
+chanUpdateChanFlags :: !Word8
+```
+
+**Tasks:**
+1. Add flag types to Types.hs:
+ ```haskell
+ -- | Message flags for channel_update.
+ data MessageFlags = MessageFlags
+ { mfHtlcMaximumPresent :: !Bool
+ }
+ deriving (Eq, Show, Generic)
+
+ instance NFData MessageFlags
+
+ -- | Channel flags for channel_update.
+ data ChannelFlags = ChannelFlags
+ { cfDirection :: !Bool -- ^ True = node_id_2 is origin
+ , cfDisabled :: !Bool -- ^ True = channel disabled
+ }
+ deriving (Eq, Show, Generic)
+
+ instance NFData ChannelFlags
+ ```
+
+2. Add encode/decode helpers:
+ ```haskell
+ encodeMessageFlags :: MessageFlags -> Word8
+ decodeMessageFlags :: Word8 -> MessageFlags
+
+ encodeChannelFlags :: ChannelFlags -> Word8
+ decodeChannelFlags :: Word8 -> ChannelFlags
+ ```
+
+3. Update ChannelUpdate in Messages.hs to use new types.
+
+4. Update Codec.hs to use encode/decode helpers.
+
+**Verification:**
+- `cabal build` succeeds
+- `cabal test` passes
+
+**Dependencies:** None (can start immediately)
+
+**Note:** This is optional. The benefit is making flag semantics explicit,
+but it adds complexity. Defer if unclear.
+
+---
+
+## Phase 6: Complete validateReplyChannelRange (Validate.hs)
+
+**Goal:** Implement the stubbed validation function.
+
+**Files:** `lib/Lightning/Protocol/BOLT7/Validate.hs`
+
+**Current state (lines 118-124):**
+```haskell
+validateReplyChannelRange :: ReplyChannelRange -> Either ValidationError ()
+validateReplyChannelRange _msg = do
+ Right () -- stubbed
+```
+
+**Tasks:**
+1. Import `decodeShortChannelIdList` from Codec module.
+
+2. Implement ascending order check:
+ ```haskell
+ validateReplyChannelRange msg = do
+ case decodeShortChannelIdList (replyRangeData msg) of
+ Left _ -> Right () -- Can't decode, skip validation
+ Right scids -> checkAscending scids
+ where
+ checkAscending [] = Right ()
+ checkAscending [_] = Right ()
+ checkAscending (a:b:rest)
+ | getShortChannelId a < getShortChannelId b = checkAscending (b:rest)
+ | otherwise = Left ValidateScidNotAscending
+ ```
+
+**Verification:**
+- `cabal build` succeeds
+- `cabal test` passes
+- Add test case for non-ascending SCIDs
+
+**Dependencies:** None (can start immediately)
+
+---
+
+## Dependency Graph
+
+```
+Phase 1 (decoder combinator) \
+ \
+Phase 2 (double-sha256) -------+---> All can proceed in parallel
+ /
+Phase 3 (len-prefixed) ------/
+ /
+Phase 4 (routing newtypes) -/
+
+Phase 5 (channel flags) -----> Optional, defer if needed
+
+Phase 6 (validation) --------> Independent
+```
+
+All phases are independent and can be executed in parallel.
+
+---
+
+## Complexity and Risk
+
+| Phase | Complexity | Risk | Lines Changed | Notes |
+|-------|------------|--------|---------------|--------------------------|
+| 1 | Low | Low | ~80 | Pure extraction |
+| 2 | Low | Low | ~10 | Trivial |
+| 3 | Low | Low | ~15 | Pure extraction |
+| 4 | Medium | Medium | ~50 | Touches multiple modules |
+| 5 | Medium | Medium | ~40 | Optional, defer if unsure|
+| 6 | Low | Low | ~15 | Completes stub |
+
+---
+
+## Execution Order Recommendation
+
+1. **First batch (parallel):** Phases 1, 2, 3, 6
+ - Low risk, immediate benefit
+ - Can be done by separate agents concurrently
+
+2. **Second batch:** Phase 4
+ - Review after first batch merges
+ - Evaluate if type safety benefit justifies churn
+
+3. **Defer:** Phase 5
+ - Nice-to-have but adds complexity
+ - Revisit if flag handling becomes error-prone
diff --git a/test/Main.hs b/test/Main.hs
@@ -201,8 +201,9 @@ channel_update_tests = testGroup "ChannelUpdate" [
, chanUpdateChainHash = testChainHash
, chanUpdateShortChanId = testShortChannelId
, chanUpdateTimestamp = 1234567890
- , chanUpdateMsgFlags = 0x00
- , chanUpdateChanFlags = 0x01
+ , chanUpdateMsgFlags = MessageFlags { mfHtlcMaxPresent = False }
+ , chanUpdateChanFlags = ChannelFlags
+ { cfDirection = True, cfDisabled = False }
, chanUpdateCltvExpDelta = CltvExpiryDelta 144
, chanUpdateHtlcMinMsat = HtlcMinimumMsat 1000
, chanUpdateFeeBaseMsat = FeeBaseMsat 1000
@@ -219,8 +220,9 @@ channel_update_tests = testGroup "ChannelUpdate" [
, chanUpdateChainHash = testChainHash
, chanUpdateShortChanId = testShortChannelId
, chanUpdateTimestamp = 1234567890
- , chanUpdateMsgFlags = 0x01 -- bit 0 set
- , chanUpdateChanFlags = 0x00
+ , chanUpdateMsgFlags = MessageFlags { mfHtlcMaxPresent = True }
+ , chanUpdateChanFlags = ChannelFlags
+ { cfDirection = False, cfDisabled = False }
, chanUpdateCltvExpDelta = CltvExpiryDelta 40
, chanUpdateHtlcMinMsat = HtlcMinimumMsat 1000
, chanUpdateFeeBaseMsat = FeeBaseMsat 500
@@ -419,8 +421,9 @@ hash_tests = testGroup "Hash Functions" [
, chanUpdateChainHash = testChainHash
, chanUpdateShortChanId = testShortChannelId
, chanUpdateTimestamp = 1234567890
- , chanUpdateMsgFlags = 0x00
- , chanUpdateChanFlags = 0x00
+ , chanUpdateMsgFlags = MessageFlags { mfHtlcMaxPresent = False }
+ , chanUpdateChanFlags = ChannelFlags
+ { cfDirection = False, cfDisabled = False }
, chanUpdateCltvExpDelta = CltvExpiryDelta 144
, chanUpdateHtlcMinMsat = HtlcMinimumMsat 1000
, chanUpdateFeeBaseMsat = FeeBaseMsat 1000
@@ -438,8 +441,9 @@ hash_tests = testGroup "Hash Functions" [
, chanUpdateChainHash = testChainHash
, chanUpdateShortChanId = testShortChannelId
, chanUpdateTimestamp = 1234567890
- , chanUpdateMsgFlags = 0x00
- , chanUpdateChanFlags = 0x00
+ , chanUpdateMsgFlags = MessageFlags { mfHtlcMaxPresent = False }
+ , chanUpdateChanFlags = ChannelFlags
+ { cfDirection = False, cfDisabled = False }
, chanUpdateCltvExpDelta = CltvExpiryDelta 144
, chanUpdateHtlcMinMsat = HtlcMinimumMsat 1000
, chanUpdateFeeBaseMsat = FeeBaseMsat 1000
@@ -456,8 +460,9 @@ hash_tests = testGroup "Hash Functions" [
, chanUpdateChainHash = testChainHash
, chanUpdateShortChanId = testShortChannelId
, chanUpdateTimestamp = 1000000000
- , chanUpdateMsgFlags = 0x00
- , chanUpdateChanFlags = 0x00
+ , chanUpdateMsgFlags = MessageFlags { mfHtlcMaxPresent = False }
+ , chanUpdateChanFlags = ChannelFlags
+ { cfDirection = False, cfDisabled = False }
, chanUpdateCltvExpDelta = CltvExpiryDelta 144
, chanUpdateHtlcMinMsat = HtlcMinimumMsat 1000
, chanUpdateFeeBaseMsat = FeeBaseMsat 1000
@@ -469,8 +474,9 @@ hash_tests = testGroup "Hash Functions" [
, chanUpdateChainHash = testChainHash
, chanUpdateShortChanId = testShortChannelId
, chanUpdateTimestamp = 2000000000
- , chanUpdateMsgFlags = 0x00
- , chanUpdateChanFlags = 0x00
+ , chanUpdateMsgFlags = MessageFlags { mfHtlcMaxPresent = False }
+ , chanUpdateChanFlags = ChannelFlags
+ { cfDirection = False, cfDisabled = False }
, chanUpdateCltvExpDelta = CltvExpiryDelta 144
, chanUpdateHtlcMinMsat = HtlcMinimumMsat 1000
, chanUpdateFeeBaseMsat = FeeBaseMsat 1000
@@ -524,8 +530,9 @@ validation_tests = testGroup "Validation" [
, chanUpdateChainHash = testChainHash
, chanUpdateShortChanId = testShortChannelId
, chanUpdateTimestamp = 1234567890
- , chanUpdateMsgFlags = 0x01
- , chanUpdateChanFlags = 0x00
+ , chanUpdateMsgFlags = MessageFlags { mfHtlcMaxPresent = True }
+ , chanUpdateChanFlags = ChannelFlags
+ { cfDirection = False, cfDisabled = False }
, chanUpdateCltvExpDelta = CltvExpiryDelta 144
, chanUpdateHtlcMinMsat = HtlcMinimumMsat 1000
, chanUpdateFeeBaseMsat = FeeBaseMsat 1000
@@ -539,8 +546,9 @@ validation_tests = testGroup "Validation" [
, chanUpdateChainHash = testChainHash
, chanUpdateShortChanId = testShortChannelId
, chanUpdateTimestamp = 1234567890
- , chanUpdateMsgFlags = 0x01
- , chanUpdateChanFlags = 0x00
+ , chanUpdateMsgFlags = MessageFlags { mfHtlcMaxPresent = True }
+ , chanUpdateChanFlags = ChannelFlags
+ { cfDirection = False, cfDisabled = False }
, chanUpdateCltvExpDelta = CltvExpiryDelta 144
, chanUpdateHtlcMinMsat = HtlcMinimumMsat 2000000000 -- > htlcMax
, chanUpdateFeeBaseMsat = FeeBaseMsat 1000
@@ -634,8 +642,9 @@ propChannelUpdateRoundtrip timestamp cltvDelta = property $ do
, chanUpdateChainHash = testChainHash
, chanUpdateShortChanId = testShortChannelId
, chanUpdateTimestamp = timestamp
- , chanUpdateMsgFlags = 0x00
- , chanUpdateChanFlags = 0x00
+ , chanUpdateMsgFlags = MessageFlags { mfHtlcMaxPresent = False }
+ , chanUpdateChanFlags = ChannelFlags
+ { cfDirection = False, cfDisabled = False }
, chanUpdateCltvExpDelta = CltvExpiryDelta cltvDelta
, chanUpdateHtlcMinMsat = HtlcMinimumMsat 1000
, chanUpdateFeeBaseMsat = FeeBaseMsat 1000