From 5d2e86dbfa55203b0e8f6e127aa88afe745c518d Mon Sep 17 00:00:00 2001 From: edgr Date: Sat, 8 Nov 2025 09:35:31 +0800 Subject: [PATCH 01/24] Add behind firewall flag to local root config --- .../lib/Cardano/Network/Diffusion/Topology.hs | 1 + .../Test/Cardano/Network/Diffusion/Testnet.hs | 61 ++++++++++--------- .../lib/Test/Cardano/Network/PeerSelection.hs | 12 ++-- .../Ouroboros/Network/Diffusion/Topology.hs | 22 +++++-- .../Network/PeerSelection/State/KnownPeers.hs | 3 + .../PeerSelection/State/LocalRootPeers.hs | 7 ++- .../Ouroboros/Network/OrphanInstances.hs | 21 ++++++- .../Network/PeerSelection/Instances.hs | 1 + .../Network/PeerSelection/RootPeersDNS.hs | 4 +- 9 files changed, 84 insertions(+), 48 deletions(-) diff --git a/cardano-diffusion/lib/Cardano/Network/Diffusion/Topology.hs b/cardano-diffusion/lib/Cardano/Network/Diffusion/Topology.hs index f4db255abe4..ee741d0472d 100644 --- a/cardano-diffusion/lib/Cardano/Network/Diffusion/Topology.hs +++ b/cardano-diffusion/lib/Cardano/Network/Diffusion/Topology.hs @@ -30,5 +30,6 @@ isValidTrustedPeerConfiguration IsTrustable -> not . null . rootAccessPoints + . rootConfig $ localRoots ) lprgs diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs index 3e4ac9f977b..14251fc2966 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs @@ -388,7 +388,7 @@ unit_cm_valid_transitions = [ (HotValency {getHotValency = 1}, WarmValency {getWarmValency = 1}, Map.fromList [(RelayAccessAddress "0:71:0:1:0:1:0:1" 65_534, - LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsTrustable)]) + LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsTrustable)]) ] (Script (LedgerPools [] :| [])) (PeerSelectionTargets @@ -430,7 +430,7 @@ unit_cm_valid_transitions = [ (HotValency {getHotValency = 1}, WarmValency {getWarmValency = 1}, Map.fromList [(RelayAccessAddress "0:79::1:0:0" 3, - LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsTrustable)]) + LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsTrustable)]) ] (Script (LedgerPools [] :| [])) ( PeerSelectionTargets @@ -634,7 +634,7 @@ unit_connection_manager_trace_coverage = naPeerSharing = PeerSharingDisabled, naLocalRootPeers = [ (1,1,Map.fromList [ (RelayAccessAddress (read "127.0.0.1") 1000, - LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable) + LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) ]) ], naLedgerPeers = Script (LedgerPools [] :| []), @@ -757,7 +757,7 @@ unit_connection_manager_transitions_coverage = naPeerSharing = PeerSharingDisabled, naLocalRootPeers = [ (1,1,Map.fromList [ (RelayAccessAddress (read "127.0.0.1") 1000, - LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable) + LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) ]) ], naLedgerPeers = Script (LedgerPools [] :| []), @@ -883,6 +883,7 @@ prop_txSubmission_allTransactions (ArbTxDecisionPolicy decisionPolicy) let localRootConfig = LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode + False IsNotTrustable diffScript = DiffusionScript @@ -1319,8 +1320,8 @@ unit_4177 = prop_inbound_governor_transitions_coverage absNoAttenuation script (Script (UseBootstrapPeers [RelayAccessDomain "bootstrap" 0] :| [])) (TestAddress (IPAddr (read "0:7:0:7::") 65_533)) PeerSharingDisabled - [ (1,1,Map.fromList [(RelayAccessDomain "test2" 65_535,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable) - , (RelayAccessAddress "0:6:0:3:0:6:0:5" 65_530,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)]) + [ (1,1,Map.fromList [(RelayAccessDomain "test2" 65_535,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) + , (RelayAccessAddress "0:6:0:3:0:6:0:5" 65_530,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]) ] (Script (LedgerPools [] :| [])) (nullPeerSelectionTargets { @@ -1338,11 +1339,11 @@ unit_4177 = prop_inbound_governor_transitions_coverage absNoAttenuation script (Script (PraosFetchMode FetchModeDeadline :| [])) [] , [JoinNetwork 1.742_857_142_857 - ,Reconfigure 6.333_333_333_33 [(1,1,Map.fromList [(RelayAccessDomain "test2" 65_535,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)]), - (1,1,Map.fromList [(RelayAccessAddress "0:6:0:3:0:6:0:5" 65_530,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable) + ,Reconfigure 6.333_333_333_33 [(1,1,Map.fromList [(RelayAccessDomain "test2" 65_535,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]), + (1,1,Map.fromList [(RelayAccessAddress "0:6:0:3:0:6:0:5" 65_530,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) ])] - ,Reconfigure 23.888_888_888_88 [(1,1,Map.empty),(1,1,Map.fromList [(RelayAccessAddress "0:6:0:3:0:6:0:5" 65_530,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])] - ,Reconfigure 4.870_967_741_935 [(1,1,Map.fromList [(RelayAccessDomain "test2" 65_535,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])] + ,Reconfigure 23.888_888_888_88 [(1,1,Map.empty),(1,1,Map.fromList [(RelayAccessAddress "0:6:0:3:0:6:0:5" 65_530,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] + ,Reconfigure 4.870_967_741_935 [(1,1,Map.fromList [(RelayAccessDomain "test2" 65_535,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] ] ) , ( NodeArgs 1 InitiatorAndResponderDiffusionMode @@ -1992,8 +1993,8 @@ unit_4191 = testWithIOSim prop_diffusion_dns_can_recover long_trace absInfo scri (Script (UseBootstrapPeers [RelayAccessDomain "bootstrap" 0] :| [])) (TestAddress (IPAddr (read "0.0.1.236") 65_527)) PeerSharingDisabled - [ (2,2,Map.fromList [ (RelayAccessDomain "test2" 15,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable) - , (RelayAccessDomain "test3" 4,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)]) + [ (2,2,Map.fromList [ (RelayAccessDomain "test2" 15,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) + , (RelayAccessDomain "test3" 4,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]) ] (Script (LedgerPools [] :| [])) (PeerSelectionTargets @@ -2043,7 +2044,7 @@ unit_4191 = testWithIOSim prop_diffusion_dns_can_recover long_trace absInfo scri , Reconfigure 0.415_384_615_384 [(1,1,Map.empty) , (1,1,Map.empty)] , Reconfigure 15.550_561_797_752 [(1,1,Map.empty) - , (1,1,Map.fromList [(RelayAccessDomain "test2" 15,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])] + , (1,1,Map.fromList [(RelayAccessDomain "test2" 15,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] , Reconfigure 82.857_142_857_14 [] ]) ] @@ -2108,7 +2109,7 @@ prop_connect_failure (AbsIOError ioerr) = naBootstrapPeers = Script (DontUseBootstrapPeers :| []), naAddr = TestAddress (IPAddr nodeIP nodePort), naPeerSharing = PeerSharingDisabled, - naLocalRootPeers = [(1,1,Map.fromList [(RelayAccessAddress relayIP relayPort,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])], + naLocalRootPeers = [(1,1,Map.fromList [(RelayAccessAddress relayIP relayPort,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], naLedgerPeers = Script (LedgerPools [] :| []), naPeerTargets = (PeerSelectionTargets { targetNumberOfRootPeers = 1, @@ -2236,7 +2237,7 @@ prop_accept_failure (AbsIOError ioerr) = naBootstrapPeers = Script (DontUseBootstrapPeers :| []), naAddr = TestAddress (IPAddr nodeIP nodePort), naPeerSharing = PeerSharingDisabled, - naLocalRootPeers = [(1,1,Map.fromList [(RelayAccessAddress relayIP relayPort,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])], + naLocalRootPeers = [(1,1,Map.fromList [(RelayAccessAddress relayIP relayPort,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], naLedgerPeers = Script (LedgerPools [] :| []), naPeerTargets = (PeerSelectionTargets { targetNumberOfRootPeers = 1, @@ -3225,21 +3226,21 @@ async_demotion_network_script = ] ) , ( common { naAddr = addr2, - naLocalRootPeers = [(1,1, Map.fromList [(ra_addr1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])] } + naLocalRootPeers = [(1,1, Map.fromList [(ra_addr1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] } , [JoinNetwork 0, Kill 5, JoinNetwork 20] ) , ( common { naAddr = addr3, - naLocalRootPeers = [(1,1, Map.fromList [(ra_addr1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])] } + naLocalRootPeers = [(1,1, Map.fromList [(ra_addr1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] } , [JoinNetwork 0] ) ] where addr1 = TestAddress (IPAddr (read "10.0.0.1") 3000) ra_addr1 = RelayAccessAddress (read "10.0.0.1") 3000 - localRoots1 = [(2,2, Map.fromList [(ra_addr2, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable) - ,(ra_addr3, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])] - localRoots1' = [(2,2, Map.fromList [(ra_addr2, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable) - ,(ra_addr3, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])] + localRoots1 = [(2,2, Map.fromList [(ra_addr2, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) + ,(ra_addr3, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] + localRoots1' = [(2,2, Map.fromList [(ra_addr2, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) + ,(ra_addr3, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] addr2 = TestAddress (IPAddr (read "10.0.0.2") 3000) ra_addr2 = RelayAccessAddress (read "10.0.0.2") 3000 @@ -3821,7 +3822,7 @@ prop_unit_4258 = (Script (UseBootstrapPeers [RelayAccessDomain "bootstrap" 0] :| [])) (TestAddress (IPAddr (read "0.0.0.4") 9)) PeerSharingDisabled - [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.8" 65_531,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])] + [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.8" 65_531,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] (Script (LedgerPools [] :| [])) (nullPeerSelectionTargets { targetNumberOfRootPeers = 2, @@ -3856,7 +3857,7 @@ prop_unit_4258 = (Script (UseBootstrapPeers [RelayAccessDomain "bootstrap" 0] :| [])) (TestAddress (IPAddr (read "0.0.0.8") 65_531)) PeerSharingDisabled - [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.4" 9,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])] + [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.4" 9,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] (Script (LedgerPools [] :| [])) (nullPeerSelectionTargets { targetNumberOfRootPeers = 4, @@ -3887,7 +3888,7 @@ prop_unit_4258 = (Script (PraosFetchMode FetchModeDeadline :| [])) [] , [ JoinNetwork 3.384_615_384_615, - Reconfigure 3.583_333_333_333 [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.4" 9,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])], + Reconfigure 3.583_333_333_333 [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.4" 9,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], Kill 15.555_555_555_55, JoinNetwork 30.533_333_333_33, Kill 71.111_111_111_11 @@ -3928,8 +3929,8 @@ prop_unit_reconnect = (Script (DontUseBootstrapPeers :| [])) (TestAddress (IPAddr (read "0.0.0.0") 0)) PeerSharingDisabled - [ (2,2,Map.fromList [ (RelayAccessAddress "0.0.0.1" 0,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable) - , (RelayAccessAddress "0.0.0.2" 0,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable) + [ (2,2,Map.fromList [ (RelayAccessAddress "0.0.0.1" 0,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) + , (RelayAccessAddress "0.0.0.2" 0,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) ]) ] (Script (LedgerPools [] :| [])) @@ -3959,7 +3960,7 @@ prop_unit_reconnect = (Script (DontUseBootstrapPeers :| [])) (TestAddress (IPAddr (read "0.0.0.1") 0)) PeerSharingDisabled - [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.0" 0,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])] + [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.0" 0,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] (Script (LedgerPools [] :| [])) (PeerSelectionTargets { targetNumberOfRootPeers = 1, @@ -4410,7 +4411,7 @@ unit_peer_sharing = (mainnetSimArgs 3 defaultTxDecisionPolicy) (singletonScript (mempty, ShortDelay)) [ ( (defaultNodeArgs GenesisMode) { naAddr = ip_0, - naLocalRootPeers = [(1, 1, Map.fromList [(ra_1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])], + naLocalRootPeers = [(1, 1, Map.fromList [(ra_1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], naPeerTargets = targets 1 } , [JoinNetwork 0] @@ -4422,7 +4423,7 @@ unit_peer_sharing = , [JoinNetwork 0] ) , ( (defaultNodeArgs GenesisMode) { naAddr = ip_2, - naLocalRootPeers = [(1, 1, Map.fromList [(ra_1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])], + naLocalRootPeers = [(1, 1, Map.fromList [(ra_1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], naPeerTargets = targets 2 } , [JoinNetwork 0] @@ -4941,7 +4942,7 @@ unit_local_root_diffusion_mode diffusionMode = naPeerSharing = PeerSharingDisabled, naLocalRootPeers = [ (1,1,Map.fromList [ (RelayAccessAddress (read "127.0.0.1") 1000, - LocalRootConfig DoNotAdvertisePeer diffusionMode IsNotTrustable) + LocalRootConfig DoNotAdvertisePeer diffusionMode False IsNotTrustable) ]) ], naLedgerPeers = Script (LedgerPools [] :| []), diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs index 246500f48da..ad68f726f16 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs @@ -4431,8 +4431,8 @@ prop_issue_3550 = prop_governor_target_established_below defaultMaxTime $ (PeerAddr 29,[],GovernorScripts {peerShareScript = Script (Nothing :| []), peerSharingScript = Script (PeerSharingDisabled :| []), connectionScript = Script ((ToWarm,NoDelay) :| [(ToCold,NoDelay),(Noop,NoDelay)])}) ], localRootPeers = LocalRootPeers.fromGroups - [ (1, 1, Map.fromList [(PeerAddr 16, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)]) - , (1, 1, Map.fromList [(PeerAddr 4, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)]) + [ (1, 1, Map.fromList [(PeerAddr 16, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]) + , (1, 1, Map.fromList [(PeerAddr 4, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]) ], publicRootPeers = Cardano.PublicRootPeers.fromPublicRootPeers (Map.fromList [ (PeerAddr 14, DoNotAdvertisePeer) @@ -4479,7 +4479,7 @@ prop_issue_3515 = prop_governor_nolivelock $ peerSharingScript = Script (PeerSharingDisabled :| []), connectionScript = Script ((ToCold,NoDelay) :| [(Noop,NoDelay)]) })], - localRootPeers = LocalRootPeers.fromGroups [(1,1,Map.fromList [(PeerAddr 10, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])], + localRootPeers = LocalRootPeers.fromGroups [(1,1,Map.fromList [(PeerAddr 10, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], publicRootPeers = PublicRootPeers.empty Cardano.ExtraPeers.empty, targets = Script . NonEmpty.fromList $ targets'', pickKnownPeersForPeerShare = Script (PickFirst :| []), @@ -4521,7 +4521,7 @@ prop_issue_3494 = prop_governor_nofail $ peerSharingScript = Script (PeerSharingDisabled :| []), connectionScript = Script ((ToCold,NoDelay) :| [(Noop,NoDelay)]) })], - localRootPeers = LocalRootPeers.fromGroups [(1,1,Map.fromList [(PeerAddr 64, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)])], + localRootPeers = LocalRootPeers.fromGroups [(1,1,Map.fromList [(PeerAddr 64, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], publicRootPeers = PublicRootPeers.empty Cardano.ExtraPeers.empty, targets = Script . NonEmpty.fromList $ targets'', pickKnownPeersForPeerShare = Script (PickFirst :| []), @@ -4571,8 +4571,8 @@ prop_issue_3233 = prop_governor_nolivelock $ (PeerAddr 15,[],GovernorScripts {peerShareScript = Script (Just ([],PeerShareTimeSlow) :| []), peerSharingScript = Script (PeerSharingDisabled :| []), connectionScript = Script ((Noop,NoDelay) :| [])}) ], localRootPeers = LocalRootPeers.fromGroups - [ (1, 1, Map.fromList [(PeerAddr 15, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)]) - , (1, 1, Map.fromList [(PeerAddr 13, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode IsNotTrustable)]) + [ (1, 1, Map.fromList [(PeerAddr 15, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]) + , (1, 1, Map.fromList [(PeerAddr 13, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]) ], publicRootPeers = Cardano.PublicRootPeers.fromPublicRootPeers (Map.fromList [(PeerAddr 4, DoNotAdvertisePeer)]), diff --git a/ouroboros-network/lib/Ouroboros/Network/Diffusion/Topology.hs b/ouroboros-network/lib/Ouroboros/Network/Diffusion/Topology.hs index bded6a924a8..bc6b4024daa 100644 --- a/ouroboros-network/lib/Ouroboros/Network/Diffusion/Topology.hs +++ b/ouroboros-network/lib/Ouroboros/Network/Diffusion/Topology.hs @@ -32,7 +32,7 @@ newtype LocalRootPeersGroups extraFlags = LocalRootPeersGroups -- will attempt to maintain. By default this value will be equal to 'hotValency'. -- data LocalRootPeersGroup extraFlags = LocalRootPeersGroup - { localRoots :: RootConfig + { localRoots :: LocalRoots , hotValency :: HotValency , warmValency :: WarmValency , rootDiffusionMode :: DiffusionMode @@ -44,6 +44,12 @@ newtype PublicRootPeers = PublicRootPeers { publicRoots :: RootConfig } deriving (Eq, Show) +data LocalRoots = LocalRoots + { rootConfig :: RootConfig + , behindFirewall :: Bool + -- ^ peer is unreachable and will initiate the connection first + } deriving (Eq, Show) + -- | Each root peer consists of a list of access points and a shared -- 'PeerAdvertise' field. -- @@ -63,9 +69,16 @@ data RootConfig = RootConfig rootConfigToRelayAccessPoint :: RootConfig -> [(RelayAccessPoint, PeerAdvertise)] -rootConfigToRelayAccessPoint RootConfig { rootAccessPoints, rootAdvertise } = +rootConfigToRelayAccessPoint RootConfig { rootAccessPoints, rootAdvertise } = [ (ap, rootAdvertise) | ap <- rootAccessPoints ] +localRootsToRelayAccessPoint + :: LocalRoots + -> [(RelayAccessPoint, PeerAdvertise, Bool)] +localRootsToRelayAccessPoint LocalRoots {rootConfig, behindFirewall} = + (\(accessPoint, advertise) -> (accessPoint, advertise, behindFirewall)) + <$> rootConfigToRelayAccessPoint rootConfig + producerAddresses :: NetworkTopology extraConfig extraFlags -> ( [(HotValency, WarmValency, Map RelayAccessPoint (LocalRootConfig extraFlags))] @@ -78,16 +91,17 @@ producerAddresses NetworkTopology { localRootPeersGroups ( map (\lrp -> ( hotValency lrp , warmValency lrp , Map.fromList - . map (\(addr, peerAdvertise) -> + . map (\(addr, peerAdvertise, localRootBehindFirewall) -> ( addr , LocalRootConfig { diffusionMode = rootDiffusionMode lrp, peerAdvertise, + localRootBehindFirewall, extraLocalRootFlags = extraFlags lrp } ) ) - . rootConfigToRelayAccessPoint + . localRootsToRelayAccessPoint $ localRoots lrp ) ) diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/KnownPeers.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/KnownPeers.hs index 537a439f3ca..a7eeefb08c7 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/KnownPeers.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/KnownPeers.hs @@ -79,6 +79,9 @@ data KnownPeers peeraddr = KnownPeers { -- establish a connection to now. This is because we have not connected -- with them before or because any failure backoff time has expired. -- + -- Note: Some peers may be behind a firewall. Local root peers marked as + -- behind a firewall are not excluded from this list. + -- availableToConnect :: !(Set peeraddr), -- | The subset of known peers that we cannot connect to for the moment. diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/LocalRootPeers.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/LocalRootPeers.hs index a753b30918c..efa4735e9eb 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/LocalRootPeers.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/LocalRootPeers.hs @@ -44,9 +44,10 @@ import Ouroboros.Network.PeerSelection.PeerAdvertise (PeerAdvertise) -- data LocalRootConfig extraFlags = LocalRootConfig { - peerAdvertise :: !PeerAdvertise, - diffusionMode :: !DiffusionMode, - extraLocalRootFlags :: !extraFlags + peerAdvertise :: !PeerAdvertise, + diffusionMode :: !DiffusionMode, + localRootBehindFirewall :: !Bool, + extraLocalRootFlags :: !extraFlags } deriving (Show, Eq) diff --git a/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs b/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs index 275fad7d22a..5371014d4e3 100644 --- a/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs +++ b/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs @@ -69,7 +69,7 @@ import Ouroboros.Network.DeltaQ (GSV (GSV), PeerGSV (PeerGSV, inboundGSV, outboundGSV)) import Ouroboros.Network.Diffusion.Topology (LocalRootPeersGroup (..), LocalRootPeersGroups (..), NetworkTopology (..), - PublicRootPeers (..), RootConfig (..)) + PublicRootPeers (..), LocalRoots (..), RootConfig (..)) import Ouroboros.Network.Diffusion.Types (DiffusionTracer (..)) import Ouroboros.Network.DiffusionMode import Ouroboros.Network.Driver.Simple @@ -97,6 +97,21 @@ kindObject k fields = object $ ("kind" .= String k) : fields -- FromJSON Instances +instance FromJSON LocalRoots where + parseJSON = withObject "LocalRoots" $ \o -> + LocalRoots + <$> (RootConfig + <$> o .: "accessPoints" + <*> o .:? "advertise" .!= DoNotAdvertisePeer) + <*> o .:? "behindFirewall" .!= False + +instance ToJSON LocalRoots where + toJSON ra = + object + [ "rootConfig" .= rootConfig ra + , "behindFirewall" .= behindFirewall ra + ] + instance FromJSON RootConfig where parseJSON = withObject "RootConfig" $ \o -> RootConfig @@ -144,8 +159,8 @@ localRootPeersGroupToJSON :: (extraFlags -> Maybe (Key, Value)) -> Value localRootPeersGroupToJSON extraFlagsToJSON lrpg@LocalRootPeersGroup {extraFlags} = Object $ - ("accessPoints" .?= rootAccessPoints (localRoots lrpg)) - <> ("advertise" .?= rootAdvertise (localRoots lrpg)) + ("accessPoints" .?= rootAccessPoints (rootConfig . localRoots $ lrpg)) + <> ("advertise" .?= rootAdvertise (rootConfig . localRoots $ lrpg)) <> ("hotValency" .?= hotValency lrpg) <> ("warmValency" .?= warmValency lrpg) <> foldMap (uncurry (.?=)) (extraFlagsToJSON extraFlags) diff --git a/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/Instances.hs b/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/Instances.hs index f1896197a3d..b2043ed64b2 100644 --- a/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/Instances.hs +++ b/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/Instances.hs @@ -172,6 +172,7 @@ instance Arbitrary extraFlags => Arbitrary (LocalRootConfig extraFlags) where <$> arbitrary <*> elements [InitiatorAndResponderDiffusionMode, InitiatorOnlyDiffusionMode] <*> arbitrary + <*> arbitrary shrink a@LocalRootConfig { peerAdvertise, extraLocalRootFlags = peerTrustable, diffusionMode diff --git a/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/RootPeersDNS.hs b/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/RootPeersDNS.hs index 1c1aec5929a..0315c071619 100644 --- a/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/RootPeersDNS.hs +++ b/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/RootPeersDNS.hs @@ -344,10 +344,10 @@ simpleMockRoots = MockRoots localRootPeers dnsMap Map.empty (singletonScript Map [ ( 2, 2 , Map.fromList [ ( RelayAccessAddress (read "192.0.2.1") (read "3333") - , LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode () + , LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False () ) , ( RelayAccessDomain "test.domain" (read "4444") - , LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode () + , LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False () ) ] ) From c2e3eec2f401fc7ee363c77c4972aa9e9ebb90fd Mon Sep 17 00:00:00 2001 From: edgr Date: Sun, 9 Nov 2025 13:46:13 +0800 Subject: [PATCH 02/24] Add ConnectionMode to AcquireOutboundConnection --- .../20251108_103013_edgr_behind_firewall.md | 17 ++++++ .../lib/Test/Cardano/Network/PeerSelection.hs | 55 ++++++++++++++++++- .../Network/PeerSelection/MockEnvironment.hs | 32 ++++++++--- .../20251108_101451_edgr_behind_firewall.md | 22 ++++++++ ouroboros-network/demo/connection-manager.hs | 4 +- .../Network/ConnectionManager/Core.hs | 7 ++- .../Network/ConnectionManager/Types.hs | 29 +++++++++- .../Ouroboros/Network/ConnectionManager.hs | 11 ++-- .../Test/Ouroboros/Network/Server/Sim.hs | 2 +- .../Network/ConnectionManager/Experiments.hs | 8 ++- .../Governor/EstablishedPeers.hs | 24 +++++++- .../Network/PeerSelection/Governor/Types.hs | 5 +- .../Network/PeerSelection/PeerStateActions.hs | 4 +- 13 files changed, 193 insertions(+), 27 deletions(-) create mode 100644 cardano-diffusion/changelog.d/20251108_103013_edgr_behind_firewall.md create mode 100644 ouroboros-network/changelog.d/20251108_101451_edgr_behind_firewall.md diff --git a/cardano-diffusion/changelog.d/20251108_103013_edgr_behind_firewall.md b/cardano-diffusion/changelog.d/20251108_103013_edgr_behind_firewall.md new file mode 100644 index 00000000000..9fd580ad906 --- /dev/null +++ b/cardano-diffusion/changelog.d/20251108_103013_edgr_behind_firewall.md @@ -0,0 +1,17 @@ + + +### Breaking + +- Modified `establishPeerConnection` in `Test.Cardano.Network.PeerSelection.MockEnvironment`: + - Now only creates a new connection if no inbound connection is found and `ConnectionMode` allows it. + - Added tracing for newly created connections. + +### Non-Breaking + +- Added a new tracer: `TraceEnvNewConnCreated`. +- Added a property test to verify that the node never connects to peers behind a firewall. diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs index ad68f726f16..383884294e9 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs @@ -154,6 +154,8 @@ tests = prop_governor_target_active_local_below , testProperty "progresses towards active target (from above)" prop_governor_target_active_local_above + , testProperty "never connect to peers behind a firewall" + prop_governor_never_connect_peer_behind_firewall ] , testGroup "big ledger peers" @@ -799,6 +801,7 @@ envEventCredits (TraceEnvSetLocalRoots peers) = LocalRootPeers.size peers envEventCredits (TraceEnvSetPublicRoots peers) = PublicRootPeers.size Cardano.ExtraPeers.size peers envEventCredits TraceEnvRequestPublicRootPeers = 0 envEventCredits TraceEnvRequestBigLedgerPeers = 0 +envEventCredits (TraceEnvNewConnCreated _) = 0 envEventCredits TraceEnvPublicRootTTL = 60 envEventCredits TraceEnvBigLedgerPeersTTL = 60 @@ -3206,6 +3209,56 @@ prop_governor_target_established_above (MaxTime maxTime) env = <*> govInProgressIneligibleSig <*> demotionOpportunitiesIgnoredTooLong) +-- | Avoid connecting to root peers marked as behind a firewall and without inbound connection. +prop_governor_never_connect_peer_behind_firewall :: MaxTime -> GovernorMockEnvironment -> Property +prop_governor_never_connect_peer_behind_firewall (MaxTime maxTime) env = + let events = Signal.eventsFromListUpToTime maxTime + . selectPeerSelectionTraceEvents + @Cardano.ExtraState + @PeerTrustable + @(Cardano.ExtraPeers PeerAddr) + @(Cardano.ExtraPeerSelectionSetsWithSizes PeerAddr) + @Cardano.ExtraTrace + . runGovernorInMockEnvironment + $ env + + govLocalRootPeersSig :: Signal (LocalRootPeers PeerTrustable PeerAddr) + govLocalRootPeersSig = + selectGovState Governor.localRootPeers + (Cardano.ExtraState.empty (consensusMode env) (NumberOfBigLedgerPeers 0)) Cardano.ExtraPeers.empty + events + + govUnreachablePeersSig :: Signal (Set PeerAddr) + govUnreachablePeersSig = + (\local -> + let + isUnreachablePeer (LocalRootConfig {localRootBehindFirewall}) = localRootBehindFirewall + + unreachablePeers = + Map.keysSet + $ Map.filter isUnreachablePeer + $ LocalRootPeers.toMap local + in + unreachablePeers + ) <$> govLocalRootPeersSig + + newConnectionSig :: Signal (Maybe PeerAddr) + newConnectionSig = + Signal.fromEvents + . Signal.selectEvents + (\case TraceEnvNewConnCreated addr -> Just $! addr + _other -> Nothing) + . selectEnvEvents + $ events + + in counterexample + "\nSignal key: (local root peers, unreachable local root peers, new connection)" $ + + signalProperty 100 show + (\(_,unreachablePeers,newConnection) -> maybe True (not . flip Set.member unreachablePeers) newConnection) + ((,,) <$> govLocalRootPeersSig + <*> govUnreachablePeersSig + <*> newConnectionSig) -- | Like 'prop_governor_target_established_above' but for big ledger peers. -- @@ -3560,7 +3613,7 @@ prop_governor_target_established_local (MaxTime maxTime) env = promotionOpportunitiesIgnoredTooLong :: Signal (Set PeerAddr) promotionOpportunitiesIgnoredTooLong = Signal.keyedTimeout - 1 -- seconds + 2 -- seconds -- cabal run cardano-diffusion:cardano-diffusion-sim-tests -- --quickcheck-replay="(SMGen 13722084053961804625 14989040016076027617,42)" -p '/local root peers/&&/progresses towards established target/' id promotionOpportunities diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs index dfe7d0e344b..0035e285063 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs @@ -48,7 +48,7 @@ import Data.IP (toIPv4w) import Control.Concurrent.Class.MonadSTM import Control.Concurrent.Class.MonadSTM.Strict qualified as StrictTVar -import Control.Exception (throw) +import Control.Exception (throw, ErrorCall (..)) import Control.Monad (forM, when) import Control.Monad.Class.MonadAsync import Control.Monad.Class.MonadFork @@ -62,6 +62,7 @@ import Control.Monad.IOSim import Control.Tracer (Tracer (..), contramap, traceWith) import Ouroboros.Network.BlockFetch (FetchMode (..), PraosFetchMode (..)) +import Ouroboros.Network.ConnectionManager.Types (ConnectionMode (..)) import Ouroboros.Network.DiffusionMode import Ouroboros.Network.ExitPolicy import Ouroboros.Network.PeerSelection hiding (requestPublicRootPeers) @@ -330,6 +331,7 @@ data TraceMockEnv = TraceEnvAddPeers !PeerGraph | TraceEnvSetTargets !PeerSelectionTargets | TraceEnvPeersDemote !AsyncDemotion !PeerAddr | TraceEnvEstablishConn !PeerAddr + | TraceEnvNewConnCreated !PeerAddr | TraceEnvActivatePeer !PeerAddr | TraceEnvDeactivatePeer !PeerAddr | TraceEnvCloseConn !PeerAddr @@ -549,20 +551,34 @@ mockPeerSelectionActions' tracer threadDelay (interpretPeerShareTime time) traceWith tracer (TraceEnvPeerShareResult addr peeraddrs) return (PeerSharingResult peeraddrs) - - establishPeerConnection :: IsBigLedgerPeer -> DiffusionMode -> PeerAddr -> m (PeerConn m) - establishPeerConnection _ _ peeraddr = do + establishPeerConnection :: IsBigLedgerPeer -> DiffusionMode -> PeerAddr -> ConnectionMode -> m (PeerConn m) + establishPeerConnection _ _ peeraddr connMode = do --TODO: add support for variable delays and synchronous failure traceWith tracer (TraceEnvEstablishConn peeraddr) threadDelay 1 let Just (_, peerSharingScript, connectScript) = Map.lookup peeraddr scripts - conn@(PeerConn _ _ v) <- atomically $ do - conn <- newTVar PeerWarm + (conn@(PeerConn _ _ v), newConnCreated) <- atomically $ do conns <- readTVar connsVar - let !conns' = Map.insert peeraddr conn conns + (conn, conns', newConnCreated) <- maybe + ( case connMode of + CreateNewIfNoInbound -> do + conn <- newTVar PeerWarm + pure (conn, conns, True) + RequireInbound -> do + throwSTM (ErrorCall "No inbound connection found.") + ) + (\conn -> do + pure (conn, Map.insert peeraddr conn conns, False) + ) + (Map.lookup peeraddr conns) + writeTVar connsVar conns' remotePeerSharing <- stepScriptSTM peerSharingScript - return (PeerConn peeraddr (peerSharingFlag <> remotePeerSharing) conn) + return (PeerConn peeraddr (peerSharingFlag <> remotePeerSharing) conn, newConnCreated) + + when newConnCreated $ + traceWith tracer (TraceEnvNewConnCreated peeraddr) + _ <- async $ -- monitoring loop which does asynchronous demotions. It will terminate -- as soon as either of the events: diff --git a/ouroboros-network/changelog.d/20251108_101451_edgr_behind_firewall.md b/ouroboros-network/changelog.d/20251108_101451_edgr_behind_firewall.md new file mode 100644 index 00000000000..91f38e6c4f4 --- /dev/null +++ b/ouroboros-network/changelog.d/20251108_101451_edgr_behind_firewall.md @@ -0,0 +1,22 @@ + + +### Breaking + +- Changed the type of `localRoots` to `LocalRoots`. +- Modified `AcquireOutboundConnection` to include an additional parameter: `ConnectionMode`. +- `acquireOutboundConnectionImpl` only creates a new connection if the `ConnectionMode` function permits it. +- `jobPromoteColdPeer` only creates a new connection if no inbound connection is found and the peer is not behind a firewall. + +### Non-Breaking + +- Added `LocalRoots` type in `Ouroboros.Network.PeerSelection.State.LocalRootPeers` with the following fields: + - `rootConfig` of type `RootConfig` + - `behindFirewall` of type `Bool` +- Added `localRootBehindFirewall` field to `LocalRootConfig`. +- Added a new sum type: `ConnectionMode`. +- Added a new constructor `InboundConnectionNotFound` for `ConnectionManagerError`. diff --git a/ouroboros-network/demo/connection-manager.hs b/ouroboros-network/demo/connection-manager.hs index bdc7740086a..ea630d97aa0 100644 --- a/ouroboros-network/demo/connection-manager.hs +++ b/ouroboros-network/demo/connection-manager.hs @@ -569,9 +569,9 @@ bidirectionalExperiment (HandlerError UnversionedProtocol)) connect n cm | n <= 1 = - acquireOutboundConnection cm InitiatorAndResponderDiffusionMode remoteAddr + acquireOutboundConnection cm InitiatorAndResponderDiffusionMode remoteAddr CreateNewIfNoInbound connect n cm = - acquireOutboundConnection cm InitiatorAndResponderDiffusionMode remoteAddr + acquireOutboundConnection cm InitiatorAndResponderDiffusionMode remoteAddr CreateNewIfNoInbound `catch` \(_ :: IOException) -> threadDelay 1 >> connect (pred n) cm `catch` \(_ :: Mux.Error) -> threadDelay 1 diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs index 3f1fcf9ff3e..fe4d6cd9fe8 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs @@ -1338,8 +1338,9 @@ with args@Arguments { -> ConnectionHandlerFn handlerTrace socket peerAddr handle handleError version versionData m -> DiffusionMode -> peerAddr + -> ConnectionMode -> m (Connected peerAddr handle handleError) - acquireOutboundConnectionImpl stateVar stdGenVar handler diffusionMode peerAddr = do + acquireOutboundConnectionImpl stateVar stdGenVar handler diffusionMode peerAddr connectionMode = do let provenance = Outbound traceWith tracer (TrIncludeConnection provenance peerAddr) (trace, mutableConnState@MutableConnState { connVar, connStateId } @@ -1486,6 +1487,10 @@ with args@Arguments { -- connection manager does not have a connection with @peerAddr@. Right Nowhere -> do + -- Only proceed if creating a new connection is allowed + when (inboundRequired connectionMode) $ + throwIO (withCallStack $ InboundConnectionNotFound peerAddr) + (reader, writer) <- newEmptyPromiseIO (connId, connThread) <- diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs index fe1891c5143..8eef70c23ed 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs @@ -114,6 +114,8 @@ module Ouroboros.Network.ConnectionManager.Types , resultInState , DemotedToColdRemoteTr (..) , AcquireOutboundConnection + , ConnectionMode (..) + , inboundRequired , IncludeInboundConnection -- *** Outbound side , acquireOutboundConnection @@ -497,9 +499,23 @@ data Connected peerAddr handle handleError = -- | Disconnected !(ConnectionId peerAddr) !(DisconnectionException handleError) +-- | Describes the behavior for handling connections when no inbound connection +-- is found. +-- - 'CreateNewIfNoInbound': If no inbound connection exists, create a new +-- conection. +-- - 'RequireInbound': Strictly require an inbound connection; fail if none +-- exists. +data ConnectionMode + = CreateNewIfNoInbound + | RequireInbound + +inboundRequired :: ConnectionMode -> Bool +inboundRequired RequireInbound = True +inboundRequired _other = False type AcquireOutboundConnection peerAddr handle handleError m - = DiffusionMode -> peerAddr -> m (Connected peerAddr handle handleError) + = DiffusionMode -> peerAddr -> ConnectionMode -> m (Connected peerAddr handle handleError) + type IncludeInboundConnection socket peerAddr handle handleError m = Word32 -- ^ inbound connections hard limit. @@ -723,6 +739,11 @@ data ConnectionManagerError peerAddr -- | ForbiddenConnection !(ConnectionId peerAddr) !CallStack + -- | No matching inbound connection found and creating new connection is + -- not allowed. + -- + | InboundConnectionNotFound !peerAddr !CallStack + -- | Connections that would be forbidden by the kernel (@TCP@ semantics). -- | ImpossibleConnection !(ConnectionId peerAddr) !CallStack @@ -774,6 +795,12 @@ instance ( Show peerAddr , "\n" , prettyCallStack cs ] + displayException (InboundConnectionNotFound peerAddr cs) = + concat [ "No matching inbound connection found and creating new connection is not allowed with peer " + , show peerAddr + , "\n" + , prettyCallStack cs + ] displayException (ConnectionTerminating connId cs) = concat [ "Connection terminating " , show connId diff --git a/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/ConnectionManager.hs b/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/ConnectionManager.hs index 9a25eab1f04..2b75ef65c53 100644 --- a/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/ConnectionManager.hs +++ b/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/ConnectionManager.hs @@ -817,7 +817,7 @@ prop_valid_transitions (Fixed rnd) (SkewedBool bindToLocalAddress) scheduleMap = -- handshake negotiation. timeout (1 + 5 + testTimeWaitTimeout) (acquireOutboundConnection - connectionManager InitiatorAndResponderDiffusionMode addr)) + connectionManager InitiatorAndResponderDiffusionMode addr CreateNewIfNoInbound)) `catches` [ Handler $ \(e :: IOException) -> return (Left (toException e)) , Handler $ \(e :: SomeConnectionManagerError) -> @@ -983,10 +983,11 @@ prop_valid_transitions (Fixed rnd) (SkewedBool bindToLocalAddress) scheduleMap = Just (SomeConnectionManagerError e@UnknownPeer {}) -> throwIO e -- If 'ForbiddenConnection' is thrown we let the test continue. - Just (SomeConnectionManagerError ForbiddenConnection {}) -> pure () - Just (SomeConnectionManagerError ConnectionExists {}) -> pure () - Just (SomeConnectionManagerError ConnectionTerminating {}) -> pure () - Just (SomeConnectionManagerError ConnectionTerminated {}) -> pure () + Just (SomeConnectionManagerError ForbiddenConnection {}) -> pure () + Just (SomeConnectionManagerError ConnectionExists {}) -> pure () + Just (SomeConnectionManagerError ConnectionTerminating {}) -> pure () + Just (SomeConnectionManagerError ConnectionTerminated {}) -> pure () + Just (SomeConnectionManagerError InboundConnectionNotFound {}) -> pure () -- | This includes the @Overwritten@ transition. diff --git a/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/Server/Sim.hs b/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/Server/Sim.hs index a6bd00592ec..292430f9d2a 100644 --- a/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/Server/Sim.hs +++ b/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/Server/Sim.hs @@ -879,7 +879,7 @@ multinodeExperiment inboundTrTracer trTracer inboundTracer debugTracer cmTracer case fromException e of Just SomeAsyncException {} -> Nothing _ -> Just e) - $ acquireOutboundConnection cm InitiatorAndResponderDiffusionMode remoteAddr + $ acquireOutboundConnection cm InitiatorAndResponderDiffusionMode remoteAddr CreateNewIfNoInbound case connHandle of Left _ -> go connMap diff --git a/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Experiments.hs b/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Experiments.hs index 05de7bd770d..46ebce5e6c9 100644 --- a/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Experiments.hs +++ b/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Experiments.hs @@ -770,7 +770,7 @@ unidirectionalExperiment stdGen timeouts snocket makeBearer confSock socket clie replicateM (numberOfRounds clientAndServerData) (bracket - (acquireOutboundConnection connectionManager InitiatorOnlyDiffusionMode serverAddr) + (acquireOutboundConnection connectionManager InitiatorOnlyDiffusionMode serverAddr CreateNewIfNoInbound) (\case Connected connId _ _ -> releaseOutboundConnection connectionManager connId Disconnected {} -> error "unidirectionalExperiment: impossible happened") @@ -876,7 +876,8 @@ bidirectionalExperiment (acquireOutboundConnection connectionManager0 InitiatorAndResponderDiffusionMode - localAddr1)) + localAddr1 + CreateNewIfNoInbound)) (\case Connected connId _ _ -> releaseOutboundConnection @@ -902,7 +903,8 @@ bidirectionalExperiment (acquireOutboundConnection connectionManager1 InitiatorAndResponderDiffusionMode - localAddr0)) + localAddr0 + CreateNewIfNoInbound)) (\case Connected connId _ _ -> releaseOutboundConnection diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs index ea15d647baf..c3e7e43dbe3 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs @@ -8,6 +8,7 @@ module Ouroboros.Network.PeerSelection.Governor.EstablishedPeers , aboveTarget ) where +import Data.Bool (bool) import Data.Map.Strict (Map) import Data.Map.Strict qualified as Map import Data.Set (Set) @@ -23,6 +24,7 @@ import Control.Monad.Class.MonadTime.SI import Control.Monad.Class.MonadTimer.SI import System.Random (randomR) +import Ouroboros.Network.ConnectionManager.Types (ConnectionMode(..)) import Ouroboros.Network.DiffusionMode import Ouroboros.Network.PeerSelection.Governor.Types import Ouroboros.Network.PeerSelection.LedgerPeers.Type (IsBigLedgerPeer (..)) @@ -31,7 +33,8 @@ import Ouroboros.Network.PeerSelection.PeerSharing (PeerSharing (..)) import Ouroboros.Network.PeerSelection.PublicRootPeers qualified as PublicRootPeers import Ouroboros.Network.PeerSelection.State.EstablishedPeers qualified as EstablishedPeers import Ouroboros.Network.PeerSelection.State.KnownPeers qualified as KnownPeers -import Ouroboros.Network.PeerSelection.State.LocalRootPeers (WarmValency (..)) +import Ouroboros.Network.PeerSelection.State.LocalRootPeers (WarmValency (..), + LocalRootConfig (..)) import Ouroboros.Network.PeerSelection.State.LocalRootPeers qualified as LocalRootPeers import Ouroboros.Network.PeerSelection.Types (PeerStatus (..), PublicExtraPeersAPI (..)) @@ -452,7 +455,7 @@ maxColdPeerRetryBackoff = 5 jobPromoteColdPeer :: forall extraState extraDebugState extraFlags extraPeers extraAPI extraCounters extraTrace peeraddr peerconn m. - ( Monad m + ( MonadSTM m , Ord peeraddr ) => PeerSelectionActions @@ -471,6 +474,7 @@ jobPromoteColdPeer -> Job () m (Completion m extraState extraDebugState extraFlags extraPeers extraTrace peeraddr peerconn) jobPromoteColdPeer PeerSelectionActions { + readLocalRootPeers, peerStateActions = PeerStateActions {establishPeerConnection}, peerConnToPeerSharing, extraPeersAPI = PublicExtraPeersAPI { @@ -541,7 +545,21 @@ jobPromoteColdPeer PeerSelectionActions { job = do --TODO: decide if we should do timeouts here or if we should make that -- the responsibility of establishPeerConnection - peerconn <- establishPeerConnection isBigLedgerPeer diffusionMode peeraddr + let + isNotBehindFirewall m = + maybe + True + (\LocalRootConfig {localRootBehindFirewall} -> not localRootBehindFirewall) + (Map.lookup peeraddr m) + + connectionMode <- atomically $ + bool RequireInbound CreateNewIfNoInbound + -- ^ We require inbound if peer is behind a firewall + . foldr (\(_, _, m) b -> b && isNotBehindFirewall m) True + -- ^ True if peer is not behind a firewall + <$> readLocalRootPeers + + peerconn <- establishPeerConnection isBigLedgerPeer diffusionMode peeraddr connectionMode let !peerSharing = peerConnToPeerSharing peerconn return $ Completion $ \st@PeerSelectionState { diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/Types.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/Types.hs index be3d925f5bb..006b1cd050d 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/Types.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/Types.hs @@ -87,6 +87,7 @@ import Control.Concurrent.JobPool (Job) import Control.Exception (Exception (..), SomeException, assert) import Control.Monad.Class.MonadTime.SI +import Ouroboros.Network.ConnectionManager.Types (ConnectionMode) import Ouroboros.Network.DiffusionMode import Ouroboros.Network.ExitPolicy import Ouroboros.Network.PeerSelection.LedgerPeers.Type @@ -393,7 +394,9 @@ data PeerStateActions peeraddr peerconn m = PeerStateActions { -- establishPeerConnection :: IsBigLedgerPeer -> DiffusionMode - -> peeraddr -> m peerconn, + -> peeraddr + -> ConnectionMode + -> m peerconn, -- | Activate a connection: warm to hot promotion. -- diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs index fce477e5902..def62551bb4 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs @@ -764,8 +764,9 @@ withPeerStateActions PeerStateActionsArguments { -> IsBigLedgerPeer -> DiffusionMode -> peerAddr + -> ConnectionMode -> m (PeerConnectionHandle muxMode responderCtx peerAddr versionData ByteString m a b) - establishPeerConnection jobPool isBigLedgerPeer diffusionMode remotePeerAddr = + establishPeerConnection jobPool isBigLedgerPeer diffusionMode remotePeerAddr connectionMode = -- Protect consistency of the peer state with 'bracketOnError' if -- opening a connection fails. bracketOnError @@ -776,6 +777,7 @@ withPeerStateActions PeerStateActionsArguments { spsConnectionManager diffusionMode remotePeerAddr + connectionMode case res of Left e -> do when (isNothing $ fromException @SomeAsyncException e) $ From a12338aed0bc861c166640a3f5e48f35e32f3f29 Mon Sep 17 00:00:00 2001 From: edgr Date: Mon, 17 Nov 2025 17:15:57 +0800 Subject: [PATCH 03/24] CM and jobPromoteColdPeer fixes --- .../Network/ConnectionManager/Core.hs | 43 +++++++++------- .../Network/ConnectionManager/Types.hs | 7 ++- .../Network/ConnectionManager/Utils.hs | 42 ++++++++-------- .../Governor/EstablishedPeers.hs | 50 +++++++++++-------- .../Ouroboros/Network/OrphanInstances.hs | 6 +++ 5 files changed, 87 insertions(+), 61 deletions(-) diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs index fe4d6cd9fe8..e60634aaa2d 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs @@ -1464,20 +1464,30 @@ with args@Arguments { :: MutableConnState peerAddr handle handleError version m) <- State.newMutableConnState peerAddr connStateIdSupply connState' - -- TODO: label `connVar` using 'ConnectionId' - labelTVar connVar ("conn-state-" ++ show peerAddr) - - writeTMVar stateVar - (State.insertUnknownLocalAddr peerAddr mutableConnState state) - return ( Just (Left (TransitionTrace - connStateId - Transition { - fromState = Unknown, - toState = Known connState' - })) - , mutableConnState - , Right Nowhere - ) + + -- Only proceed if creating a new connection is allowed + if inboundRequired connectionMode + then do + return ( Just (Right (TrInboundConnectionNotFound connectionMode peerAddr)) + , mutableConnState + , Left (withCallStack + (InboundConnectionNotFound connectionMode peerAddr)) + ) + else do + -- TODO: label `connVar` using 'ConnectionId' + labelTVar connVar ("conn-state-" ++ show peerAddr) + + writeTMVar stateVar + (State.insertUnknownLocalAddr peerAddr mutableConnState state) + return ( Just (Left (TransitionTrace + connStateId + Transition { + fromState = Unknown, + toState = Known connState' + })) + , mutableConnState + , Right Nowhere + ) traverse_ (either (traceWith trTracer) (traceWith tracer)) trace traceCounters stateVar @@ -1487,10 +1497,6 @@ with args@Arguments { -- connection manager does not have a connection with @peerAddr@. Right Nowhere -> do - -- Only proceed if creating a new connection is allowed - when (inboundRequired connectionMode) $ - throwIO (withCallStack $ InboundConnectionNotFound peerAddr) - (reader, writer) <- newEmptyPromiseIO (connId, connThread) <- @@ -2473,6 +2479,7 @@ withCallStack k = k callStack -- data Trace peerAddr handlerTrace = TrIncludeConnection Provenance peerAddr + | TrInboundConnectionNotFound ConnectionMode peerAddr | TrReleaseConnection Provenance (ConnectionId peerAddr) | TrConnect (Maybe peerAddr) -- ^ local address peerAddr -- ^ remote address diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs index 8eef70c23ed..47cfa59c559 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs @@ -508,6 +508,7 @@ data Connected peerAddr handle handleError = data ConnectionMode = CreateNewIfNoInbound | RequireInbound + deriving Show inboundRequired :: ConnectionMode -> Bool inboundRequired RequireInbound = True @@ -742,7 +743,7 @@ data ConnectionManagerError peerAddr -- | No matching inbound connection found and creating new connection is -- not allowed. -- - | InboundConnectionNotFound !peerAddr !CallStack + | InboundConnectionNotFound !ConnectionMode !peerAddr !CallStack -- | Connections that would be forbidden by the kernel (@TCP@ semantics). -- @@ -795,8 +796,10 @@ instance ( Show peerAddr , "\n" , prettyCallStack cs ] - displayException (InboundConnectionNotFound peerAddr cs) = + displayException (InboundConnectionNotFound connMode peerAddr cs) = concat [ "No matching inbound connection found and creating new connection is not allowed with peer " + , show connMode + , "\n" , show peerAddr , "\n" , prettyCallStack cs diff --git a/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs b/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs index 573ce87ba89..6ed42b204d1 100644 --- a/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs +++ b/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs @@ -300,43 +300,45 @@ connectionManagerTraceMap ntnAddr (ConnectionHandlerTrace ntnVersion ntnVersionData) -> String -connectionManagerTraceMap (TrIncludeConnection p _) = +connectionManagerTraceMap (TrInboundConnectionNotFound cm _) = + "TrInboundConnectionNotFound " ++ show cm +connectionManagerTraceMap (TrIncludeConnection p _) = "TrIncludeConnection " ++ show p -connectionManagerTraceMap (TrReleaseConnection p _) = +connectionManagerTraceMap (TrReleaseConnection p _) = "TrUnregisterConnection " ++ show p -connectionManagerTraceMap TrConnect {} = +connectionManagerTraceMap TrConnect {} = "TrConnect" -connectionManagerTraceMap (TrConnectError _ _ _) = +connectionManagerTraceMap (TrConnectError _ _ _) = "TrConnectError" -connectionManagerTraceMap (TrTerminatingConnection p _) = +connectionManagerTraceMap (TrTerminatingConnection p _) = "TrTerminatingConnection " ++ show p -connectionManagerTraceMap (TrTerminatedConnection p _) = +connectionManagerTraceMap (TrTerminatedConnection p _) = "TrTerminatedConnection " ++ show p -connectionManagerTraceMap (TrConnectionHandler _ _) = +connectionManagerTraceMap (TrConnectionHandler _ _) = "TrConnectionHandler" -connectionManagerTraceMap TrShutdown = +connectionManagerTraceMap TrShutdown = "TrShutdown" -connectionManagerTraceMap (TrConnectionExists p _ as) = +connectionManagerTraceMap (TrConnectionExists p _ as) = "TrConnectionExists " ++ show p ++ " " ++ show as -connectionManagerTraceMap (TrForbiddenConnection _) = +connectionManagerTraceMap (TrForbiddenConnection _) = "TrForbiddenConnection" -connectionManagerTraceMap (TrConnectionFailure _) = +connectionManagerTraceMap (TrConnectionFailure _) = "TrConnectionFailure" -connectionManagerTraceMap (TrConnectionNotFound p _) = +connectionManagerTraceMap (TrConnectionNotFound p _) = "TrConnectionNotFound " ++ show p -connectionManagerTraceMap (TrForbiddenOperation _ as) = +connectionManagerTraceMap (TrForbiddenOperation _ as) = "TrForbiddenOperation" ++ show as -connectionManagerTraceMap (TrPruneConnections _ _ _) = +connectionManagerTraceMap (TrPruneConnections _ _ _) = "TrPruneConnections" -connectionManagerTraceMap (TrConnectionCleanup _) = +connectionManagerTraceMap (TrConnectionCleanup _) = "TrConnectionCleanup" -connectionManagerTraceMap (TrConnectionTimeWait _) = +connectionManagerTraceMap (TrConnectionTimeWait _) = "TrConnectionTimeWait" -connectionManagerTraceMap (TrConnectionTimeWaitDone _) = +connectionManagerTraceMap (TrConnectionTimeWaitDone _) = "TrConnectionTimeWaitDone" -connectionManagerTraceMap (TrConnectionManagerCounters _) = +connectionManagerTraceMap (TrConnectionManagerCounters _) = "TrConnectionManagerCounters" -connectionManagerTraceMap (TrState _) = +connectionManagerTraceMap (TrState _) = "TrState" -connectionManagerTraceMap (TrUnexpectedlyFalseAssertion _) = +connectionManagerTraceMap (TrUnexpectedlyFalseAssertion _) = "TrUnexpectedlyFalseAssertion" diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs index c3e7e43dbe3..eb4ec19a8c1 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs @@ -186,7 +186,9 @@ belowTargetLocal actions@PeerSelectionActions { inProgressPromoteCold = inProgressPromoteCold <> selectedToPromote }, - decisionJobs = [ jobPromoteColdPeer actions policy peer IsNotBigLedgerPeer diffusionMode + decisionJobs = [ jobPromoteColdPeer + actions policy peer IsNotBigLedgerPeer diffusionMode + (connectionMode peer localRootPeers) | peer <- Set.toList selectedToPromote , let diffusionMode = LocalRootPeers.diffusionMode $ LocalRootPeers.toMap localRootPeers Map.! peer @@ -263,6 +265,7 @@ belowTargetOther actions@PeerSelectionActions { policyPickColdPeersToPromote } st@PeerSelectionState { + localRootPeers, knownPeers, inProgressPromoteCold, targets = PeerSelectionTargets { @@ -285,7 +288,10 @@ belowTargetOther actions@PeerSelectionActions { inProgressPromoteCold = inProgressPromoteCold <> selectedToPromote }, - decisionJobs = [ jobPromoteColdPeer actions policy peer IsNotBigLedgerPeer InitiatorAndResponderDiffusionMode + decisionJobs = [ jobPromoteColdPeer + actions policy peer IsNotBigLedgerPeer + InitiatorAndResponderDiffusionMode + (connectionMode peer localRootPeers) | peer <- Set.toList selectedToPromote ] } @@ -371,6 +377,7 @@ belowTargetBigLedgerPeers enableAction policyPickColdPeersToPromote } st@PeerSelectionState { + localRootPeers, knownPeers, establishedPeers, inProgressPromoteCold, @@ -416,7 +423,9 @@ belowTargetBigLedgerPeers enableAction inProgressPromoteCold = inProgressPromoteCold <> selectedToPromote }, - decisionJobs = [ jobPromoteColdPeer actions policy peer IsBigLedgerPeer InitiatorAndResponderDiffusionMode + decisionJobs = [ jobPromoteColdPeer actions policy peer IsBigLedgerPeer + InitiatorAndResponderDiffusionMode + (connectionMode peer localRootPeers) | peer <- Set.toList selectedToPromote ] } @@ -455,7 +464,7 @@ maxColdPeerRetryBackoff = 5 jobPromoteColdPeer :: forall extraState extraDebugState extraFlags extraPeers extraAPI extraCounters extraTrace peeraddr peerconn m. - ( MonadSTM m + ( Monad m , Ord peeraddr ) => PeerSelectionActions @@ -471,10 +480,10 @@ jobPromoteColdPeer -> peeraddr -> IsBigLedgerPeer -> DiffusionMode + -> ConnectionMode -> Job () m (Completion m extraState extraDebugState extraFlags extraPeers extraTrace peeraddr peerconn) jobPromoteColdPeer PeerSelectionActions { - readLocalRootPeers, peerStateActions = PeerStateActions {establishPeerConnection}, peerConnToPeerSharing, extraPeersAPI = PublicExtraPeersAPI { @@ -483,7 +492,7 @@ jobPromoteColdPeer PeerSelectionActions { extraStateToExtraCounters } PeerSelectionPolicy { policyPeerShareActivationDelay } - peeraddr isBigLedgerPeer diffusionMode = + peeraddr isBigLedgerPeer diffusionMode connMode = Job job handler () "promoteColdPeer" where handler :: SomeException @@ -545,21 +554,7 @@ jobPromoteColdPeer PeerSelectionActions { job = do --TODO: decide if we should do timeouts here or if we should make that -- the responsibility of establishPeerConnection - let - isNotBehindFirewall m = - maybe - True - (\LocalRootConfig {localRootBehindFirewall} -> not localRootBehindFirewall) - (Map.lookup peeraddr m) - - connectionMode <- atomically $ - bool RequireInbound CreateNewIfNoInbound - -- ^ We require inbound if peer is behind a firewall - . foldr (\(_, _, m) b -> b && isNotBehindFirewall m) True - -- ^ True if peer is not behind a firewall - <$> readLocalRootPeers - - peerconn <- establishPeerConnection isBigLedgerPeer diffusionMode peeraddr connectionMode + peerconn <- establishPeerConnection isBigLedgerPeer diffusionMode peeraddr connMode let !peerSharing = peerConnToPeerSharing peerconn return $ Completion $ \st@PeerSelectionState { @@ -882,6 +877,19 @@ aboveTargetBigLedgerPeers actions@PeerSelectionActions { | otherwise = GuardedSkip Nothing +connectionMode + :: forall peeraddr extraFlags. + ( Ord peeraddr + ) + => peeraddr + -> LocalRootPeers.LocalRootPeers extraFlags peeraddr + -> ConnectionMode +connectionMode peer localRootPeers = + maybe + CreateNewIfNoInbound + (\LocalRootConfig {localRootBehindFirewall} -> + bool CreateNewIfNoInbound RequireInbound localRootBehindFirewall) + (Map.lookup peer $ LocalRootPeers.toMap localRootPeers) jobDemoteEstablishedPeer :: forall extraState extraDebugState extraFlags extraPeers extraAPI diff --git a/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs b/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs index 5371014d4e3..be03394098a 100644 --- a/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs +++ b/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs @@ -1282,6 +1282,12 @@ instance (Show addr, Show versionNumber, Show agreedOptions, ToJSON addr, ToJSON versionNumber, ToJSON agreedOptions) => ToJSON (ConnMgr.Trace addr (ConnectionHandlerTrace versionNumber agreedOptions)) where toJSON = \case + TrInboundConnectionNotFound connMode peerAddr -> + object + [ "kind" .= String "InboundConnectionNotFound" + , "remoteAddress" .= peerAddr + , "connectionMode" .= String (pack . show $ connMode) + ] TrIncludeConnection prov peerAddr -> object [ "kind" .= String "IncludeConnection" From 405b00536b9ddcc2b2f968be0d868657dc31dd5d Mon Sep 17 00:00:00 2001 From: edgr Date: Mon, 17 Nov 2025 18:45:51 +0800 Subject: [PATCH 04/24] Add diffusion property test --- .../20251108_103013_edgr_behind_firewall.md | 7 -- .../Test/Cardano/Network/Diffusion/Testnet.hs | 94 +++++++++++++++++++ .../lib/Test/Cardano/Network/PeerSelection.hs | 56 +---------- .../Network/PeerSelection/MockEnvironment.hs | 29 ++---- 4 files changed, 102 insertions(+), 84 deletions(-) diff --git a/cardano-diffusion/changelog.d/20251108_103013_edgr_behind_firewall.md b/cardano-diffusion/changelog.d/20251108_103013_edgr_behind_firewall.md index 9fd580ad906..b9d681c3d65 100644 --- a/cardano-diffusion/changelog.d/20251108_103013_edgr_behind_firewall.md +++ b/cardano-diffusion/changelog.d/20251108_103013_edgr_behind_firewall.md @@ -5,13 +5,6 @@ Uncomment the section that is right (remove the HTML comment wrapper). For top level release notes, leave all the headers commented out. --> -### Breaking - -- Modified `establishPeerConnection` in `Test.Cardano.Network.PeerSelection.MockEnvironment`: - - Now only creates a new connection if no inbound connection is found and `ConnectionMode` allows it. - - Added tracing for newly created connections. - ### Non-Breaking -- Added a new tracer: `TraceEnvNewConnCreated`. - Added a property test to verify that the node never connects to peers behind a firewall. diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs index 14251fc2966..f988d6ae3a5 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs @@ -132,6 +132,8 @@ tests = prop_diffusion_target_active_public_iosimpor , nightlyTest $ testProperty "target established local" prop_diffusion_target_established_local_iosimpor + , nightlyTest $ testProperty "never connect to peers behind a firewall" + prop_diffusion_never_connect_peer_behind_firewall_iosimpor , nightlyTest $ testProperty "target active local" prop_diffusion_target_active_local_iosimpor , nightlyTest $ testProperty "target active root" @@ -192,6 +194,8 @@ tests = prop_diffusion_target_active_public_iosim , testProperty "target established local" prop_diffusion_target_established_local_iosim + , testProperty "never connect to peers behind a firewall" + prop_diffusion_never_connect_peer_behind_firewall_iosim , testProperty "unit reconnect" prop_unit_reconnect , testProperty "target active local" @@ -2847,6 +2851,96 @@ prop_diffusion_target_established_local_iosim prop_diffusion_target_established_local_iosim = testWithIOSim prop_diffusion_target_established_local long_trace +-- | Avoid connecting to root peers marked as behind a firewall and without +-- inbound connection. +-- +prop_diffusion_never_connect_peer_behind_firewall + :: SimTrace Void + -> Int + -> Property +prop_diffusion_never_connect_peer_behind_firewall ioSimTrace traceNumber = + let events :: [Events DiffusionTestTrace] + events = Trace.toList + . fmap ( Signal.eventsFromList + . fmap (\(WithName _ (WithTime t b)) -> (t, b)) + ) + . splitWithNameTrace + . fmap (\(WithTime t (WithName name b)) -> + WithName name (WithTime t b)) + . withTimeNameTraceEvents + @DiffusionTestTrace + @NtNAddr + . Trace.take traceNumber + $ ioSimTrace + + in conjoin + $ (\ev -> + let evsList = eventsToList ev + lastTime = fst + . last + $ evsList + in classifySimulatedTime lastTime + $ classifyNumberOfEvents (length evsList) + $ verify_target_established_local ev + ) + <$> events + + where + verify_target_established_local :: Events DiffusionTestTrace + -> Property + verify_target_established_local events = + let govLocalRootPeersSig + :: Signal (LocalRootPeers.LocalRootPeers PeerTrustable NtNAddr) + govLocalRootPeersSig = + selectDiffusionPeerSelectionState Governor.localRootPeers events + + govUnreachablePeersSig :: Signal (Set NtNAddr) + govUnreachablePeersSig = + (\local -> + let + isUnreachablePeer (LocalRootConfig {localRootBehindFirewall}) = + localRootBehindFirewall + unreachablePeers = + Map.keysSet + $ Map.filter isUnreachablePeer + $ LocalRootPeers.toMap local + in + unreachablePeers + ) <$> govLocalRootPeersSig + + govInboundConnectionsSig :: Signal (Set NtNAddr) + govInboundConnectionsSig = + Signal.keyedLinger + 180 -- 3 minutes + (Just . fromMaybe Set.empty) + . Signal.fromEvents + . Signal.selectEvents + (\case + DiffusionConnectionManagerTrace + -- initiated by remote + (CM.TrConnectionNotFound Inbound peer) -> + Just (Set.singleton peer) + _other -> Nothing + ) + $ events + + in counterexample + ("\nSignal key: (local root peers, unreachables, inbounds") $ + signalProperty 100 show + (\(_,unreachables,inbounds) -> unreachables `Set.disjoint` inbounds) + ((,,) <$> govLocalRootPeersSig + <*> govUnreachablePeersSig + <*> govInboundConnectionsSig) + +prop_diffusion_never_connect_peer_behind_firewall_iosimpor + :: AbsBearerInfo -> DiffusionScript -> Property +prop_diffusion_never_connect_peer_behind_firewall_iosimpor + = testWithIOSimPOR prop_diffusion_never_connect_peer_behind_firewall short_trace + +prop_diffusion_never_connect_peer_behind_firewall_iosim + :: AbsBearerInfo -> DiffusionScript -> Property +prop_diffusion_never_connect_peer_behind_firewall_iosim + = testWithIOSim prop_diffusion_never_connect_peer_behind_firewall long_trace -- | A variant of -- 'Test.Ouroboros.Network.PeerSelection.prop_governor_target_active_below' diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs index 383884294e9..4b17b2d86e4 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs @@ -154,8 +154,6 @@ tests = prop_governor_target_active_local_below , testProperty "progresses towards active target (from above)" prop_governor_target_active_local_above - , testProperty "never connect to peers behind a firewall" - prop_governor_never_connect_peer_behind_firewall ] , testGroup "big ledger peers" @@ -801,7 +799,6 @@ envEventCredits (TraceEnvSetLocalRoots peers) = LocalRootPeers.size peers envEventCredits (TraceEnvSetPublicRoots peers) = PublicRootPeers.size Cardano.ExtraPeers.size peers envEventCredits TraceEnvRequestPublicRootPeers = 0 envEventCredits TraceEnvRequestBigLedgerPeers = 0 -envEventCredits (TraceEnvNewConnCreated _) = 0 envEventCredits TraceEnvPublicRootTTL = 60 envEventCredits TraceEnvBigLedgerPeersTTL = 60 @@ -3209,57 +3206,6 @@ prop_governor_target_established_above (MaxTime maxTime) env = <*> govInProgressIneligibleSig <*> demotionOpportunitiesIgnoredTooLong) --- | Avoid connecting to root peers marked as behind a firewall and without inbound connection. -prop_governor_never_connect_peer_behind_firewall :: MaxTime -> GovernorMockEnvironment -> Property -prop_governor_never_connect_peer_behind_firewall (MaxTime maxTime) env = - let events = Signal.eventsFromListUpToTime maxTime - . selectPeerSelectionTraceEvents - @Cardano.ExtraState - @PeerTrustable - @(Cardano.ExtraPeers PeerAddr) - @(Cardano.ExtraPeerSelectionSetsWithSizes PeerAddr) - @Cardano.ExtraTrace - . runGovernorInMockEnvironment - $ env - - govLocalRootPeersSig :: Signal (LocalRootPeers PeerTrustable PeerAddr) - govLocalRootPeersSig = - selectGovState Governor.localRootPeers - (Cardano.ExtraState.empty (consensusMode env) (NumberOfBigLedgerPeers 0)) Cardano.ExtraPeers.empty - events - - govUnreachablePeersSig :: Signal (Set PeerAddr) - govUnreachablePeersSig = - (\local -> - let - isUnreachablePeer (LocalRootConfig {localRootBehindFirewall}) = localRootBehindFirewall - - unreachablePeers = - Map.keysSet - $ Map.filter isUnreachablePeer - $ LocalRootPeers.toMap local - in - unreachablePeers - ) <$> govLocalRootPeersSig - - newConnectionSig :: Signal (Maybe PeerAddr) - newConnectionSig = - Signal.fromEvents - . Signal.selectEvents - (\case TraceEnvNewConnCreated addr -> Just $! addr - _other -> Nothing) - . selectEnvEvents - $ events - - in counterexample - "\nSignal key: (local root peers, unreachable local root peers, new connection)" $ - - signalProperty 100 show - (\(_,unreachablePeers,newConnection) -> maybe True (not . flip Set.member unreachablePeers) newConnection) - ((,,) <$> govLocalRootPeersSig - <*> govUnreachablePeersSig - <*> newConnectionSig) - -- | Like 'prop_governor_target_established_above' but for big ledger peers. -- prop_governor_target_established_big_ledger_peers_above @@ -3613,7 +3559,7 @@ prop_governor_target_established_local (MaxTime maxTime) env = promotionOpportunitiesIgnoredTooLong :: Signal (Set PeerAddr) promotionOpportunitiesIgnoredTooLong = Signal.keyedTimeout - 2 -- seconds -- cabal run cardano-diffusion:cardano-diffusion-sim-tests -- --quickcheck-replay="(SMGen 13722084053961804625 14989040016076027617,42)" -p '/local root peers/&&/progresses towards established target/' + 1 -- seconds id promotionOpportunities diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs index 0035e285063..85ec962e5ca 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs @@ -48,7 +48,7 @@ import Data.IP (toIPv4w) import Control.Concurrent.Class.MonadSTM import Control.Concurrent.Class.MonadSTM.Strict qualified as StrictTVar -import Control.Exception (throw, ErrorCall (..)) +import Control.Exception (throw) import Control.Monad (forM, when) import Control.Monad.Class.MonadAsync import Control.Monad.Class.MonadFork @@ -331,7 +331,6 @@ data TraceMockEnv = TraceEnvAddPeers !PeerGraph | TraceEnvSetTargets !PeerSelectionTargets | TraceEnvPeersDemote !AsyncDemotion !PeerAddr | TraceEnvEstablishConn !PeerAddr - | TraceEnvNewConnCreated !PeerAddr | TraceEnvActivatePeer !PeerAddr | TraceEnvDeactivatePeer !PeerAddr | TraceEnvCloseConn !PeerAddr @@ -551,34 +550,20 @@ mockPeerSelectionActions' tracer threadDelay (interpretPeerShareTime time) traceWith tracer (TraceEnvPeerShareResult addr peeraddrs) return (PeerSharingResult peeraddrs) + establishPeerConnection :: IsBigLedgerPeer -> DiffusionMode -> PeerAddr -> ConnectionMode -> m (PeerConn m) - establishPeerConnection _ _ peeraddr connMode = do + establishPeerConnection _ _ peeraddr _ = do --TODO: add support for variable delays and synchronous failure traceWith tracer (TraceEnvEstablishConn peeraddr) threadDelay 1 let Just (_, peerSharingScript, connectScript) = Map.lookup peeraddr scripts - (conn@(PeerConn _ _ v), newConnCreated) <- atomically $ do + conn@(PeerConn _ _ v) <- atomically $ do + conn <- newTVar PeerWarm conns <- readTVar connsVar - (conn, conns', newConnCreated) <- maybe - ( case connMode of - CreateNewIfNoInbound -> do - conn <- newTVar PeerWarm - pure (conn, conns, True) - RequireInbound -> do - throwSTM (ErrorCall "No inbound connection found.") - ) - (\conn -> do - pure (conn, Map.insert peeraddr conn conns, False) - ) - (Map.lookup peeraddr conns) - + let !conns' = Map.insert peeraddr conn conns writeTVar connsVar conns' remotePeerSharing <- stepScriptSTM peerSharingScript - return (PeerConn peeraddr (peerSharingFlag <> remotePeerSharing) conn, newConnCreated) - - when newConnCreated $ - traceWith tracer (TraceEnvNewConnCreated peeraddr) - + return (PeerConn peeraddr (peerSharingFlag <> remotePeerSharing) conn) _ <- async $ -- monitoring loop which does asynchronous demotions. It will terminate -- as soon as either of the events: From e8fcd54a63d6a14517b3437a459d7b31b70e96f8 Mon Sep 17 00:00:00 2001 From: Edi <55669107+the-headless-ghost@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:26:32 +0800 Subject: [PATCH 05/24] Update cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs Co-authored-by: coot --- .../tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs index f988d6ae3a5..4fc76719a59 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs @@ -2898,11 +2898,9 @@ prop_diffusion_never_connect_peer_behind_firewall ioSimTrace traceNumber = govUnreachablePeersSig = (\local -> let - isUnreachablePeer (LocalRootConfig {localRootBehindFirewall}) = - localRootBehindFirewall unreachablePeers = Map.keysSet - $ Map.filter isUnreachablePeer + $ Map.filter localRootBehindFirewall $ LocalRootPeers.toMap local in unreachablePeers From a496cedff99693f52d7db854b5a62092ad235468 Mon Sep 17 00:00:00 2001 From: Edi <55669107+the-headless-ghost@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:26:58 +0800 Subject: [PATCH 06/24] Update ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs Co-authored-by: coot --- .../lib/Ouroboros/Network/ConnectionManager/Core.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs index e60634aaa2d..dfa677fb275 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs @@ -1469,10 +1469,10 @@ with args@Arguments { if inboundRequired connectionMode then do return ( Just (Right (TrInboundConnectionNotFound connectionMode peerAddr)) - , mutableConnState - , Left (withCallStack - (InboundConnectionNotFound connectionMode peerAddr)) - ) + , mutableConnState + , Left (withCallStack + (InboundConnectionNotFound connectionMode peerAddr)) + ) else do -- TODO: label `connVar` using 'ConnectionId' labelTVar connVar ("conn-state-" ++ show peerAddr) From c3e7c294b753ffcd842d33bc11e6e4e85ba479fb Mon Sep 17 00:00:00 2001 From: Edi <55669107+the-headless-ghost@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:27:10 +0800 Subject: [PATCH 07/24] Update cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs Co-authored-by: coot --- .../tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs index 4fc76719a59..91968a640ea 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs @@ -2927,8 +2927,8 @@ prop_diffusion_never_connect_peer_behind_firewall ioSimTrace traceNumber = signalProperty 100 show (\(_,unreachables,inbounds) -> unreachables `Set.disjoint` inbounds) ((,,) <$> govLocalRootPeersSig - <*> govUnreachablePeersSig - <*> govInboundConnectionsSig) + <*> govUnreachablePeersSig + <*> govInboundConnectionsSig) prop_diffusion_never_connect_peer_behind_firewall_iosimpor :: AbsBearerInfo -> DiffusionScript -> Property From f0ef9bb5ff98ef60d2c4deef0b3601b11acfc668 Mon Sep 17 00:00:00 2001 From: Edi <55669107+the-headless-ghost@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:27:25 +0800 Subject: [PATCH 08/24] Update cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs Co-authored-by: coot --- .../tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs index 91968a640ea..507461afe9e 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs @@ -2906,8 +2906,9 @@ prop_diffusion_never_connect_peer_behind_firewall ioSimTrace traceNumber = unreachablePeers ) <$> govLocalRootPeersSig - govInboundConnectionsSig :: Signal (Set NtNAddr) - govInboundConnectionsSig = + -- all connections which triggered `TrConnectionNotFound Inbound` + govNotFoundInboundConnSig :: Signal (Set NtNAddr) + govNotFoundInboundConnSig = Signal.keyedLinger 180 -- 3 minutes (Just . fromMaybe Set.empty) From b82fd8d961329acb291ee7a5af3db6ec3ab03eb2 Mon Sep 17 00:00:00 2001 From: edgr Date: Fri, 5 Dec 2025 10:40:26 +0800 Subject: [PATCH 09/24] Naming fix --- .../tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs index 507461afe9e..2088dc25ba3 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs @@ -2929,7 +2929,7 @@ prop_diffusion_never_connect_peer_behind_firewall ioSimTrace traceNumber = (\(_,unreachables,inbounds) -> unreachables `Set.disjoint` inbounds) ((,,) <$> govLocalRootPeersSig <*> govUnreachablePeersSig - <*> govInboundConnectionsSig) + <*> govNotFoundInboundConnSig) prop_diffusion_never_connect_peer_behind_firewall_iosimpor :: AbsBearerInfo -> DiffusionScript -> Property From baa81e7a1dc7ffa44a8cb95e68516a8714b0087a Mon Sep 17 00:00:00 2001 From: Edi <55669107+the-headless-ghost@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:41:02 +0800 Subject: [PATCH 10/24] Update ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs Co-authored-by: coot --- .../framework/lib/Ouroboros/Network/ConnectionManager/Types.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs index 47cfa59c559..a0f1e7bf6a2 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs @@ -740,7 +740,7 @@ data ConnectionManagerError peerAddr -- | ForbiddenConnection !(ConnectionId peerAddr) !CallStack - -- | No matching inbound connection found and creating new connection is + -- | No matching inbound connection found while establishing a new connection is -- not allowed. -- | InboundConnectionNotFound !ConnectionMode !peerAddr !CallStack From b843f5c36ce782c4ff446faba307c8d1ab3f7c9c Mon Sep 17 00:00:00 2001 From: edgr Date: Fri, 5 Dec 2025 10:48:05 +0800 Subject: [PATCH 11/24] swap establishPeerConnection arguments --- .../lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs | 4 ++-- .../Network/PeerSelection/Governor/EstablishedPeers.hs | 2 +- .../lib/Ouroboros/Network/PeerSelection/Governor/Types.hs | 2 +- .../lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs index 85ec962e5ca..75ee2e4c556 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs @@ -551,8 +551,8 @@ mockPeerSelectionActions' tracer traceWith tracer (TraceEnvPeerShareResult addr peeraddrs) return (PeerSharingResult peeraddrs) - establishPeerConnection :: IsBigLedgerPeer -> DiffusionMode -> PeerAddr -> ConnectionMode -> m (PeerConn m) - establishPeerConnection _ _ peeraddr _ = do + establishPeerConnection :: IsBigLedgerPeer -> DiffusionMode -> ConnectionMode -> PeerAddr -> m (PeerConn m) + establishPeerConnection _ _ _ peeraddr = do --TODO: add support for variable delays and synchronous failure traceWith tracer (TraceEnvEstablishConn peeraddr) threadDelay 1 diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs index eb4ec19a8c1..36757ec751f 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs @@ -554,7 +554,7 @@ jobPromoteColdPeer PeerSelectionActions { job = do --TODO: decide if we should do timeouts here or if we should make that -- the responsibility of establishPeerConnection - peerconn <- establishPeerConnection isBigLedgerPeer diffusionMode peeraddr connMode + peerconn <- establishPeerConnection isBigLedgerPeer diffusionMode connMode peeraddr let !peerSharing = peerConnToPeerSharing peerconn return $ Completion $ \st@PeerSelectionState { diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/Types.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/Types.hs index 006b1cd050d..516709ea349 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/Types.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/Types.hs @@ -394,8 +394,8 @@ data PeerStateActions peeraddr peerconn m = PeerStateActions { -- establishPeerConnection :: IsBigLedgerPeer -> DiffusionMode - -> peeraddr -> ConnectionMode + -> peeraddr -> m peerconn, -- | Activate a connection: warm to hot promotion. diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs index def62551bb4..4b56dbd7e6b 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs @@ -763,10 +763,10 @@ withPeerStateActions PeerStateActionsArguments { establishPeerConnection :: JobPool () m (Maybe SomeException) -> IsBigLedgerPeer -> DiffusionMode - -> peerAddr -> ConnectionMode + -> peerAddr -> m (PeerConnectionHandle muxMode responderCtx peerAddr versionData ByteString m a b) - establishPeerConnection jobPool isBigLedgerPeer diffusionMode remotePeerAddr connectionMode = + establishPeerConnection jobPool isBigLedgerPeer diffusionMode connectionMode remotePeerAddr = -- Protect consistency of the peer state with 'bracketOnError' if -- opening a connection fails. bracketOnError From 1fedb07e1d19cd1dbce090ece505cf36df2eda67 Mon Sep 17 00:00:00 2001 From: edgr Date: Fri, 5 Dec 2025 11:35:34 +0800 Subject: [PATCH 12/24] Replace ConnectionMode with Provenance --- .../Network/PeerSelection/MockEnvironment.hs | 4 +-- ouroboros-network/demo/connection-manager.hs | 4 +-- .../Network/ConnectionManager/Core.hs | 6 ++--- .../Network/ConnectionManager/Types.hs | 26 +++++-------------- .../Ouroboros/Network/ConnectionManager.hs | 2 +- .../Test/Ouroboros/Network/Server/Sim.hs | 2 +- .../Network/ConnectionManager/Experiments.hs | 6 ++--- .../Governor/EstablishedPeers.hs | 20 +++++++------- .../Network/PeerSelection/Governor/Types.hs | 4 +-- .../Network/PeerSelection/PeerStateActions.hs | 2 +- 10 files changed, 32 insertions(+), 44 deletions(-) diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs index 75ee2e4c556..c4a41990e1c 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs @@ -62,7 +62,7 @@ import Control.Monad.IOSim import Control.Tracer (Tracer (..), contramap, traceWith) import Ouroboros.Network.BlockFetch (FetchMode (..), PraosFetchMode (..)) -import Ouroboros.Network.ConnectionManager.Types (ConnectionMode (..)) +import Ouroboros.Network.ConnectionManager.Types (Provenance (..)) import Ouroboros.Network.DiffusionMode import Ouroboros.Network.ExitPolicy import Ouroboros.Network.PeerSelection hiding (requestPublicRootPeers) @@ -551,7 +551,7 @@ mockPeerSelectionActions' tracer traceWith tracer (TraceEnvPeerShareResult addr peeraddrs) return (PeerSharingResult peeraddrs) - establishPeerConnection :: IsBigLedgerPeer -> DiffusionMode -> ConnectionMode -> PeerAddr -> m (PeerConn m) + establishPeerConnection :: IsBigLedgerPeer -> DiffusionMode -> Provenance -> PeerAddr -> m (PeerConn m) establishPeerConnection _ _ _ peeraddr = do --TODO: add support for variable delays and synchronous failure traceWith tracer (TraceEnvEstablishConn peeraddr) diff --git a/ouroboros-network/demo/connection-manager.hs b/ouroboros-network/demo/connection-manager.hs index ea630d97aa0..6576233dca1 100644 --- a/ouroboros-network/demo/connection-manager.hs +++ b/ouroboros-network/demo/connection-manager.hs @@ -569,9 +569,9 @@ bidirectionalExperiment (HandlerError UnversionedProtocol)) connect n cm | n <= 1 = - acquireOutboundConnection cm InitiatorAndResponderDiffusionMode remoteAddr CreateNewIfNoInbound + acquireOutboundConnection cm InitiatorAndResponderDiffusionMode remoteAddr Outbound connect n cm = - acquireOutboundConnection cm InitiatorAndResponderDiffusionMode remoteAddr CreateNewIfNoInbound + acquireOutboundConnection cm InitiatorAndResponderDiffusionMode remoteAddr Outbound `catch` \(_ :: IOException) -> threadDelay 1 >> connect (pred n) cm `catch` \(_ :: Mux.Error) -> threadDelay 1 diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs index dfa677fb275..dd5bdd6828f 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs @@ -1338,7 +1338,7 @@ with args@Arguments { -> ConnectionHandlerFn handlerTrace socket peerAddr handle handleError version versionData m -> DiffusionMode -> peerAddr - -> ConnectionMode + -> Provenance -> m (Connected peerAddr handle handleError) acquireOutboundConnectionImpl stateVar stdGenVar handler diffusionMode peerAddr connectionMode = do let provenance = Outbound @@ -1466,7 +1466,7 @@ with args@Arguments { <- State.newMutableConnState peerAddr connStateIdSupply connState' -- Only proceed if creating a new connection is allowed - if inboundRequired connectionMode + if connectionMode == Inbound then do return ( Just (Right (TrInboundConnectionNotFound connectionMode peerAddr)) , mutableConnState @@ -2479,7 +2479,7 @@ withCallStack k = k callStack -- data Trace peerAddr handlerTrace = TrIncludeConnection Provenance peerAddr - | TrInboundConnectionNotFound ConnectionMode peerAddr + | TrInboundConnectionNotFound Provenance peerAddr | TrReleaseConnection Provenance (ConnectionId peerAddr) | TrConnect (Maybe peerAddr) -- ^ local address peerAddr -- ^ remote address diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs index a0f1e7bf6a2..4a47d13367b 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs @@ -114,8 +114,6 @@ module Ouroboros.Network.ConnectionManager.Types , resultInState , DemotedToColdRemoteTr (..) , AcquireOutboundConnection - , ConnectionMode (..) - , inboundRequired , IncludeInboundConnection -- *** Outbound side , acquireOutboundConnection @@ -499,23 +497,13 @@ data Connected peerAddr handle handleError = -- | Disconnected !(ConnectionId peerAddr) !(DisconnectionException handleError) --- | Describes the behavior for handling connections when no inbound connection --- is found. --- - 'CreateNewIfNoInbound': If no inbound connection exists, create a new --- conection. --- - 'RequireInbound': Strictly require an inbound connection; fail if none --- exists. -data ConnectionMode - = CreateNewIfNoInbound - | RequireInbound - deriving Show - -inboundRequired :: ConnectionMode -> Bool -inboundRequired RequireInbound = True -inboundRequired _other = False - +-- | Acquire outbound connection +-- 'Inbound' provenance restricts acquiring an outbound connection to those +-- initiated by a remote peer. +-- 'Outbound' provenance allows acquiring an outbound connection regardless of +-- who initiated it. type AcquireOutboundConnection peerAddr handle handleError m - = DiffusionMode -> peerAddr -> ConnectionMode -> m (Connected peerAddr handle handleError) + = DiffusionMode -> peerAddr -> Provenance -> m (Connected peerAddr handle handleError) type IncludeInboundConnection socket peerAddr handle handleError m = Word32 @@ -743,7 +731,7 @@ data ConnectionManagerError peerAddr -- | No matching inbound connection found while establishing a new connection is -- not allowed. -- - | InboundConnectionNotFound !ConnectionMode !peerAddr !CallStack + | InboundConnectionNotFound !Provenance !peerAddr !CallStack -- | Connections that would be forbidden by the kernel (@TCP@ semantics). -- diff --git a/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/ConnectionManager.hs b/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/ConnectionManager.hs index 2b75ef65c53..b332852209f 100644 --- a/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/ConnectionManager.hs +++ b/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/ConnectionManager.hs @@ -817,7 +817,7 @@ prop_valid_transitions (Fixed rnd) (SkewedBool bindToLocalAddress) scheduleMap = -- handshake negotiation. timeout (1 + 5 + testTimeWaitTimeout) (acquireOutboundConnection - connectionManager InitiatorAndResponderDiffusionMode addr CreateNewIfNoInbound)) + connectionManager InitiatorAndResponderDiffusionMode addr Outbound)) `catches` [ Handler $ \(e :: IOException) -> return (Left (toException e)) , Handler $ \(e :: SomeConnectionManagerError) -> diff --git a/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/Server/Sim.hs b/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/Server/Sim.hs index 292430f9d2a..87e66cdd2ff 100644 --- a/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/Server/Sim.hs +++ b/ouroboros-network/framework/sim-tests/Test/Ouroboros/Network/Server/Sim.hs @@ -879,7 +879,7 @@ multinodeExperiment inboundTrTracer trTracer inboundTracer debugTracer cmTracer case fromException e of Just SomeAsyncException {} -> Nothing _ -> Just e) - $ acquireOutboundConnection cm InitiatorAndResponderDiffusionMode remoteAddr CreateNewIfNoInbound + $ acquireOutboundConnection cm InitiatorAndResponderDiffusionMode remoteAddr Outbound case connHandle of Left _ -> go connMap diff --git a/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Experiments.hs b/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Experiments.hs index 46ebce5e6c9..dabe4cc808f 100644 --- a/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Experiments.hs +++ b/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Experiments.hs @@ -770,7 +770,7 @@ unidirectionalExperiment stdGen timeouts snocket makeBearer confSock socket clie replicateM (numberOfRounds clientAndServerData) (bracket - (acquireOutboundConnection connectionManager InitiatorOnlyDiffusionMode serverAddr CreateNewIfNoInbound) + (acquireOutboundConnection connectionManager InitiatorOnlyDiffusionMode serverAddr Outbound) (\case Connected connId _ _ -> releaseOutboundConnection connectionManager connId Disconnected {} -> error "unidirectionalExperiment: impossible happened") @@ -877,7 +877,7 @@ bidirectionalExperiment connectionManager0 InitiatorAndResponderDiffusionMode localAddr1 - CreateNewIfNoInbound)) + Outbound)) (\case Connected connId _ _ -> releaseOutboundConnection @@ -904,7 +904,7 @@ bidirectionalExperiment connectionManager1 InitiatorAndResponderDiffusionMode localAddr0 - CreateNewIfNoInbound)) + Outbound)) (\case Connected connId _ _ -> releaseOutboundConnection diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs index 36757ec751f..3b8e15e03fd 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs @@ -24,7 +24,7 @@ import Control.Monad.Class.MonadTime.SI import Control.Monad.Class.MonadTimer.SI import System.Random (randomR) -import Ouroboros.Network.ConnectionManager.Types (ConnectionMode(..)) +import Ouroboros.Network.ConnectionManager.Types (Provenance (..)) import Ouroboros.Network.DiffusionMode import Ouroboros.Network.PeerSelection.Governor.Types import Ouroboros.Network.PeerSelection.LedgerPeers.Type (IsBigLedgerPeer (..)) @@ -188,7 +188,7 @@ belowTargetLocal actions@PeerSelectionActions { }, decisionJobs = [ jobPromoteColdPeer actions policy peer IsNotBigLedgerPeer diffusionMode - (connectionMode peer localRootPeers) + (localRootConnectionProvenance peer localRootPeers) | peer <- Set.toList selectedToPromote , let diffusionMode = LocalRootPeers.diffusionMode $ LocalRootPeers.toMap localRootPeers Map.! peer @@ -291,7 +291,7 @@ belowTargetOther actions@PeerSelectionActions { decisionJobs = [ jobPromoteColdPeer actions policy peer IsNotBigLedgerPeer InitiatorAndResponderDiffusionMode - (connectionMode peer localRootPeers) + (localRootConnectionProvenance peer localRootPeers) | peer <- Set.toList selectedToPromote ] } @@ -425,7 +425,7 @@ belowTargetBigLedgerPeers enableAction }, decisionJobs = [ jobPromoteColdPeer actions policy peer IsBigLedgerPeer InitiatorAndResponderDiffusionMode - (connectionMode peer localRootPeers) + (localRootConnectionProvenance peer localRootPeers) | peer <- Set.toList selectedToPromote ] } @@ -480,7 +480,7 @@ jobPromoteColdPeer -> peeraddr -> IsBigLedgerPeer -> DiffusionMode - -> ConnectionMode + -> Provenance -> Job () m (Completion m extraState extraDebugState extraFlags extraPeers extraTrace peeraddr peerconn) jobPromoteColdPeer PeerSelectionActions { @@ -877,18 +877,18 @@ aboveTargetBigLedgerPeers actions@PeerSelectionActions { | otherwise = GuardedSkip Nothing -connectionMode +localRootConnectionProvenance :: forall peeraddr extraFlags. ( Ord peeraddr ) => peeraddr -> LocalRootPeers.LocalRootPeers extraFlags peeraddr - -> ConnectionMode -connectionMode peer localRootPeers = + -> Provenance +localRootConnectionProvenance peer localRootPeers = maybe - CreateNewIfNoInbound + Outbound (\LocalRootConfig {localRootBehindFirewall} -> - bool CreateNewIfNoInbound RequireInbound localRootBehindFirewall) + bool Outbound Inbound localRootBehindFirewall) (Map.lookup peer $ LocalRootPeers.toMap localRootPeers) jobDemoteEstablishedPeer diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/Types.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/Types.hs index 516709ea349..5058de5ef70 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/Types.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/Types.hs @@ -87,7 +87,7 @@ import Control.Concurrent.JobPool (Job) import Control.Exception (Exception (..), SomeException, assert) import Control.Monad.Class.MonadTime.SI -import Ouroboros.Network.ConnectionManager.Types (ConnectionMode) +import Ouroboros.Network.ConnectionManager.Types (Provenance) import Ouroboros.Network.DiffusionMode import Ouroboros.Network.ExitPolicy import Ouroboros.Network.PeerSelection.LedgerPeers.Type @@ -394,7 +394,7 @@ data PeerStateActions peeraddr peerconn m = PeerStateActions { -- establishPeerConnection :: IsBigLedgerPeer -> DiffusionMode - -> ConnectionMode + -> Provenance -> peeraddr -> m peerconn, diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs index 4b56dbd7e6b..441959187ec 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs @@ -763,7 +763,7 @@ withPeerStateActions PeerStateActionsArguments { establishPeerConnection :: JobPool () m (Maybe SomeException) -> IsBigLedgerPeer -> DiffusionMode - -> ConnectionMode + -> Provenance -> peerAddr -> m (PeerConnectionHandle muxMode responderCtx peerAddr versionData ByteString m a b) establishPeerConnection jobPool isBigLedgerPeer diffusionMode connectionMode remotePeerAddr = From 00072a18a54df245e30e403686f2eb2008102abc Mon Sep 17 00:00:00 2001 From: edgr Date: Fri, 5 Dec 2025 11:40:43 +0800 Subject: [PATCH 13/24] correct var binding name --- .../Network/PeerSelection/Governor/EstablishedPeers.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs index 3b8e15e03fd..83fa1eeabc7 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs @@ -492,7 +492,7 @@ jobPromoteColdPeer PeerSelectionActions { extraStateToExtraCounters } PeerSelectionPolicy { policyPeerShareActivationDelay } - peeraddr isBigLedgerPeer diffusionMode connMode = + peeraddr isBigLedgerPeer diffusionMode provenance = Job job handler () "promoteColdPeer" where handler :: SomeException @@ -554,7 +554,7 @@ jobPromoteColdPeer PeerSelectionActions { job = do --TODO: decide if we should do timeouts here or if we should make that -- the responsibility of establishPeerConnection - peerconn <- establishPeerConnection isBigLedgerPeer diffusionMode connMode peeraddr + peerconn <- establishPeerConnection isBigLedgerPeer diffusionMode provenance peeraddr let !peerSharing = peerConnToPeerSharing peerconn return $ Completion $ \st@PeerSelectionState { From 09c19d249380efcfd7a4aa22d4296faad32ec1be Mon Sep 17 00:00:00 2001 From: edgr Date: Fri, 5 Dec 2025 11:50:44 +0800 Subject: [PATCH 14/24] Reuse FromJSON instance for RootConfig --- .../orphan-instances/Ouroboros/Network/OrphanInstances.hs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs b/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs index be03394098a..ea96ef69f46 100644 --- a/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs +++ b/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs @@ -100,9 +100,7 @@ kindObject k fields = object $ ("kind" .= String k) : fields instance FromJSON LocalRoots where parseJSON = withObject "LocalRoots" $ \o -> LocalRoots - <$> (RootConfig - <$> o .: "accessPoints" - <*> o .:? "advertise" .!= DoNotAdvertisePeer) + <$> parseJSON (Object o) <*> o .:? "behindFirewall" .!= False instance ToJSON LocalRoots where From a0b92e2e99cadf7e564b13af11b0f85ceff81f83 Mon Sep 17 00:00:00 2001 From: edgr Date: Fri, 5 Dec 2025 12:29:27 +0800 Subject: [PATCH 15/24] Remove ConnectionMode from the behind firewall changelog fragment --- .../changelog.d/20251108_101451_edgr_behind_firewall.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ouroboros-network/changelog.d/20251108_101451_edgr_behind_firewall.md b/ouroboros-network/changelog.d/20251108_101451_edgr_behind_firewall.md index 91f38e6c4f4..aaad49b1f0c 100644 --- a/ouroboros-network/changelog.d/20251108_101451_edgr_behind_firewall.md +++ b/ouroboros-network/changelog.d/20251108_101451_edgr_behind_firewall.md @@ -8,8 +8,8 @@ For top level release notes, leave all the headers commented out. ### Breaking - Changed the type of `localRoots` to `LocalRoots`. -- Modified `AcquireOutboundConnection` to include an additional parameter: `ConnectionMode`. -- `acquireOutboundConnectionImpl` only creates a new connection if the `ConnectionMode` function permits it. +- Modified `AcquireOutboundConnection` to include an additional parameter: `Provenance`. +- `acquireOutboundConnectionImpl` only creates a new connection if `Provenance` permits it. - `jobPromoteColdPeer` only creates a new connection if no inbound connection is found and the peer is not behind a firewall. ### Non-Breaking @@ -18,5 +18,4 @@ For top level release notes, leave all the headers commented out. - `rootConfig` of type `RootConfig` - `behindFirewall` of type `Bool` - Added `localRootBehindFirewall` field to `LocalRootConfig`. -- Added a new sum type: `ConnectionMode`. - Added a new constructor `InboundConnectionNotFound` for `ConnectionManagerError`. From cc2519c1b2008649daaac920dcb86f90304992d7 Mon Sep 17 00:00:00 2001 From: edgr Date: Fri, 5 Dec 2025 14:36:31 +0800 Subject: [PATCH 16/24] remove mutableConnState from failed aqcuire outbound connection --- .../Network/ConnectionManager/Core.hs | 42 +++++++------------ 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs index dd5bdd6828f..9c335385a99 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs @@ -1343,8 +1343,7 @@ with args@Arguments { acquireOutboundConnectionImpl stateVar stdGenVar handler diffusionMode peerAddr connectionMode = do let provenance = Outbound traceWith tracer (TrIncludeConnection provenance peerAddr) - (trace, mutableConnState@MutableConnState { connVar, connStateId } - , eHandleWedge) <- atomically $ do + (trace, eHandleWedge) <- atomically $ do state <- readTMVar stateVar stdGen <- stateTVar stdGenVar Random.split case State.lookupByRemoteAddr stdGen peerAddr state of @@ -1354,14 +1353,12 @@ with args@Arguments { case connState of ReservedOutboundState -> return ( Just (Right (TrConnectionExists provenance peerAddr st)) - , mutableConnState , Left (withCallStack (ConnectionExists provenance peerAddr)) ) UnnegotiatedState Outbound _connId _connThread -> do return ( Just (Right (TrConnectionExists provenance peerAddr st)) - , mutableConnState , Left (withCallStack (ConnectionExists provenance peerAddr)) ) @@ -1371,20 +1368,17 @@ with args@Arguments { -- return 'There' to indicate that we need to block on -- the connection state. return ( Nothing - , mutableConnState - , Right (There connId) + , Right (mutableConnState, There connId) ) OutboundUniState {} -> do return ( Just (Right (TrConnectionExists provenance peerAddr st)) - , mutableConnState , Left (withCallStack (ConnectionExists provenance peerAddr)) ) OutboundDupState {} -> do return ( Just (Right (TrConnectionExists provenance peerAddr st)) - , mutableConnState , Left (withCallStack (ConnectionExists provenance peerAddr)) ) @@ -1392,13 +1386,11 @@ with args@Arguments { OutboundIdleState _connId _connThread _handle _dataFlow -> let tr = State.abstractState (Known connState) in return ( Just (Right (TrForbiddenOperation peerAddr tr)) - , mutableConnState , Left (withCallStack (ForbiddenOperation peerAddr tr)) ) InboundIdleState connId _connThread _handle Unidirectional -> do return ( Just (Right (TrForbiddenConnection connId)) - , mutableConnState , Left (withCallStack (ForbiddenConnection connId)) ) @@ -1413,15 +1405,13 @@ with args@Arguments { return ( Just (Left (TransitionTrace connStateId (mkTransition connState connState'))) - , mutableConnState - , Right (Here (Connected connId dataFlow handle)) + , Right (mutableConnState, Here (Connected connId dataFlow handle)) ) InboundState connId _connThread _handle Unidirectional -> do -- the remote side negotiated unidirectional connection, we -- cannot re-use it. return ( Just (Right (TrForbiddenConnection connId)) - , mutableConnState , Left (withCallStack (ForbiddenConnection connId)) ) @@ -1436,13 +1426,11 @@ with args@Arguments { return ( Just (Left (TransitionTrace connStateId (mkTransition connState connState'))) - , mutableConnState - , Right (Here (Connected connId dataFlow handle)) + , Right (mutableConnState, Here (Connected connId dataFlow handle)) ) DuplexState _connId _connThread _handle -> return ( Just (Right (TrConnectionExists provenance peerAddr st)) - , mutableConnState , Left (withCallStack (ConnectionExists provenance peerAddr)) ) @@ -1459,21 +1447,20 @@ with args@Arguments { retry Nothing -> do - let connState' = ReservedOutboundState - (mutableConnState@MutableConnState { connVar, connStateId } - :: MutableConnState peerAddr handle handleError - version m) - <- State.newMutableConnState peerAddr connStateIdSupply connState' - -- Only proceed if creating a new connection is allowed if connectionMode == Inbound then do return ( Just (Right (TrInboundConnectionNotFound connectionMode peerAddr)) - , mutableConnState , Left (withCallStack (InboundConnectionNotFound connectionMode peerAddr)) ) else do + let connState' = ReservedOutboundState + (mutableConnState@MutableConnState { connVar, connStateId } + :: MutableConnState peerAddr handle handleError + version m) + <- State.newMutableConnState peerAddr connStateIdSupply connState' + -- TODO: label `connVar` using 'ConnectionId' labelTVar connVar ("conn-state-" ++ show peerAddr) @@ -1485,8 +1472,7 @@ with args@Arguments { fromState = Unknown, toState = Known connState' })) - , mutableConnState - , Right Nowhere + , Right (mutableConnState, Nowhere) ) traverse_ (either (traceWith trTracer) (traceWith tracer)) trace @@ -1496,7 +1482,7 @@ with args@Arguments { throwIO e -- connection manager does not have a connection with @peerAddr@. - Right Nowhere -> do + Right (mutableConnState@MutableConnState { connVar, connStateId }, Nowhere) -> do (reader, writer) <- newEmptyPromiseIO (connId, connThread) <- @@ -1730,7 +1716,7 @@ with args@Arguments { Right _ -> Connected connId dataFlow handle Left err -> Disconnected connId err - Right (There connId) -> do + Right (MutableConnState { connVar, connStateId }, There connId) -> do -- We can only enter the 'There' case if there is an inbound -- connection, and we are about to reuse it, but we need to wait -- for handshake. @@ -1822,7 +1808,7 @@ with args@Arguments { return connected -- Connection manager has a connection which can be reused. - Right (Here connected) -> do + Right (_, Here connected) -> do traceCounters stateVar return connected From 68580153d8cb9b1d9d69bc5eecd031f7426bbced Mon Sep 17 00:00:00 2001 From: edgr Date: Fri, 5 Dec 2025 14:46:49 +0800 Subject: [PATCH 17/24] Rename connection mode variables --- .../lib/Ouroboros/Network/ConnectionManager/Core.hs | 8 ++++---- .../Ouroboros/Network/PeerSelection/PeerStateActions.hs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs index 9c335385a99..97761f03f09 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs @@ -1340,7 +1340,7 @@ with args@Arguments { -> peerAddr -> Provenance -> m (Connected peerAddr handle handleError) - acquireOutboundConnectionImpl stateVar stdGenVar handler diffusionMode peerAddr connectionMode = do + acquireOutboundConnectionImpl stateVar stdGenVar handler diffusionMode peerAddr connProv = do let provenance = Outbound traceWith tracer (TrIncludeConnection provenance peerAddr) (trace, eHandleWedge) <- atomically $ do @@ -1448,11 +1448,11 @@ with args@Arguments { Nothing -> do -- Only proceed if creating a new connection is allowed - if connectionMode == Inbound + if connProv == Inbound then do - return ( Just (Right (TrInboundConnectionNotFound connectionMode peerAddr)) + return ( Just (Right (TrInboundConnectionNotFound connProv peerAddr)) , Left (withCallStack - (InboundConnectionNotFound connectionMode peerAddr)) + (InboundConnectionNotFound connProv peerAddr)) ) else do let connState' = ReservedOutboundState diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs index 441959187ec..54f42a55c1d 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/PeerStateActions.hs @@ -766,7 +766,7 @@ withPeerStateActions PeerStateActionsArguments { -> Provenance -> peerAddr -> m (PeerConnectionHandle muxMode responderCtx peerAddr versionData ByteString m a b) - establishPeerConnection jobPool isBigLedgerPeer diffusionMode connectionMode remotePeerAddr = + establishPeerConnection jobPool isBigLedgerPeer diffusionMode provenance remotePeerAddr = -- Protect consistency of the peer state with 'bracketOnError' if -- opening a connection fails. bracketOnError @@ -777,7 +777,7 @@ withPeerStateActions PeerStateActionsArguments { spsConnectionManager diffusionMode remotePeerAddr - connectionMode + provenance case res of Left e -> do when (isNothing $ fromException @SomeAsyncException e) $ From 53beda8dd03cdf62ab20a7b0dd73dce919d79bff Mon Sep 17 00:00:00 2001 From: edgr Date: Wed, 10 Dec 2025 09:41:10 +0800 Subject: [PATCH 18/24] EstablishedPeers cleanup --- .../Governor/EstablishedPeers.hs | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs index 83fa1eeabc7..59d847363a8 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs @@ -188,7 +188,7 @@ belowTargetLocal actions@PeerSelectionActions { }, decisionJobs = [ jobPromoteColdPeer actions policy peer IsNotBigLedgerPeer diffusionMode - (localRootConnectionProvenance peer localRootPeers) + (localRootConnectionProvenance peer) | peer <- Set.toList selectedToPromote , let diffusionMode = LocalRootPeers.diffusionMode $ LocalRootPeers.toMap localRootPeers Map.! peer @@ -218,6 +218,17 @@ belowTargetLocal actions@PeerSelectionActions { minConnectExcludeSet = bigLedgerPeersSet `Set.union` Set.difference establishedPeers localEstablishedPeers + + localRootConnectionProvenance + :: peeraddr + -> Provenance + localRootConnectionProvenance peer = + maybe + Outbound + (\LocalRootConfig {localRootBehindFirewall} -> + bool Outbound Inbound localRootBehindFirewall) + (Map.lookup peer $ LocalRootPeers.toMap localRootPeers) + PeerSelectionView { viewKnownBigLedgerPeers = (bigLedgerPeersSet, _), @@ -265,7 +276,6 @@ belowTargetOther actions@PeerSelectionActions { policyPickColdPeersToPromote } st@PeerSelectionState { - localRootPeers, knownPeers, inProgressPromoteCold, targets = PeerSelectionTargets { @@ -290,8 +300,7 @@ belowTargetOther actions@PeerSelectionActions { }, decisionJobs = [ jobPromoteColdPeer actions policy peer IsNotBigLedgerPeer - InitiatorAndResponderDiffusionMode - (localRootConnectionProvenance peer localRootPeers) + InitiatorAndResponderDiffusionMode Outbound | peer <- Set.toList selectedToPromote ] } @@ -377,7 +386,6 @@ belowTargetBigLedgerPeers enableAction policyPickColdPeersToPromote } st@PeerSelectionState { - localRootPeers, knownPeers, establishedPeers, inProgressPromoteCold, @@ -424,8 +432,7 @@ belowTargetBigLedgerPeers enableAction <> selectedToPromote }, decisionJobs = [ jobPromoteColdPeer actions policy peer IsBigLedgerPeer - InitiatorAndResponderDiffusionMode - (localRootConnectionProvenance peer localRootPeers) + InitiatorAndResponderDiffusionMode Outbound | peer <- Set.toList selectedToPromote ] } @@ -877,20 +884,6 @@ aboveTargetBigLedgerPeers actions@PeerSelectionActions { | otherwise = GuardedSkip Nothing -localRootConnectionProvenance - :: forall peeraddr extraFlags. - ( Ord peeraddr - ) - => peeraddr - -> LocalRootPeers.LocalRootPeers extraFlags peeraddr - -> Provenance -localRootConnectionProvenance peer localRootPeers = - maybe - Outbound - (\LocalRootConfig {localRootBehindFirewall} -> - bool Outbound Inbound localRootBehindFirewall) - (Map.lookup peer $ LocalRootPeers.toMap localRootPeers) - jobDemoteEstablishedPeer :: forall extraState extraDebugState extraFlags extraPeers extraAPI extraCounters extraTrace peeraddr peerconn m. From 01d2727e46d212e365596386263d31132c8a2a14 Mon Sep 17 00:00:00 2001 From: edgr Date: Wed, 10 Dec 2025 09:58:32 +0800 Subject: [PATCH 19/24] Fix comment for AcquireOutboundConnection --- .../framework/lib/Ouroboros/Network/ConnectionManager/Types.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs index 4a47d13367b..a8aac8abe3a 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs @@ -500,8 +500,7 @@ data Connected peerAddr handle handleError = -- | Acquire outbound connection -- 'Inbound' provenance restricts acquiring an outbound connection to those -- initiated by a remote peer. --- 'Outbound' provenance allows acquiring an outbound connection regardless of --- who initiated it. +-- 'Outbound' provenance doesn't require any additional pre-conditions. type AcquireOutboundConnection peerAddr handle handleError m = DiffusionMode -> peerAddr -> Provenance -> m (Connected peerAddr handle handleError) From 34a510589bf8b9ed4957dccd40bbf50fa32095c3 Mon Sep 17 00:00:00 2001 From: edgr Date: Wed, 10 Dec 2025 11:27:10 +0800 Subject: [PATCH 20/24] Replace local root peers fields with provenance fields --- .../Test/Cardano/Network/Diffusion/Testnet.hs | 68 ++++++++++--------- .../lib/Test/Cardano/Network/PeerSelection.hs | 13 ++-- .../Ouroboros/Network/Diffusion/Topology.hs | 16 ++--- .../Governor/EstablishedPeers.hs | 4 +- .../PeerSelection/State/LocalRootPeers.hs | 9 +-- .../Ouroboros/Network/OrphanInstances.hs | 19 ++++-- .../Network/PeerSelection/Instances.hs | 3 +- .../Network/PeerSelection/RootPeersDNS.hs | 5 +- 8 files changed, 75 insertions(+), 62 deletions(-) diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs index 2088dc25ba3..9ddacc25ad9 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs @@ -392,7 +392,7 @@ unit_cm_valid_transitions = [ (HotValency {getHotValency = 1}, WarmValency {getWarmValency = 1}, Map.fromList [(RelayAccessAddress "0:71:0:1:0:1:0:1" 65_534, - LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsTrustable)]) + LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsTrustable)]) ] (Script (LedgerPools [] :| [])) (PeerSelectionTargets @@ -434,7 +434,7 @@ unit_cm_valid_transitions = [ (HotValency {getHotValency = 1}, WarmValency {getWarmValency = 1}, Map.fromList [(RelayAccessAddress "0:79::1:0:0" 3, - LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsTrustable)]) + LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsTrustable)]) ] (Script (LedgerPools [] :| [])) ( PeerSelectionTargets @@ -638,7 +638,7 @@ unit_connection_manager_trace_coverage = naPeerSharing = PeerSharingDisabled, naLocalRootPeers = [ (1,1,Map.fromList [ (RelayAccessAddress (read "127.0.0.1") 1000, - LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) + LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable) ]) ], naLedgerPeers = Script (LedgerPools [] :| []), @@ -761,7 +761,7 @@ unit_connection_manager_transitions_coverage = naPeerSharing = PeerSharingDisabled, naLocalRootPeers = [ (1,1,Map.fromList [ (RelayAccessAddress (read "127.0.0.1") 1000, - LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) + LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable) ]) ], naLedgerPeers = Script (LedgerPools [] :| []), @@ -887,7 +887,7 @@ prop_txSubmission_allTransactions (ArbTxDecisionPolicy decisionPolicy) let localRootConfig = LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode - False + Outbound IsNotTrustable diffScript = DiffusionScript @@ -1324,8 +1324,8 @@ unit_4177 = prop_inbound_governor_transitions_coverage absNoAttenuation script (Script (UseBootstrapPeers [RelayAccessDomain "bootstrap" 0] :| [])) (TestAddress (IPAddr (read "0:7:0:7::") 65_533)) PeerSharingDisabled - [ (1,1,Map.fromList [(RelayAccessDomain "test2" 65_535,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) - , (RelayAccessAddress "0:6:0:3:0:6:0:5" 65_530,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]) + [ (1,1,Map.fromList [(RelayAccessDomain "test2" 65_535,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable) + , (RelayAccessAddress "0:6:0:3:0:6:0:5" 65_530,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)]) ] (Script (LedgerPools [] :| [])) (nullPeerSelectionTargets { @@ -1343,11 +1343,11 @@ unit_4177 = prop_inbound_governor_transitions_coverage absNoAttenuation script (Script (PraosFetchMode FetchModeDeadline :| [])) [] , [JoinNetwork 1.742_857_142_857 - ,Reconfigure 6.333_333_333_33 [(1,1,Map.fromList [(RelayAccessDomain "test2" 65_535,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]), - (1,1,Map.fromList [(RelayAccessAddress "0:6:0:3:0:6:0:5" 65_530,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) + ,Reconfigure 6.333_333_333_33 [(1,1,Map.fromList [(RelayAccessDomain "test2" 65_535,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)]), + (1,1,Map.fromList [(RelayAccessAddress "0:6:0:3:0:6:0:5" 65_530,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable) ])] - ,Reconfigure 23.888_888_888_88 [(1,1,Map.empty),(1,1,Map.fromList [(RelayAccessAddress "0:6:0:3:0:6:0:5" 65_530,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] - ,Reconfigure 4.870_967_741_935 [(1,1,Map.fromList [(RelayAccessDomain "test2" 65_535,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] + ,Reconfigure 23.888_888_888_88 [(1,1,Map.empty),(1,1,Map.fromList [(RelayAccessAddress "0:6:0:3:0:6:0:5" 65_530,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])] + ,Reconfigure 4.870_967_741_935 [(1,1,Map.fromList [(RelayAccessDomain "test2" 65_535,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])] ] ) , ( NodeArgs 1 InitiatorAndResponderDiffusionMode @@ -1997,8 +1997,8 @@ unit_4191 = testWithIOSim prop_diffusion_dns_can_recover long_trace absInfo scri (Script (UseBootstrapPeers [RelayAccessDomain "bootstrap" 0] :| [])) (TestAddress (IPAddr (read "0.0.1.236") 65_527)) PeerSharingDisabled - [ (2,2,Map.fromList [ (RelayAccessDomain "test2" 15,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) - , (RelayAccessDomain "test3" 4,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]) + [ (2,2,Map.fromList [ (RelayAccessDomain "test2" 15,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable) + , (RelayAccessDomain "test3" 4,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)]) ] (Script (LedgerPools [] :| [])) (PeerSelectionTargets @@ -2048,7 +2048,7 @@ unit_4191 = testWithIOSim prop_diffusion_dns_can_recover long_trace absInfo scri , Reconfigure 0.415_384_615_384 [(1,1,Map.empty) , (1,1,Map.empty)] , Reconfigure 15.550_561_797_752 [(1,1,Map.empty) - , (1,1,Map.fromList [(RelayAccessDomain "test2" 15,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] + , (1,1,Map.fromList [(RelayAccessDomain "test2" 15,LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])] , Reconfigure 82.857_142_857_14 [] ]) ] @@ -2113,7 +2113,7 @@ prop_connect_failure (AbsIOError ioerr) = naBootstrapPeers = Script (DontUseBootstrapPeers :| []), naAddr = TestAddress (IPAddr nodeIP nodePort), naPeerSharing = PeerSharingDisabled, - naLocalRootPeers = [(1,1,Map.fromList [(RelayAccessAddress relayIP relayPort,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], + naLocalRootPeers = [(1,1,Map.fromList [(RelayAccessAddress relayIP relayPort,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])], naLedgerPeers = Script (LedgerPools [] :| []), naPeerTargets = (PeerSelectionTargets { targetNumberOfRootPeers = 1, @@ -2241,7 +2241,7 @@ prop_accept_failure (AbsIOError ioerr) = naBootstrapPeers = Script (DontUseBootstrapPeers :| []), naAddr = TestAddress (IPAddr nodeIP nodePort), naPeerSharing = PeerSharingDisabled, - naLocalRootPeers = [(1,1,Map.fromList [(RelayAccessAddress relayIP relayPort,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], + naLocalRootPeers = [(1,1,Map.fromList [(RelayAccessAddress relayIP relayPort,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])], naLedgerPeers = Script (LedgerPools [] :| []), naPeerTargets = (PeerSelectionTargets { targetNumberOfRootPeers = 1, @@ -2900,7 +2900,11 @@ prop_diffusion_never_connect_peer_behind_firewall ioSimTrace traceNumber = let unreachablePeers = Map.keysSet - $ Map.filter localRootBehindFirewall + $ Map.filter (\peers -> + case localProvenance peers of + Outbound -> False + Inbound -> True + ) $ LocalRootPeers.toMap local in unreachablePeers @@ -3319,21 +3323,21 @@ async_demotion_network_script = ] ) , ( common { naAddr = addr2, - naLocalRootPeers = [(1,1, Map.fromList [(ra_addr1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] } + naLocalRootPeers = [(1,1, Map.fromList [(ra_addr1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])] } , [JoinNetwork 0, Kill 5, JoinNetwork 20] ) , ( common { naAddr = addr3, - naLocalRootPeers = [(1,1, Map.fromList [(ra_addr1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] } + naLocalRootPeers = [(1,1, Map.fromList [(ra_addr1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])] } , [JoinNetwork 0] ) ] where addr1 = TestAddress (IPAddr (read "10.0.0.1") 3000) ra_addr1 = RelayAccessAddress (read "10.0.0.1") 3000 - localRoots1 = [(2,2, Map.fromList [(ra_addr2, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) - ,(ra_addr3, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] - localRoots1' = [(2,2, Map.fromList [(ra_addr2, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) - ,(ra_addr3, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] + localRoots1 = [(2,2, Map.fromList [(ra_addr2, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable) + ,(ra_addr3, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])] + localRoots1' = [(2,2, Map.fromList [(ra_addr2, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable) + ,(ra_addr3, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])] addr2 = TestAddress (IPAddr (read "10.0.0.2") 3000) ra_addr2 = RelayAccessAddress (read "10.0.0.2") 3000 @@ -3915,7 +3919,7 @@ prop_unit_4258 = (Script (UseBootstrapPeers [RelayAccessDomain "bootstrap" 0] :| [])) (TestAddress (IPAddr (read "0.0.0.4") 9)) PeerSharingDisabled - [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.8" 65_531,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] + [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.8" 65_531,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])] (Script (LedgerPools [] :| [])) (nullPeerSelectionTargets { targetNumberOfRootPeers = 2, @@ -3950,7 +3954,7 @@ prop_unit_4258 = (Script (UseBootstrapPeers [RelayAccessDomain "bootstrap" 0] :| [])) (TestAddress (IPAddr (read "0.0.0.8") 65_531)) PeerSharingDisabled - [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.4" 9,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] + [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.4" 9,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])] (Script (LedgerPools [] :| [])) (nullPeerSelectionTargets { targetNumberOfRootPeers = 4, @@ -3981,7 +3985,7 @@ prop_unit_4258 = (Script (PraosFetchMode FetchModeDeadline :| [])) [] , [ JoinNetwork 3.384_615_384_615, - Reconfigure 3.583_333_333_333 [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.4" 9,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], + Reconfigure 3.583_333_333_333 [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.4" 9,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])], Kill 15.555_555_555_55, JoinNetwork 30.533_333_333_33, Kill 71.111_111_111_11 @@ -4022,8 +4026,8 @@ prop_unit_reconnect = (Script (DontUseBootstrapPeers :| [])) (TestAddress (IPAddr (read "0.0.0.0") 0)) PeerSharingDisabled - [ (2,2,Map.fromList [ (RelayAccessAddress "0.0.0.1" 0,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) - , (RelayAccessAddress "0.0.0.2" 0,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable) + [ (2,2,Map.fromList [ (RelayAccessAddress "0.0.0.1" 0,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable) + , (RelayAccessAddress "0.0.0.2" 0,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable) ]) ] (Script (LedgerPools [] :| [])) @@ -4053,7 +4057,7 @@ prop_unit_reconnect = (Script (DontUseBootstrapPeers :| [])) (TestAddress (IPAddr (read "0.0.0.1") 0)) PeerSharingDisabled - [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.0" 0,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])] + [(1,1,Map.fromList [(RelayAccessAddress "0.0.0.0" 0,LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])] (Script (LedgerPools [] :| [])) (PeerSelectionTargets { targetNumberOfRootPeers = 1, @@ -4504,7 +4508,7 @@ unit_peer_sharing = (mainnetSimArgs 3 defaultTxDecisionPolicy) (singletonScript (mempty, ShortDelay)) [ ( (defaultNodeArgs GenesisMode) { naAddr = ip_0, - naLocalRootPeers = [(1, 1, Map.fromList [(ra_1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], + naLocalRootPeers = [(1, 1, Map.fromList [(ra_1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])], naPeerTargets = targets 1 } , [JoinNetwork 0] @@ -4516,7 +4520,7 @@ unit_peer_sharing = , [JoinNetwork 0] ) , ( (defaultNodeArgs GenesisMode) { naAddr = ip_2, - naLocalRootPeers = [(1, 1, Map.fromList [(ra_1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], + naLocalRootPeers = [(1, 1, Map.fromList [(ra_1, LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])], naPeerTargets = targets 2 } , [JoinNetwork 0] @@ -5035,7 +5039,7 @@ unit_local_root_diffusion_mode diffusionMode = naPeerSharing = PeerSharingDisabled, naLocalRootPeers = [ (1,1,Map.fromList [ (RelayAccessAddress (read "127.0.0.1") 1000, - LocalRootConfig DoNotAdvertisePeer diffusionMode False IsNotTrustable) + LocalRootConfig DoNotAdvertisePeer diffusionMode Outbound IsNotTrustable) ]) ], naLedgerPeers = Script (LedgerPools [] :| []), diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs index 4b17b2d86e4..46b7a28e1b9 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs @@ -59,6 +59,7 @@ import Cardano.Network.PeerSelection -- import Cardano.Network.PeerSelection.PublicRootPeers (PublicRootPeers (..)) import Cardano.Network.PeerSelection.PublicRootPeers qualified as Cardano.PublicRootPeers +import Ouroboros.Network.ConnectionManager.Types (Provenance(Outbound)) import Ouroboros.Network.DiffusionMode import Ouroboros.Network.ExitPolicy (RepromoteDelay (..)) import Ouroboros.Network.PeerSelection @@ -4430,8 +4431,8 @@ prop_issue_3550 = prop_governor_target_established_below defaultMaxTime $ (PeerAddr 29,[],GovernorScripts {peerShareScript = Script (Nothing :| []), peerSharingScript = Script (PeerSharingDisabled :| []), connectionScript = Script ((ToWarm,NoDelay) :| [(ToCold,NoDelay),(Noop,NoDelay)])}) ], localRootPeers = LocalRootPeers.fromGroups - [ (1, 1, Map.fromList [(PeerAddr 16, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]) - , (1, 1, Map.fromList [(PeerAddr 4, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]) + [ (1, 1, Map.fromList [(PeerAddr 16, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)]) + , (1, 1, Map.fromList [(PeerAddr 4, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)]) ], publicRootPeers = Cardano.PublicRootPeers.fromPublicRootPeers (Map.fromList [ (PeerAddr 14, DoNotAdvertisePeer) @@ -4478,7 +4479,7 @@ prop_issue_3515 = prop_governor_nolivelock $ peerSharingScript = Script (PeerSharingDisabled :| []), connectionScript = Script ((ToCold,NoDelay) :| [(Noop,NoDelay)]) })], - localRootPeers = LocalRootPeers.fromGroups [(1,1,Map.fromList [(PeerAddr 10, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], + localRootPeers = LocalRootPeers.fromGroups [(1,1,Map.fromList [(PeerAddr 10, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])], publicRootPeers = PublicRootPeers.empty Cardano.ExtraPeers.empty, targets = Script . NonEmpty.fromList $ targets'', pickKnownPeersForPeerShare = Script (PickFirst :| []), @@ -4520,7 +4521,7 @@ prop_issue_3494 = prop_governor_nofail $ peerSharingScript = Script (PeerSharingDisabled :| []), connectionScript = Script ((ToCold,NoDelay) :| [(Noop,NoDelay)]) })], - localRootPeers = LocalRootPeers.fromGroups [(1,1,Map.fromList [(PeerAddr 64, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)])], + localRootPeers = LocalRootPeers.fromGroups [(1,1,Map.fromList [(PeerAddr 64, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)])], publicRootPeers = PublicRootPeers.empty Cardano.ExtraPeers.empty, targets = Script . NonEmpty.fromList $ targets'', pickKnownPeersForPeerShare = Script (PickFirst :| []), @@ -4570,8 +4571,8 @@ prop_issue_3233 = prop_governor_nolivelock $ (PeerAddr 15,[],GovernorScripts {peerShareScript = Script (Just ([],PeerShareTimeSlow) :| []), peerSharingScript = Script (PeerSharingDisabled :| []), connectionScript = Script ((Noop,NoDelay) :| [])}) ], localRootPeers = LocalRootPeers.fromGroups - [ (1, 1, Map.fromList [(PeerAddr 15, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]) - , (1, 1, Map.fromList [(PeerAddr 13, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False IsNotTrustable)]) + [ (1, 1, Map.fromList [(PeerAddr 15, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)]) + , (1, 1, Map.fromList [(PeerAddr 13, LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound IsNotTrustable)]) ], publicRootPeers = Cardano.PublicRootPeers.fromPublicRootPeers (Map.fromList [(PeerAddr 4, DoNotAdvertisePeer)]), diff --git a/ouroboros-network/lib/Ouroboros/Network/Diffusion/Topology.hs b/ouroboros-network/lib/Ouroboros/Network/Diffusion/Topology.hs index bc6b4024daa..0033d80278b 100644 --- a/ouroboros-network/lib/Ouroboros/Network/Diffusion/Topology.hs +++ b/ouroboros-network/lib/Ouroboros/Network/Diffusion/Topology.hs @@ -5,6 +5,7 @@ module Ouroboros.Network.Diffusion.Topology where import Data.Map qualified as Map import Data.Map.Strict (Map) +import Ouroboros.Network.ConnectionManager.Types (Provenance) import Ouroboros.Network.Diffusion.Configuration (DiffusionMode) import Ouroboros.Network.PeerSelection.LedgerPeers.Type (UseLedgerPeers) import Ouroboros.Network.PeerSelection.PeerAdvertise (PeerAdvertise) @@ -45,9 +46,8 @@ newtype PublicRootPeers = PublicRootPeers } deriving (Eq, Show) data LocalRoots = LocalRoots - { rootConfig :: RootConfig - , behindFirewall :: Bool - -- ^ peer is unreachable and will initiate the connection first + { rootConfig :: RootConfig + , provenance :: Provenance } deriving (Eq, Show) -- | Each root peer consists of a list of access points and a shared @@ -74,9 +74,9 @@ rootConfigToRelayAccessPoint RootConfig { rootAccessPoints, rootAdvertise } = localRootsToRelayAccessPoint :: LocalRoots - -> [(RelayAccessPoint, PeerAdvertise, Bool)] -localRootsToRelayAccessPoint LocalRoots {rootConfig, behindFirewall} = - (\(accessPoint, advertise) -> (accessPoint, advertise, behindFirewall)) + -> [(RelayAccessPoint, PeerAdvertise, Provenance)] +localRootsToRelayAccessPoint LocalRoots {rootConfig, provenance} = + (\(accessPoint, advertise) -> (accessPoint, advertise, provenance)) <$> rootConfigToRelayAccessPoint rootConfig producerAddresses @@ -91,12 +91,12 @@ producerAddresses NetworkTopology { localRootPeersGroups ( map (\lrp -> ( hotValency lrp , warmValency lrp , Map.fromList - . map (\(addr, peerAdvertise, localRootBehindFirewall) -> + . map (\(addr, peerAdvertise, localProvenance) -> ( addr , LocalRootConfig { diffusionMode = rootDiffusionMode lrp, peerAdvertise, - localRootBehindFirewall, + localProvenance, extraLocalRootFlags = extraFlags lrp } ) diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs index 59d847363a8..e1706d328bb 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/Governor/EstablishedPeers.hs @@ -8,7 +8,6 @@ module Ouroboros.Network.PeerSelection.Governor.EstablishedPeers , aboveTarget ) where -import Data.Bool (bool) import Data.Map.Strict (Map) import Data.Map.Strict qualified as Map import Data.Set (Set) @@ -225,8 +224,7 @@ belowTargetLocal actions@PeerSelectionActions { localRootConnectionProvenance peer = maybe Outbound - (\LocalRootConfig {localRootBehindFirewall} -> - bool Outbound Inbound localRootBehindFirewall) + localProvenance (Map.lookup peer $ LocalRootPeers.toMap localRootPeers) diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/LocalRootPeers.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/LocalRootPeers.hs index efa4735e9eb..264b3f90e36 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/LocalRootPeers.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/LocalRootPeers.hs @@ -35,6 +35,7 @@ import Data.Map.Strict qualified as Map import Data.Set (Set) import Data.Set qualified as Set +import Ouroboros.Network.ConnectionManager.Types (Provenance) import Ouroboros.Network.DiffusionMode import Ouroboros.Network.PeerSelection.PeerAdvertise (PeerAdvertise) @@ -44,10 +45,10 @@ import Ouroboros.Network.PeerSelection.PeerAdvertise (PeerAdvertise) -- data LocalRootConfig extraFlags = LocalRootConfig { - peerAdvertise :: !PeerAdvertise, - diffusionMode :: !DiffusionMode, - localRootBehindFirewall :: !Bool, - extraLocalRootFlags :: !extraFlags + peerAdvertise :: !PeerAdvertise, + diffusionMode :: !DiffusionMode, + localProvenance :: !Provenance, + extraLocalRootFlags :: !extraFlags } deriving (Show, Eq) diff --git a/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs b/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs index ea96ef69f46..f482646067d 100644 --- a/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs +++ b/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs @@ -26,6 +26,7 @@ import Control.Monad.Class.MonadTime.SI (Time (..)) import Data.Aeson import Data.Aeson.Types (Pair, Parser, listValue) import Data.Bifunctor (first) +import Data.Bool (bool) import Data.Foldable (toList) import Data.IP (fromHostAddress, fromHostAddress6) import Data.Map.Strict qualified as Map @@ -63,7 +64,7 @@ import Ouroboros.Network.ConnectionManager.State (ConnMap (..), ConnStateId (..), LocalAddr (..)) import Ouroboros.Network.ConnectionManager.Types (AbstractState (..), ConnectionManagerCounters (..), MaybeUnknown (..), - OperationResult (..)) + OperationResult (..), Provenance(..)) import Ouroboros.Network.ConnectionManager.Types qualified as ConnMgr import Ouroboros.Network.DeltaQ (GSV (GSV), PeerGSV (PeerGSV, inboundGSV, outboundGSV)) @@ -98,16 +99,22 @@ kindObject k fields = object $ ("kind" .= String k) : fields -- FromJSON Instances instance FromJSON LocalRoots where - parseJSON = withObject "LocalRoots" $ \o -> - LocalRoots - <$> parseJSON (Object o) - <*> o .:? "behindFirewall" .!= False + parseJSON = withObject "LocalRoots" $ \o -> do + conf <- o .: "rootConfig" + behindFirewall <- o .:? "behindFirewall" .!= False + pure $ + LocalRoots + conf + (bool Outbound Inbound behindFirewall) instance ToJSON LocalRoots where toJSON ra = object [ "rootConfig" .= rootConfig ra - , "behindFirewall" .= behindFirewall ra + , "behindFirewall" .= + case provenance ra of + Outbound -> False + Inbound -> True ] instance FromJSON RootConfig where diff --git a/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/Instances.hs b/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/Instances.hs index b2043ed64b2..f91da6fce7e 100644 --- a/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/Instances.hs +++ b/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/Instances.hs @@ -26,6 +26,7 @@ import Data.Word (Word16, Word32, Word64) import Cardano.Slotting.Slot (SlotNo (..)) +import Ouroboros.Network.ConnectionManager.Types (Provenance(..)) import Ouroboros.Network.DiffusionMode import Ouroboros.Network.PeerSelection.Governor @@ -171,7 +172,7 @@ instance Arbitrary extraFlags => Arbitrary (LocalRootConfig extraFlags) where arbitrary = LocalRootConfig <$> arbitrary <*> elements [InitiatorAndResponderDiffusionMode, InitiatorOnlyDiffusionMode] - <*> arbitrary + <*> elements [Outbound, Inbound] <*> arbitrary shrink a@LocalRootConfig { peerAdvertise, extraLocalRootFlags = peerTrustable, diff --git a/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/RootPeersDNS.hs b/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/RootPeersDNS.hs index 0315c071619..f1e08155982 100644 --- a/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/RootPeersDNS.hs +++ b/ouroboros-network/tests/lib/Test/Ouroboros/Network/PeerSelection/RootPeersDNS.hs @@ -70,6 +70,7 @@ import Control.Monad.Class.MonadTimer.SI qualified as MonadTimer import Control.Monad.IOSim import Control.Tracer (Tracer (Tracer), contramap, nullTracer, traceWith) +import Ouroboros.Network.ConnectionManager.Types (Provenance(Outbound)) import Ouroboros.Network.DiffusionMode import Ouroboros.Network.PeerSelection import Test.Ouroboros.Network.Data.Script (Script (Script), initScript', @@ -344,10 +345,10 @@ simpleMockRoots = MockRoots localRootPeers dnsMap Map.empty (singletonScript Map [ ( 2, 2 , Map.fromList [ ( RelayAccessAddress (read "192.0.2.1") (read "3333") - , LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode False () + , LocalRootConfig DoAdvertisePeer InitiatorAndResponderDiffusionMode Outbound () ) , ( RelayAccessDomain "test.domain" (read "4444") - , LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode False () + , LocalRootConfig DoNotAdvertisePeer InitiatorAndResponderDiffusionMode Outbound () ) ] ) From 0ef4c30c56d3ca48f691b57ec732da04dea79863 Mon Sep 17 00:00:00 2001 From: edgr Date: Wed, 10 Dec 2025 12:02:14 +0800 Subject: [PATCH 21/24] Update changelog fragment --- .../changelog.d/20251108_101451_edgr_behind_firewall.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ouroboros-network/changelog.d/20251108_101451_edgr_behind_firewall.md b/ouroboros-network/changelog.d/20251108_101451_edgr_behind_firewall.md index aaad49b1f0c..2b578a105ad 100644 --- a/ouroboros-network/changelog.d/20251108_101451_edgr_behind_firewall.md +++ b/ouroboros-network/changelog.d/20251108_101451_edgr_behind_firewall.md @@ -10,12 +10,12 @@ For top level release notes, leave all the headers commented out. - Changed the type of `localRoots` to `LocalRoots`. - Modified `AcquireOutboundConnection` to include an additional parameter: `Provenance`. - `acquireOutboundConnectionImpl` only creates a new connection if `Provenance` permits it. -- `jobPromoteColdPeer` only creates a new connection if no inbound connection is found and the peer is not behind a firewall. +- `jobPromoteColdPeer` only creates a new connection if no inbound connection is found and provenance is set to `Outbound`. ### Non-Breaking - Added `LocalRoots` type in `Ouroboros.Network.PeerSelection.State.LocalRootPeers` with the following fields: - `rootConfig` of type `RootConfig` - - `behindFirewall` of type `Bool` -- Added `localRootBehindFirewall` field to `LocalRootConfig`. + - `provenance` of type `Provenance` +- Added `localProvenance` field to `LocalRootConfig`. - Added a new constructor `InboundConnectionNotFound` for `ConnectionManagerError`. From 2e20fd0735960237d3d1a7d3bfb8461206bff0d7 Mon Sep 17 00:00:00 2001 From: edgr Date: Wed, 10 Dec 2025 12:11:15 +0800 Subject: [PATCH 22/24] Fix naming around TrInboundConnectionNotFound --- .../Test/Ouroboros/Network/ConnectionManager/Utils.hs | 4 ++-- .../orphan-instances/Ouroboros/Network/OrphanInstances.hs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs b/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs index 6ed42b204d1..d24205439ec 100644 --- a/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs +++ b/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs @@ -300,8 +300,8 @@ connectionManagerTraceMap ntnAddr (ConnectionHandlerTrace ntnVersion ntnVersionData) -> String -connectionManagerTraceMap (TrInboundConnectionNotFound cm _) = - "TrInboundConnectionNotFound " ++ show cm +connectionManagerTraceMap (TrInboundConnectionNotFound p _) = + "TrInboundConnectionNotFound " ++ show p connectionManagerTraceMap (TrIncludeConnection p _) = "TrIncludeConnection " ++ show p connectionManagerTraceMap (TrReleaseConnection p _) = diff --git a/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs b/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs index f482646067d..cbbfebe4b58 100644 --- a/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs +++ b/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs @@ -1287,11 +1287,11 @@ instance (Show addr, Show versionNumber, Show agreedOptions, ToJSON addr, ToJSON versionNumber, ToJSON agreedOptions) => ToJSON (ConnMgr.Trace addr (ConnectionHandlerTrace versionNumber agreedOptions)) where toJSON = \case - TrInboundConnectionNotFound connMode peerAddr -> + TrInboundConnectionNotFound prov peerAddr -> object [ "kind" .= String "InboundConnectionNotFound" , "remoteAddress" .= peerAddr - , "connectionMode" .= String (pack . show $ connMode) + , "provenance" .= String (pack . show $ prov) ] TrIncludeConnection prov peerAddr -> object From 8fecf763c4e153ddc9b74d287ffe12b885773a1d Mon Sep 17 00:00:00 2001 From: edgr Date: Wed, 10 Dec 2025 13:08:12 +0800 Subject: [PATCH 23/24] Cleanup: Formatting, comments --- .../Test/Cardano/Network/Diffusion/Testnet.hs | 6 +-- .../Network/PeerSelection/MockEnvironment.hs | 2 +- .../Network/ConnectionManager/Utils.hs | 40 +++++++++---------- .../Network/PeerSelection/State/KnownPeers.hs | 4 +- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs index 9ddacc25ad9..77c84b1bb49 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs @@ -2851,8 +2851,8 @@ prop_diffusion_target_established_local_iosim prop_diffusion_target_established_local_iosim = testWithIOSim prop_diffusion_target_established_local long_trace --- | Avoid connecting to root peers marked as behind a firewall and without --- inbound connection. +-- | Avoid connecting to root peers with inbound provenance and without inbound +-- connection. -- prop_diffusion_never_connect_peer_behind_firewall :: SimTrace Void @@ -2928,7 +2928,7 @@ prop_diffusion_never_connect_peer_behind_firewall ioSimTrace traceNumber = $ events in counterexample - ("\nSignal key: (local root peers, unreachables, inbounds") $ + "\nSignal key: (local root peers, unreachables, inbounds" $ signalProperty 100 show (\(_,unreachables,inbounds) -> unreachables `Set.disjoint` inbounds) ((,,) <$> govLocalRootPeersSig diff --git a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs index c4a41990e1c..5189e61c38b 100644 --- a/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs +++ b/cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs @@ -62,7 +62,7 @@ import Control.Monad.IOSim import Control.Tracer (Tracer (..), contramap, traceWith) import Ouroboros.Network.BlockFetch (FetchMode (..), PraosFetchMode (..)) -import Ouroboros.Network.ConnectionManager.Types (Provenance (..)) +import Ouroboros.Network.ConnectionManager.Types (Provenance) import Ouroboros.Network.DiffusionMode import Ouroboros.Network.ExitPolicy import Ouroboros.Network.PeerSelection hiding (requestPublicRootPeers) diff --git a/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs b/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs index d24205439ec..960e224c12b 100644 --- a/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs +++ b/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs @@ -302,43 +302,43 @@ connectionManagerTraceMap -> String connectionManagerTraceMap (TrInboundConnectionNotFound p _) = "TrInboundConnectionNotFound " ++ show p -connectionManagerTraceMap (TrIncludeConnection p _) = +connectionManagerTraceMap (TrIncludeConnection p _) = "TrIncludeConnection " ++ show p -connectionManagerTraceMap (TrReleaseConnection p _) = +connectionManagerTraceMap (TrReleaseConnection p _) = "TrUnregisterConnection " ++ show p -connectionManagerTraceMap TrConnect {} = +connectionManagerTraceMap TrConnect {} = "TrConnect" -connectionManagerTraceMap (TrConnectError _ _ _) = +connectionManagerTraceMap (TrConnectError _ _ _) = "TrConnectError" -connectionManagerTraceMap (TrTerminatingConnection p _) = +connectionManagerTraceMap (TrTerminatingConnection p _) = "TrTerminatingConnection " ++ show p -connectionManagerTraceMap (TrTerminatedConnection p _) = +connectionManagerTraceMap (TrTerminatedConnection p _) = "TrTerminatedConnection " ++ show p -connectionManagerTraceMap (TrConnectionHandler _ _) = +connectionManagerTraceMap (TrConnectionHandler _ _) = "TrConnectionHandler" -connectionManagerTraceMap TrShutdown = +connectionManagerTraceMap TrShutdown = "TrShutdown" -connectionManagerTraceMap (TrConnectionExists p _ as) = +connectionManagerTraceMap (TrConnectionExists p _ as) = "TrConnectionExists " ++ show p ++ " " ++ show as -connectionManagerTraceMap (TrForbiddenConnection _) = +connectionManagerTraceMap (TrForbiddenConnection _) = "TrForbiddenConnection" -connectionManagerTraceMap (TrConnectionFailure _) = +connectionManagerTraceMap (TrConnectionFailure _) = "TrConnectionFailure" -connectionManagerTraceMap (TrConnectionNotFound p _) = +connectionManagerTraceMap (TrConnectionNotFound p _) = "TrConnectionNotFound " ++ show p -connectionManagerTraceMap (TrForbiddenOperation _ as) = +connectionManagerTraceMap (TrForbiddenOperation _ as) = "TrForbiddenOperation" ++ show as -connectionManagerTraceMap (TrPruneConnections _ _ _) = +connectionManagerTraceMap (TrPruneConnections _ _ _) = "TrPruneConnections" -connectionManagerTraceMap (TrConnectionCleanup _) = +connectionManagerTraceMap (TrConnectionCleanup _) = "TrConnectionCleanup" -connectionManagerTraceMap (TrConnectionTimeWait _) = +connectionManagerTraceMap (TrConnectionTimeWait _) = "TrConnectionTimeWait" -connectionManagerTraceMap (TrConnectionTimeWaitDone _) = +connectionManagerTraceMap (TrConnectionTimeWaitDone _) = "TrConnectionTimeWaitDone" -connectionManagerTraceMap (TrConnectionManagerCounters _) = +connectionManagerTraceMap (TrConnectionManagerCounters _) = "TrConnectionManagerCounters" -connectionManagerTraceMap (TrState _) = +connectionManagerTraceMap (TrState _) = "TrState" -connectionManagerTraceMap (TrUnexpectedlyFalseAssertion _) = +connectionManagerTraceMap (TrUnexpectedlyFalseAssertion _) = "TrUnexpectedlyFalseAssertion" diff --git a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/KnownPeers.hs b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/KnownPeers.hs index a7eeefb08c7..7f8c54d70ca 100644 --- a/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/KnownPeers.hs +++ b/ouroboros-network/lib/Ouroboros/Network/PeerSelection/State/KnownPeers.hs @@ -79,8 +79,8 @@ data KnownPeers peeraddr = KnownPeers { -- establish a connection to now. This is because we have not connected -- with them before or because any failure backoff time has expired. -- - -- Note: Some peers may be behind a firewall. Local root peers marked as - -- behind a firewall are not excluded from this list. + -- Note: Some peers may be behind a firewall. Local root peers with + -- inbound provenance are not excluded from this list. -- availableToConnect :: !(Set peeraddr), From 0364702ff679e6d52b50fdb815d1850ba7035c89 Mon Sep 17 00:00:00 2001 From: edgr Date: Thu, 11 Dec 2025 17:21:57 +0800 Subject: [PATCH 24/24] Remove provenance from InboundConnectionNotFound --- .../Network/ConnectionManager/Core.hs | 6 +-- .../Network/ConnectionManager/Types.hs | 6 +-- .../Network/ConnectionManager/Utils.hs | 44 +++++++++---------- .../Ouroboros/Network/OrphanInstances.hs | 3 +- 4 files changed, 28 insertions(+), 31 deletions(-) diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs index 97761f03f09..9c3924ed120 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Core.hs @@ -1450,9 +1450,9 @@ with args@Arguments { -- Only proceed if creating a new connection is allowed if connProv == Inbound then do - return ( Just (Right (TrInboundConnectionNotFound connProv peerAddr)) + return ( Just (Right (TrInboundConnectionNotFound peerAddr)) , Left (withCallStack - (InboundConnectionNotFound connProv peerAddr)) + (InboundConnectionNotFound peerAddr)) ) else do let connState' = ReservedOutboundState @@ -2465,7 +2465,7 @@ withCallStack k = k callStack -- data Trace peerAddr handlerTrace = TrIncludeConnection Provenance peerAddr - | TrInboundConnectionNotFound Provenance peerAddr + | TrInboundConnectionNotFound peerAddr | TrReleaseConnection Provenance (ConnectionId peerAddr) | TrConnect (Maybe peerAddr) -- ^ local address peerAddr -- ^ remote address diff --git a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs index a8aac8abe3a..fb7f1c5ecd3 100644 --- a/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs +++ b/ouroboros-network/framework/lib/Ouroboros/Network/ConnectionManager/Types.hs @@ -730,7 +730,7 @@ data ConnectionManagerError peerAddr -- | No matching inbound connection found while establishing a new connection is -- not allowed. -- - | InboundConnectionNotFound !Provenance !peerAddr !CallStack + | InboundConnectionNotFound !peerAddr !CallStack -- | Connections that would be forbidden by the kernel (@TCP@ semantics). -- @@ -783,10 +783,8 @@ instance ( Show peerAddr , "\n" , prettyCallStack cs ] - displayException (InboundConnectionNotFound connMode peerAddr cs) = + displayException (InboundConnectionNotFound peerAddr cs) = concat [ "No matching inbound connection found and creating new connection is not allowed with peer " - , show connMode - , "\n" , show peerAddr , "\n" , prettyCallStack cs diff --git a/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs b/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs index 960e224c12b..07657951a80 100644 --- a/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs +++ b/ouroboros-network/framework/tests-lib/Test/Ouroboros/Network/ConnectionManager/Utils.hs @@ -300,45 +300,45 @@ connectionManagerTraceMap ntnAddr (ConnectionHandlerTrace ntnVersion ntnVersionData) -> String -connectionManagerTraceMap (TrInboundConnectionNotFound p _) = - "TrInboundConnectionNotFound " ++ show p -connectionManagerTraceMap (TrIncludeConnection p _) = +connectionManagerTraceMap (TrInboundConnectionNotFound _) = + "TrInboundConnectionNotFound" +connectionManagerTraceMap (TrIncludeConnection p _) = "TrIncludeConnection " ++ show p -connectionManagerTraceMap (TrReleaseConnection p _) = +connectionManagerTraceMap (TrReleaseConnection p _) = "TrUnregisterConnection " ++ show p -connectionManagerTraceMap TrConnect {} = +connectionManagerTraceMap TrConnect {} = "TrConnect" -connectionManagerTraceMap (TrConnectError _ _ _) = +connectionManagerTraceMap (TrConnectError _ _ _) = "TrConnectError" -connectionManagerTraceMap (TrTerminatingConnection p _) = +connectionManagerTraceMap (TrTerminatingConnection p _) = "TrTerminatingConnection " ++ show p -connectionManagerTraceMap (TrTerminatedConnection p _) = +connectionManagerTraceMap (TrTerminatedConnection p _) = "TrTerminatedConnection " ++ show p -connectionManagerTraceMap (TrConnectionHandler _ _) = +connectionManagerTraceMap (TrConnectionHandler _ _) = "TrConnectionHandler" -connectionManagerTraceMap TrShutdown = +connectionManagerTraceMap TrShutdown = "TrShutdown" -connectionManagerTraceMap (TrConnectionExists p _ as) = +connectionManagerTraceMap (TrConnectionExists p _ as) = "TrConnectionExists " ++ show p ++ " " ++ show as -connectionManagerTraceMap (TrForbiddenConnection _) = +connectionManagerTraceMap (TrForbiddenConnection _) = "TrForbiddenConnection" -connectionManagerTraceMap (TrConnectionFailure _) = +connectionManagerTraceMap (TrConnectionFailure _) = "TrConnectionFailure" -connectionManagerTraceMap (TrConnectionNotFound p _) = +connectionManagerTraceMap (TrConnectionNotFound p _) = "TrConnectionNotFound " ++ show p -connectionManagerTraceMap (TrForbiddenOperation _ as) = +connectionManagerTraceMap (TrForbiddenOperation _ as) = "TrForbiddenOperation" ++ show as -connectionManagerTraceMap (TrPruneConnections _ _ _) = +connectionManagerTraceMap (TrPruneConnections _ _ _) = "TrPruneConnections" -connectionManagerTraceMap (TrConnectionCleanup _) = +connectionManagerTraceMap (TrConnectionCleanup _) = "TrConnectionCleanup" -connectionManagerTraceMap (TrConnectionTimeWait _) = +connectionManagerTraceMap (TrConnectionTimeWait _) = "TrConnectionTimeWait" -connectionManagerTraceMap (TrConnectionTimeWaitDone _) = +connectionManagerTraceMap (TrConnectionTimeWaitDone _) = "TrConnectionTimeWaitDone" -connectionManagerTraceMap (TrConnectionManagerCounters _) = +connectionManagerTraceMap (TrConnectionManagerCounters _) = "TrConnectionManagerCounters" -connectionManagerTraceMap (TrState _) = +connectionManagerTraceMap (TrState _) = "TrState" -connectionManagerTraceMap (TrUnexpectedlyFalseAssertion _) = +connectionManagerTraceMap (TrUnexpectedlyFalseAssertion _) = "TrUnexpectedlyFalseAssertion" diff --git a/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs b/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs index cbbfebe4b58..bb7fa92bcbf 100644 --- a/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs +++ b/ouroboros-network/orphan-instances/Ouroboros/Network/OrphanInstances.hs @@ -1287,11 +1287,10 @@ instance (Show addr, Show versionNumber, Show agreedOptions, ToJSON addr, ToJSON versionNumber, ToJSON agreedOptions) => ToJSON (ConnMgr.Trace addr (ConnectionHandlerTrace versionNumber agreedOptions)) where toJSON = \case - TrInboundConnectionNotFound prov peerAddr -> + TrInboundConnectionNotFound peerAddr -> object [ "kind" .= String "InboundConnectionNotFound" , "remoteAddress" .= peerAddr - , "provenance" .= String (pack . show $ prov) ] TrIncludeConnection prov peerAddr -> object