Skip to content

Commit 405b005

Browse files
Add diffusion property test
1 parent a12338a commit 405b005

File tree

4 files changed

+102
-84
lines changed

4 files changed

+102
-84
lines changed

cardano-diffusion/changelog.d/20251108_103013_edgr_behind_firewall.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,6 @@ Uncomment the section that is right (remove the HTML comment wrapper).
55
For top level release notes, leave all the headers commented out.
66
-->
77

8-
### Breaking
9-
10-
- Modified `establishPeerConnection` in `Test.Cardano.Network.PeerSelection.MockEnvironment`:
11-
- Now only creates a new connection if no inbound connection is found and `ConnectionMode` allows it.
12-
- Added tracing for newly created connections.
13-
148
### Non-Breaking
159

16-
- Added a new tracer: `TraceEnvNewConnCreated`.
1710
- Added a property test to verify that the node never connects to peers behind a firewall.

cardano-diffusion/tests/lib/Test/Cardano/Network/Diffusion/Testnet.hs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ tests =
132132
prop_diffusion_target_active_public_iosimpor
133133
, nightlyTest $ testProperty "target established local"
134134
prop_diffusion_target_established_local_iosimpor
135+
, nightlyTest $ testProperty "never connect to peers behind a firewall"
136+
prop_diffusion_never_connect_peer_behind_firewall_iosimpor
135137
, nightlyTest $ testProperty "target active local"
136138
prop_diffusion_target_active_local_iosimpor
137139
, nightlyTest $ testProperty "target active root"
@@ -192,6 +194,8 @@ tests =
192194
prop_diffusion_target_active_public_iosim
193195
, testProperty "target established local"
194196
prop_diffusion_target_established_local_iosim
197+
, testProperty "never connect to peers behind a firewall"
198+
prop_diffusion_never_connect_peer_behind_firewall_iosim
195199
, testProperty "unit reconnect"
196200
prop_unit_reconnect
197201
, testProperty "target active local"
@@ -2847,6 +2851,96 @@ prop_diffusion_target_established_local_iosim
28472851
prop_diffusion_target_established_local_iosim
28482852
= testWithIOSim prop_diffusion_target_established_local long_trace
28492853

2854+
-- | Avoid connecting to root peers marked as behind a firewall and without
2855+
-- inbound connection.
2856+
--
2857+
prop_diffusion_never_connect_peer_behind_firewall
2858+
:: SimTrace Void
2859+
-> Int
2860+
-> Property
2861+
prop_diffusion_never_connect_peer_behind_firewall ioSimTrace traceNumber =
2862+
let events :: [Events DiffusionTestTrace]
2863+
events = Trace.toList
2864+
. fmap ( Signal.eventsFromList
2865+
. fmap (\(WithName _ (WithTime t b)) -> (t, b))
2866+
)
2867+
. splitWithNameTrace
2868+
. fmap (\(WithTime t (WithName name b)) ->
2869+
WithName name (WithTime t b))
2870+
. withTimeNameTraceEvents
2871+
@DiffusionTestTrace
2872+
@NtNAddr
2873+
. Trace.take traceNumber
2874+
$ ioSimTrace
2875+
2876+
in conjoin
2877+
$ (\ev ->
2878+
let evsList = eventsToList ev
2879+
lastTime = fst
2880+
. last
2881+
$ evsList
2882+
in classifySimulatedTime lastTime
2883+
$ classifyNumberOfEvents (length evsList)
2884+
$ verify_target_established_local ev
2885+
)
2886+
<$> events
2887+
2888+
where
2889+
verify_target_established_local :: Events DiffusionTestTrace
2890+
-> Property
2891+
verify_target_established_local events =
2892+
let govLocalRootPeersSig
2893+
:: Signal (LocalRootPeers.LocalRootPeers PeerTrustable NtNAddr)
2894+
govLocalRootPeersSig =
2895+
selectDiffusionPeerSelectionState Governor.localRootPeers events
2896+
2897+
govUnreachablePeersSig :: Signal (Set NtNAddr)
2898+
govUnreachablePeersSig =
2899+
(\local ->
2900+
let
2901+
isUnreachablePeer (LocalRootConfig {localRootBehindFirewall}) =
2902+
localRootBehindFirewall
2903+
unreachablePeers =
2904+
Map.keysSet
2905+
$ Map.filter isUnreachablePeer
2906+
$ LocalRootPeers.toMap local
2907+
in
2908+
unreachablePeers
2909+
) <$> govLocalRootPeersSig
2910+
2911+
govInboundConnectionsSig :: Signal (Set NtNAddr)
2912+
govInboundConnectionsSig =
2913+
Signal.keyedLinger
2914+
180 -- 3 minutes
2915+
(Just . fromMaybe Set.empty)
2916+
. Signal.fromEvents
2917+
. Signal.selectEvents
2918+
(\case
2919+
DiffusionConnectionManagerTrace
2920+
-- initiated by remote
2921+
(CM.TrConnectionNotFound Inbound peer) ->
2922+
Just (Set.singleton peer)
2923+
_other -> Nothing
2924+
)
2925+
$ events
2926+
2927+
in counterexample
2928+
("\nSignal key: (local root peers, unreachables, inbounds") $
2929+
signalProperty 100 show
2930+
(\(_,unreachables,inbounds) -> unreachables `Set.disjoint` inbounds)
2931+
((,,) <$> govLocalRootPeersSig
2932+
<*> govUnreachablePeersSig
2933+
<*> govInboundConnectionsSig)
2934+
2935+
prop_diffusion_never_connect_peer_behind_firewall_iosimpor
2936+
:: AbsBearerInfo -> DiffusionScript -> Property
2937+
prop_diffusion_never_connect_peer_behind_firewall_iosimpor
2938+
= testWithIOSimPOR prop_diffusion_never_connect_peer_behind_firewall short_trace
2939+
2940+
prop_diffusion_never_connect_peer_behind_firewall_iosim
2941+
:: AbsBearerInfo -> DiffusionScript -> Property
2942+
prop_diffusion_never_connect_peer_behind_firewall_iosim
2943+
= testWithIOSim prop_diffusion_never_connect_peer_behind_firewall long_trace
28502944

28512945
-- | A variant of
28522946
-- 'Test.Ouroboros.Network.PeerSelection.prop_governor_target_active_below'

cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection.hs

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,6 @@ tests =
154154
prop_governor_target_active_local_below
155155
, testProperty "progresses towards active target (from above)"
156156
prop_governor_target_active_local_above
157-
, testProperty "never connect to peers behind a firewall"
158-
prop_governor_never_connect_peer_behind_firewall
159157
]
160158

161159
, testGroup "big ledger peers"
@@ -801,7 +799,6 @@ envEventCredits (TraceEnvSetLocalRoots peers) = LocalRootPeers.size peers
801799
envEventCredits (TraceEnvSetPublicRoots peers) = PublicRootPeers.size Cardano.ExtraPeers.size peers
802800
envEventCredits TraceEnvRequestPublicRootPeers = 0
803801
envEventCredits TraceEnvRequestBigLedgerPeers = 0
804-
envEventCredits (TraceEnvNewConnCreated _) = 0
805802
envEventCredits TraceEnvPublicRootTTL = 60
806803
envEventCredits TraceEnvBigLedgerPeersTTL = 60
807804

@@ -3209,57 +3206,6 @@ prop_governor_target_established_above (MaxTime maxTime) env =
32093206
<*> govInProgressIneligibleSig
32103207
<*> demotionOpportunitiesIgnoredTooLong)
32113208

3212-
-- | Avoid connecting to root peers marked as behind a firewall and without inbound connection.
3213-
prop_governor_never_connect_peer_behind_firewall :: MaxTime -> GovernorMockEnvironment -> Property
3214-
prop_governor_never_connect_peer_behind_firewall (MaxTime maxTime) env =
3215-
let events = Signal.eventsFromListUpToTime maxTime
3216-
. selectPeerSelectionTraceEvents
3217-
@Cardano.ExtraState
3218-
@PeerTrustable
3219-
@(Cardano.ExtraPeers PeerAddr)
3220-
@(Cardano.ExtraPeerSelectionSetsWithSizes PeerAddr)
3221-
@Cardano.ExtraTrace
3222-
. runGovernorInMockEnvironment
3223-
$ env
3224-
3225-
govLocalRootPeersSig :: Signal (LocalRootPeers PeerTrustable PeerAddr)
3226-
govLocalRootPeersSig =
3227-
selectGovState Governor.localRootPeers
3228-
(Cardano.ExtraState.empty (consensusMode env) (NumberOfBigLedgerPeers 0)) Cardano.ExtraPeers.empty
3229-
events
3230-
3231-
govUnreachablePeersSig :: Signal (Set PeerAddr)
3232-
govUnreachablePeersSig =
3233-
(\local ->
3234-
let
3235-
isUnreachablePeer (LocalRootConfig {localRootBehindFirewall}) = localRootBehindFirewall
3236-
3237-
unreachablePeers =
3238-
Map.keysSet
3239-
$ Map.filter isUnreachablePeer
3240-
$ LocalRootPeers.toMap local
3241-
in
3242-
unreachablePeers
3243-
) <$> govLocalRootPeersSig
3244-
3245-
newConnectionSig :: Signal (Maybe PeerAddr)
3246-
newConnectionSig =
3247-
Signal.fromEvents
3248-
. Signal.selectEvents
3249-
(\case TraceEnvNewConnCreated addr -> Just $! addr
3250-
_other -> Nothing)
3251-
. selectEnvEvents
3252-
$ events
3253-
3254-
in counterexample
3255-
"\nSignal key: (local root peers, unreachable local root peers, new connection)" $
3256-
3257-
signalProperty 100 show
3258-
(\(_,unreachablePeers,newConnection) -> maybe True (not . flip Set.member unreachablePeers) newConnection)
3259-
((,,) <$> govLocalRootPeersSig
3260-
<*> govUnreachablePeersSig
3261-
<*> newConnectionSig)
3262-
32633209
-- | Like 'prop_governor_target_established_above' but for big ledger peers.
32643210
--
32653211
prop_governor_target_established_big_ledger_peers_above
@@ -3613,7 +3559,7 @@ prop_governor_target_established_local (MaxTime maxTime) env =
36133559
promotionOpportunitiesIgnoredTooLong :: Signal (Set PeerAddr)
36143560
promotionOpportunitiesIgnoredTooLong =
36153561
Signal.keyedTimeout
3616-
2 -- seconds -- cabal run cardano-diffusion:cardano-diffusion-sim-tests -- --quickcheck-replay="(SMGen 13722084053961804625 14989040016076027617,42)" -p '/local root peers/&&/progresses towards established target/'
3562+
1 -- seconds
36173563
id
36183564
promotionOpportunities
36193565

cardano-diffusion/tests/lib/Test/Cardano/Network/PeerSelection/MockEnvironment.hs

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ import Data.IP (toIPv4w)
4848

4949
import Control.Concurrent.Class.MonadSTM
5050
import Control.Concurrent.Class.MonadSTM.Strict qualified as StrictTVar
51-
import Control.Exception (throw, ErrorCall (..))
51+
import Control.Exception (throw)
5252
import Control.Monad (forM, when)
5353
import Control.Monad.Class.MonadAsync
5454
import Control.Monad.Class.MonadFork
@@ -331,7 +331,6 @@ data TraceMockEnv = TraceEnvAddPeers !PeerGraph
331331
| TraceEnvSetTargets !PeerSelectionTargets
332332
| TraceEnvPeersDemote !AsyncDemotion !PeerAddr
333333
| TraceEnvEstablishConn !PeerAddr
334-
| TraceEnvNewConnCreated !PeerAddr
335334
| TraceEnvActivatePeer !PeerAddr
336335
| TraceEnvDeactivatePeer !PeerAddr
337336
| TraceEnvCloseConn !PeerAddr
@@ -551,34 +550,20 @@ mockPeerSelectionActions' tracer
551550
threadDelay (interpretPeerShareTime time)
552551
traceWith tracer (TraceEnvPeerShareResult addr peeraddrs)
553552
return (PeerSharingResult peeraddrs)
553+
554554
establishPeerConnection :: IsBigLedgerPeer -> DiffusionMode -> PeerAddr -> ConnectionMode -> m (PeerConn m)
555-
establishPeerConnection _ _ peeraddr connMode = do
555+
establishPeerConnection _ _ peeraddr _ = do
556556
--TODO: add support for variable delays and synchronous failure
557557
traceWith tracer (TraceEnvEstablishConn peeraddr)
558558
threadDelay 1
559559
let Just (_, peerSharingScript, connectScript) = Map.lookup peeraddr scripts
560-
(conn@(PeerConn _ _ v), newConnCreated) <- atomically $ do
560+
conn@(PeerConn _ _ v) <- atomically $ do
561+
conn <- newTVar PeerWarm
561562
conns <- readTVar connsVar
562-
(conn, conns', newConnCreated) <- maybe
563-
( case connMode of
564-
CreateNewIfNoInbound -> do
565-
conn <- newTVar PeerWarm
566-
pure (conn, conns, True)
567-
RequireInbound -> do
568-
throwSTM (ErrorCall "No inbound connection found.")
569-
)
570-
(\conn -> do
571-
pure (conn, Map.insert peeraddr conn conns, False)
572-
)
573-
(Map.lookup peeraddr conns)
574-
563+
let !conns' = Map.insert peeraddr conn conns
575564
writeTVar connsVar conns'
576565
remotePeerSharing <- stepScriptSTM peerSharingScript
577-
return (PeerConn peeraddr (peerSharingFlag <> remotePeerSharing) conn, newConnCreated)
578-
579-
when newConnCreated $
580-
traceWith tracer (TraceEnvNewConnCreated peeraddr)
581-
566+
return (PeerConn peeraddr (peerSharingFlag <> remotePeerSharing) conn)
582567
_ <- async $
583568
-- monitoring loop which does asynchronous demotions. It will terminate
584569
-- as soon as either of the events:

0 commit comments

Comments
 (0)