Validate.hs (3970B)
1 {-# OPTIONS_HADDOCK hide #-} 2 {-# LANGUAGE DeriveGeneric #-} 3 4 -- | 5 -- Module: Lightning.Protocol.BOLT7.Validate 6 -- Copyright: (c) 2025 Jared Tobin 7 -- License: MIT 8 -- Maintainer: Jared Tobin <jared@ppad.tech> 9 -- 10 -- Stateless checks of BOLT #7 messages. 11 12 module Lightning.Protocol.BOLT7.Validate ( 13 ValidationError(..) 14 , validate_channel_announcement 15 , validate_node_announcement 16 , validate_channel_update 17 , validate_query_short_channel_ids 18 , validate_query_channel_range 19 , validate_reply_channel_range 20 ) where 21 22 import Control.DeepSeq (NFData) 23 import Data.Word (Word64) 24 import GHC.Generics (Generic) 25 import Lightning.Protocol.BOLT1 (ShortChannelId) 26 import Lightning.Protocol.BOLT7.Messages 27 import Lightning.Protocol.BOLT7.Types 28 29 -- | A rule a message breaks. 30 data ValidationError 31 = ValidateNodeIdOrdering 32 -- ^ @node_id_1@ is not lexicographically less than @node_id_2@ 33 | ValidateMultipleDns 34 -- ^ more than one DNS hostname descriptor 35 | ValidateHtlcAmounts 36 -- ^ @htlc_minimum_msat@ exceeds @htlc_maximum_msat@ 37 | ValidateZeroBlocks 38 -- ^ @number_of_blocks@ is 0 39 | ValidateBlockOverflow 40 -- ^ the block range extends past block 2^32 - 1 41 | ValidateScidNotAscending 42 -- ^ short channel ids are not in strictly ascending order 43 deriving (Eq, Show, Generic) 44 45 instance NFData ValidationError 46 47 -- | Check that @node_id_1@ is lexicographically less than @node_id_2@; 48 -- a receiver must ignore the message otherwise. 49 -- 50 -- Signatures and feature bits are not checked here; see 51 -- 'Lightning.Protocol.BOLT7.verify_channel_announcement' and 52 -- ppad-bolt9's @validate_remote@. 53 validate_channel_announcement 54 :: ChannelAnnouncement -> Either ValidationError () 55 validate_channel_announcement m 56 | ca_node_id_1 m < ca_node_id_2 m = Right () 57 | otherwise = Left ValidateNodeIdOrdering 58 59 -- | Check that at most one DNS hostname is announced; a receiver must 60 -- not forward the message otherwise. 61 -- 62 -- Descriptors a receiver should merely ignore (Tor v2, port 0, a 63 -- hostname that isn't ASCII) are left to 64 -- 'Lightning.Protocol.BOLT7.usable_addresses'. 65 validate_node_announcement :: NodeAnnouncement -> Either ValidationError () 66 validate_node_announcement m 67 | length [ () | AddrDNS _ _ <- na_addresses m ] > 1 = 68 Left ValidateMultipleDns 69 | otherwise = Right () 70 71 -- | Check that @htlc_minimum_msat@ does not exceed @htlc_maximum_msat@; 72 -- a receiver should not route through the channel otherwise. 73 validate_channel_update :: ChannelUpdate -> Either ValidationError () 74 validate_channel_update m 75 | cu_htlc_minimum_msat m > cu_htlc_maximum_msat m = Left ValidateHtlcAmounts 76 | otherwise = Right () 77 78 -- | Check that the short channel ids are in strictly ascending order, as 79 -- their encoding requires. 80 validate_query_short_channel_ids 81 :: QueryShortChannelIds -> Either ValidationError () 82 validate_query_short_channel_ids = ascending . qsci_short_channel_ids 83 84 -- | Check that @number_of_blocks@ is at least 1, as the sender must 85 -- ensure, and that the range ends at or before block 2^32 - 1 (a 86 -- library rule: such a range can't be represented). 87 validate_query_channel_range 88 :: QueryChannelRange -> Either ValidationError () 89 validate_query_channel_range m 90 | num == 0 = Left ValidateZeroBlocks 91 | first + num > 0x100000000 = Left ValidateBlockOverflow 92 | otherwise = Right () 93 where 94 first = fromIntegral (qcr_first_blocknum m) :: Word64 95 num = fromIntegral (qcr_number_of_blocks m) :: Word64 96 97 -- | Check that the short channel ids are in strictly ascending order, as 98 -- their encoding requires. 99 validate_reply_channel_range 100 :: ReplyChannelRange -> Either ValidationError () 101 validate_reply_channel_range = ascending . rcr_short_channel_ids 102 103 ascending :: [ShortChannelId] -> Either ValidationError () 104 ascending (a : rest@(b : _)) 105 | a < b = ascending rest 106 | otherwise = Left ValidateScidNotAscending 107 ascending _ = Right ()