From 9718a9c94f12197e074bfd0f6d45e610b08b16d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20W=C3=B3jtowicz?= Date: Sun, 8 Dec 2024 13:21:13 +0100 Subject: [PATCH] Tests wip --- .../Test/Ouroboros/Network/LedgerPeers.hs | 16 +- .../Test/Ouroboros/Network/PeerSelection.hs | 206 ++++---- .../Network/PeerSelection/Instances.hs | 46 +- .../Ouroboros/Network/PeerSelection/Json.hs | 17 +- .../Network/PeerSelection/RootPeersDNS.hs | 437 +++++++++------- .../Test/Ouroboros/Network/Testnet.hs | 212 ++++---- .../Ouroboros/Network/Testnet/Internal.hs | 474 ++++++++++-------- .../Test/Ouroboros/Network/Testnet/Node.hs | 9 +- 8 files changed, 775 insertions(+), 642 deletions(-) diff --git a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/LedgerPeers.hs b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/LedgerPeers.hs index b82de8d36f8..db9fc5a1b22 100644 --- a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/LedgerPeers.hs +++ b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/LedgerPeers.hs @@ -8,6 +8,7 @@ module Test.Ouroboros.Network.LedgerPeers where +import Ouroboros.Network.PeerSelection.RootPeersDNS.DNSActions import Codec.CBOR.FlatTerm import Control.Concurrent.Class.MonadSTM.Strict import Control.Exception (SomeException (..)) @@ -79,6 +80,7 @@ instance Arbitrary ArbitraryRelayAccessPoint where ArbitraryRelayAccessPoint <$> oneof [ RelayAccessAddress (read "1.1.1.1") . getArbitraryPortNumber <$> arbitrary , RelayAccessDomain "relay.iohk.example" . getArbitraryPortNumber <$> arbitrary + , pure $ RelayAccessSRVDomain "_cardano._tcp.iohk.example" ] newtype ArbitraryLedgerStateJudgement = @@ -287,7 +289,12 @@ prop_pick100 seed (NonNegative n) (ArbLedgerPeersKind ledgerPeersKind) (MockRoot withLedgerPeers PeerActionsDNS { paToPeerAddr = curry IP.toSockAddr, - paDnsActions = (mockDNSActions @SomeException dnsMapVar dnsTimeoutScriptVar dnsLookupDelayScriptVar), + paDnsActions = mockDNSActions + @SomeException + LookupReqAOnly + dnsMapVar + dnsTimeoutScriptVar + dnsLookupDelayScriptVar, paDnsSemaphore = dnsSemaphore } WithLedgerPeersArgs { wlpRng = rng, wlpConsensusInterface = interface, @@ -348,7 +355,12 @@ prop_pick (LedgerPools lps) (ArbLedgerPeersKind ledgerPeersKind) count seed (Moc withLedgerPeers PeerActionsDNS { paToPeerAddr = curry IP.toSockAddr, - paDnsActions = mockDNSActions @SomeException dnsMapVar dnsTimeoutScriptVar dnsLookupDelayScriptVar, + paDnsActions = mockDNSActions + @SomeException + LookupReqAOnly + dnsMapVar + dnsTimeoutScriptVar + dnsLookupDelayScriptVar, paDnsSemaphore = dnsSemaphore } WithLedgerPeersArgs { wlpRng = rng, wlpConsensusInterface = interface, diff --git a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection.hs b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection.hs index 72727798661..cdcbb5fc182 100644 --- a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection.hs +++ b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection.hs @@ -3760,109 +3760,109 @@ selectEnvTargets f = -- This is a manual test that runs in IO and has to be observed to see that it -- is doing something sensible. It is not run automatically. -- -_governorFindingPublicRoots :: Int - -> STM IO (Map RelayAccessPoint PeerAdvertise) - -> STM IO UseBootstrapPeers - -> STM IO LedgerStateJudgement - -> PeerSharing - -> StrictTVar IO OutboundConnectionsState - -> ConsensusMode - -> IO Void -_governorFindingPublicRoots targetNumberOfRootPeers readDomains readUseBootstrapPeers readLedgerStateJudgement peerSharing olocVar consensusMode = do - countersVar <- newTVarIO emptyPeerSelectionCounters - publicStateVar <- makePublicPeerSelectionStateVar - debugStateVar <- newTVarIO $ emptyPeerSelectionState (mkStdGen 42) consensusMode (MinBigLedgerPeersForTrustedState 0) - dnsSemaphore <- newLedgerAndPublicRootDNSSemaphore - let interfaces = PeerSelectionInterfaces { - countersVar, - publicStateVar, - debugStateVar, - readUseLedgerPeers = return DontUseLedgerPeers - } - - publicRootPeersProvider - tracer - (curry IP.toSockAddr) - dnsSemaphore - DNS.defaultResolvConf - readDomains - (ioDNSActions LookupReqAAndAAAA) $ \requestPublicRootPeers -> do - peerSelectionGovernor - tracer tracer tracer - -- TODO: #3182 Rng seed should come from quickcheck. - (mkStdGen 42) - consensusMode - (MinBigLedgerPeersForTrustedState 0) - actions - { requestPublicRootPeers = \_ -> - transformPeerSelectionAction requestPublicRootPeers } - policy - interfaces - where - tracer :: Show a => Tracer IO a - tracer = Tracer (BS.putStrLn . BS.pack . show) - - actions :: PeerSelectionActions SockAddr PeerSharing IO - actions = PeerSelectionActions { - peerTargets, - readLocalRootPeers = return [], - peerSharing = peerSharing, - readPeerSelectionTargets = return targets, - requestPeerShare = \_ _ -> return (PeerSharingResult []), - peerConnToPeerSharing = id, - requestPublicRootPeers = \_ _ -> return (PublicRootPeers.empty, 0), - peerStateActions = PeerStateActions { - establishPeerConnection = error "establishPeerConnection", - monitorPeerConnection = error "monitorPeerConnection", - activatePeerConnection = error "activatePeerConnection", - deactivatePeerConnection = error "deactivatePeerConnection", - closePeerConnection = error "closePeerConnection" - }, - readUseBootstrapPeers, - readInboundPeers = pure Map.empty, - updateOutboundConnectionsState = \a -> do - a' <- readTVar olocVar - when (a /= a') $ - writeTVar olocVar a, - getLedgerStateCtx = - LedgerPeersConsensusInterface { - lpGetLatestSlot = pure Origin, - lpGetLedgerStateJudgement = readLedgerStateJudgement, - lpGetLedgerPeers = pure [] }, - readLedgerPeerSnapshot = pure Nothing - } - - targets :: PeerSelectionTargets - targets = nullPeerSelectionTargets { - targetNumberOfRootPeers = targetNumberOfRootPeers, - targetNumberOfKnownPeers = targetNumberOfRootPeers - } - - peerTargets = ConsensusModePeerTargets { - deadlineTargets = targets, - syncTargets = targets} - - policy :: PeerSelectionPolicy SockAddr IO - policy = PeerSelectionPolicy { - policyPickKnownPeersForPeerShare = \_ _ _ -> pickTrivially, - policyPickColdPeersToForget = \_ _ _ -> pickTrivially, - policyPickColdPeersToPromote = \_ _ _ -> pickTrivially, - policyPickWarmPeersToPromote = \_ _ _ -> pickTrivially, - policyPickHotPeersToDemote = \_ _ _ -> pickTrivially, - policyPickWarmPeersToDemote = \_ _ _ -> pickTrivially, - policyPickInboundPeers = \_ _ _ -> pickTrivially, - policyFindPublicRootTimeout = 5, - policyMaxInProgressPeerShareReqs = 0, - policyPeerShareRetryTime = 0, -- seconds - policyPeerShareBatchWaitTime = 0, -- seconds - policyPeerShareOverallTimeout = 0, -- seconds - policyPeerShareActivationDelay = 2, -- seconds - policyErrorDelay = 0 -- seconds - } - pickTrivially :: Applicative m => Set SockAddr -> Int -> m (Set SockAddr) - pickTrivially m n = pure . Set.take n $ m - - transformPeerSelectionAction = fmap (fmap (\(a, b) -> (PublicRootPeers.fromMapAndSet a Set.empty Set.empty Set.empty, b))) +-- _governorFindingPublicRoots :: Int +-- -> STM IO (Map RelayAccessPoint PeerAdvertise) +-- -> STM IO UseBootstrapPeers +-- -> STM IO LedgerStateJudgement +-- -> PeerSharing +-- -> StrictTVar IO OutboundConnectionsState +-- -> ConsensusMode +-- -> IO Void +-- _governorFindingPublicRoots targetNumberOfRootPeers readDomains readUseBootstrapPeers readLedgerStateJudgement peerSharing olocVar consensusMode = do +-- countersVar <- newTVarIO emptyPeerSelectionCounters +-- publicStateVar <- makePublicPeerSelectionStateVar +-- debugStateVar <- newTVarIO $ emptyPeerSelectionState (mkStdGen 42) consensusMode (MinBigLedgerPeersForTrustedState 0) +-- dnsSemaphore <- newLedgerAndPublicRootDNSSemaphore +-- let interfaces = PeerSelectionInterfaces { +-- countersVar, +-- publicStateVar, +-- debugStateVar, +-- readUseLedgerPeers = return DontUseLedgerPeers +-- } + +-- publicRootPeersProvider +-- tracer +-- (curry IP.toSockAddr) +-- dnsSemaphore +-- DNS.defaultResolvConf +-- readDomains +-- (ioDNSActions LookupReqAAndAAAA) $ \requestPublicRootPeers -> do +-- peerSelectionGovernor +-- tracer tracer tracer +-- -- TODO: #3182 Rng seed should come from quickcheck. +-- (mkStdGen 42) +-- consensusMode +-- (MinBigLedgerPeersForTrustedState 0) +-- actions +-- { requestPublicRootPeers = \_ -> +-- transformPeerSelectionAction requestPublicRootPeers } +-- policy +-- interfaces +-- where +-- tracer :: Show a => Tracer IO a +-- tracer = Tracer (BS.putStrLn . BS.pack . show) + +-- actions :: PeerSelectionActions SockAddr PeerSharing IO +-- actions = PeerSelectionActions { +-- peerTargets, +-- readLocalRootPeers = return [], +-- peerSharing = peerSharing, +-- readPeerSelectionTargets = return targets, +-- requestPeerShare = \_ _ -> return (PeerSharingResult []), +-- peerConnToPeerSharing = id, +-- requestPublicRootPeers = \_ _ -> return (PublicRootPeers.empty, 0), +-- peerStateActions = PeerStateActions { +-- establishPeerConnection = error "establishPeerConnection", +-- monitorPeerConnection = error "monitorPeerConnection", +-- activatePeerConnection = error "activatePeerConnection", +-- deactivatePeerConnection = error "deactivatePeerConnection", +-- closePeerConnection = error "closePeerConnection" +-- }, +-- readUseBootstrapPeers, +-- readInboundPeers = pure Map.empty, +-- updateOutboundConnectionsState = \a -> do +-- a' <- readTVar olocVar +-- when (a /= a') $ +-- writeTVar olocVar a, +-- getLedgerStateCtx = +-- LedgerPeersConsensusInterface { +-- lpGetLatestSlot = pure Origin, +-- lpGetLedgerStateJudgement = readLedgerStateJudgement, +-- lpGetLedgerPeers = pure [] }, +-- readLedgerPeerSnapshot = pure Nothing +-- } + +-- targets :: PeerSelectionTargets +-- targets = nullPeerSelectionTargets { +-- targetNumberOfRootPeers = targetNumberOfRootPeers, +-- targetNumberOfKnownPeers = targetNumberOfRootPeers +-- } + +-- peerTargets = ConsensusModePeerTargets { +-- deadlineTargets = targets, +-- syncTargets = targets} + +-- policy :: PeerSelectionPolicy SockAddr IO +-- policy = PeerSelectionPolicy { +-- policyPickKnownPeersForPeerShare = \_ _ _ -> pickTrivially, +-- policyPickColdPeersToForget = \_ _ _ -> pickTrivially, +-- policyPickColdPeersToPromote = \_ _ _ -> pickTrivially, +-- policyPickWarmPeersToPromote = \_ _ _ -> pickTrivially, +-- policyPickHotPeersToDemote = \_ _ _ -> pickTrivially, +-- policyPickWarmPeersToDemote = \_ _ _ -> pickTrivially, +-- policyPickInboundPeers = \_ _ _ -> pickTrivially, +-- policyFindPublicRootTimeout = 5, +-- policyMaxInProgressPeerShareReqs = 0, +-- policyPeerShareRetryTime = 0, -- seconds +-- policyPeerShareBatchWaitTime = 0, -- seconds +-- policyPeerShareOverallTimeout = 0, -- seconds +-- policyPeerShareActivationDelay = 2, -- seconds +-- policyErrorDelay = 0 -- seconds +-- } +-- pickTrivially :: Applicative m => Set SockAddr -> Int -> m (Set SockAddr) +-- pickTrivially m n = pure . Set.take n $ m + +-- transformPeerSelectionAction = fmap (fmap (\(a, b) -> (PublicRootPeers.fromMapAndSet a Set.empty Set.empty Set.empty, b))) prop_issue_3550 :: Property prop_issue_3550 = prop_governor_target_established_below defaultMaxTime $ diff --git a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection/Instances.hs b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection/Instances.hs index 8216fb56f28..38cb6b51a98 100644 --- a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection/Instances.hs +++ b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection/Instances.hs @@ -12,11 +12,14 @@ module Test.Ouroboros.Network.PeerSelection.Instances -- generators , genIPv4 , genIPv6 + , genPort -- generator tests , prop_arbitrary_PeerSelectionTargets , prop_shrink_PeerSelectionTargets ) where +import Network.DNS qualified as DNS +import Ouroboros.Network.PeerSelection.RelayAccessPoint import Data.Text.Encoding (encodeUtf8) import Data.Word (Word32, Word64) @@ -26,6 +29,7 @@ import Ouroboros.Network.PeerSelection.Governor import Data.Hashable import Data.IP qualified as IP +import Network.Socket import Ouroboros.Network.ConsensusMode import Ouroboros.Network.PeerSelection.Bootstrap (UseBootstrapPeers (..)) import Ouroboros.Network.PeerSelection.LedgerPeers.Type (AfterSlot (..), @@ -144,22 +148,28 @@ instance Arbitrary ConsensusModePeerTargets where syncTargets'' <- syncTargets'] instance Arbitrary DomainAccessPoint where - arbitrary = - DomainAccessPoint . encodeUtf8 - <$> elements domains - <*> (fromIntegral <$> (arbitrary :: Gen Int)) + arbitrary = oneof [plain, srv] where - domains = [ "test1" - , "test2" - , "test3" - , "test4" - , "test5" - ] + plain = DomainAccessPoint <$> (DomainPlain + <$> elements domains + <*> genPort) + srv = DomainSRVAccessPoint <$> (DomainSRV <$> elements domains) + domains = encodeUtf8 <$> + [ "test1" + , "test2" + , "test3" + , "test4" + , "test5" + ] genIPv4 :: Gen IP.IP genIPv4 = IP.IPv4 . IP.toIPv4w <$> resize 200 arbitrary `suchThat` (> 100) +genPort :: Gen PortNumber +genPort = + fromIntegral <$> (arbitrary :: Gen Int) + genIPv6 :: Gen IP.IP genIPv6 = IP.IPv6 . IP.toIPv6w <$> genFourWord32 @@ -173,11 +183,16 @@ genIPv6 = instance Arbitrary RelayAccessPoint where arbitrary = - oneof [ RelayDomainAccessPoint <$> arbitrary - , RelayAccessAddress <$> oneof [genIPv4, genIPv6] - <*> (fromIntegral - <$> (arbitrary :: Gen Int)) - ] + frequency [ (4, RelayAccessAddress <$> oneof [genIPv4, genIPv6] <*> genPort) + , (4, RelayAccessDomain <$> elements domains <*> genPort) + , (1, RelayAccessSRVDomain <$> elements domains)] + where + domains = encodeUtf8 <$> [ "test1" + , "test2" + , "test3" + , "test4" + , "test5" + ] prop_arbitrary_PeerSelectionTargets :: PeerSelectionTargets -> Bool prop_arbitrary_PeerSelectionTargets = @@ -187,4 +202,3 @@ prop_shrink_PeerSelectionTargets :: ShrinkCarefully PeerSelectionTargets -> Prop prop_shrink_PeerSelectionTargets x = prop_shrink_valid sanePeerSelectionTargets x .&&. prop_shrink_nonequal x - diff --git a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection/Json.hs b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection/Json.hs index 84b4aca408a..39b70e28b0d 100644 --- a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection/Json.hs +++ b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection/Json.hs @@ -21,20 +21,19 @@ tests = ] prop_roundtrip_DomainAccessPoint_JSON :: DomainAccessPoint -> Property -prop_roundtrip_DomainAccessPoint_JSON da = - decode (encode da) === Just da - .&&. - fromJSON (toJSON da) === pure da +prop_roundtrip_DomainAccessPoint_JSON da = undefined + -- decode (encode da) === Just da + -- .&&. + -- fromJSON (toJSON da) === pure da prop_roundtrip_RelayAccessPoint_JSON :: RelayAccessPoint -> Property -prop_roundtrip_RelayAccessPoint_JSON ra = - decode (encode ra) === Just ra - .&&. - fromJSON (toJSON ra) === pure ra +prop_roundtrip_RelayAccessPoint_JSON ra = undefined + -- decode (encode ra) === Just ra + -- .&&. + -- fromJSON (toJSON ra) === pure ra prop_roundtrip_PeerAdvertise_JSON :: PeerAdvertise -> Property prop_roundtrip_PeerAdvertise_JSON pa = decode (encode pa) === Just pa .&&. fromJSON (toJSON pa) === pure pa - diff --git a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection/RootPeersDNS.hs b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection/RootPeersDNS.hs index d12bb2001f0..648632b4a86 100644 --- a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection/RootPeersDNS.hs +++ b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/PeerSelection/RootPeersDNS.hs @@ -1,3 +1,7 @@ +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE BlockArguments #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NamedFieldPuns #-} @@ -16,11 +20,15 @@ module Test.Ouroboros.Network.PeerSelection.RootPeersDNS ( tests , mockDNSActions , MockRoots (..) + , MockDNSMap + , MockDNSLookupResult , DNSTimeout (..) , DNSLookupDelay (..) , DelayAndTimeoutScripts (..) ) where +import Data.Bifunctor (bimap, second) +import Data.Text.Encoding (encodeUtf8) import Control.Applicative (Alternative) import Control.Monad (forever, replicateM_) import Data.ByteString.Char8 (pack) @@ -38,7 +46,9 @@ import Data.Set (Set) import Data.Set qualified as Set import Data.Time.Clock (picosecondsToDiffTime) import Data.Void (Void) -import Network.DNS (DNSError (NameError, TimeoutExpired), Domain, TTL) +import Data.Word (Word16) +import Network.DNS (DNSError (NameError, TimeoutExpired), answer, DNSMessage, ResourceRecord (..), defaultResponse, TTL) +import Network.DNS qualified as DNS import Network.DNS.Resolver qualified as DNSResolver import Network.Socket (SockAddr (..)) @@ -60,6 +70,7 @@ import Data.List.NonEmpty (NonEmpty (..)) import Ouroboros.Network.PeerSelection.LedgerPeers import Ouroboros.Network.PeerSelection.PeerAdvertise (PeerAdvertise (..)) import Ouroboros.Network.PeerSelection.PeerTrustable (PeerTrustable (..)) +import Ouroboros.Network.PeerSelection.RelayAccessPoint import Ouroboros.Network.PeerSelection.RootPeersDNS.DNSActions import Ouroboros.Network.PeerSelection.RootPeersDNS.DNSSemaphore import Ouroboros.Network.PeerSelection.RootPeersDNS.LocalRootPeers @@ -68,10 +79,11 @@ import Ouroboros.Network.PeerSelection.State.LocalRootPeers (HotValency (..), WarmValency (..)) import Ouroboros.Network.Testing.Data.Script (Script (Script), initScript', scriptHead, singletonScript, stepScript') -import Test.Ouroboros.Network.PeerSelection.Instances () +import Test.Ouroboros.Network.PeerSelection.Instances (genPort) import Test.QuickCheck import Test.Tasty (TestTree, testGroup) import Test.Tasty.QuickCheck (testProperty) +import Ouroboros.Network.PeerSelection.RootPeersDNS.DNSActions (dispatchLookupWithTTL) tests :: TestTree tests = @@ -101,13 +113,20 @@ tests = -- Mock Environment and Utils -- +type MockDNSLookupResult = Either [(IP, TTL)] + [( DNS.Domain + , Word16 -- ^ priority + , Word16 -- ^ weight + , PortNumber)] +type MockDNSMap = (Map (DNS.Domain, DNS.TYPE) MockDNSLookupResult) + data MockRoots = MockRoots { mockLocalRootPeers :: [( HotValency , WarmValency , Map RelayAccessPoint (PeerAdvertise, PeerTrustable))] - , mockLocalRootPeersDNSMap :: Script (Map Domain [(IP, TTL)]) + , mockLocalRootPeersDNSMap :: Script (Map (DNS.Domain, DNS.TYPE) MockDNSLookupResult) , mockPublicRootPeers :: Map RelayAccessPoint PeerAdvertise - , mockPublicRootPeersDNSMap :: Script (Map Domain [(IP, TTL)]) + , mockPublicRootPeersDNSMap :: Script (Map (DNS.Domain, DNS.TYPE) MockDNSLookupResult) } deriving Show @@ -119,41 +138,39 @@ genMockRoots = sized $ \relaysNumber -> do -- relaysPerGroup <- chooseEnum (1, relaysNumber `div` 3) - localRootRelays <- vectorOf relaysNumber arbitrary + -- concat unique identifier to DNS domains to simplify tests + taggedLocalRelays <- tagRelays <$> vectorOf relaysNumber arbitrary targets <- vectorOf relaysNumber genTargets - peerAdvertise <- blocks relaysPerGroup <$> vectorOf relaysNumber arbitrary - -- concat unique identifier to DNS domains to simplify tests - let taggedLocalRelays = tagRelays localRootRelays + let ipsPerDomain = 2 + genLookup relays = do + let (_relayAddress, relayDomains, relaySRVs) = + foldl' threeWay ([], [], []) relays + lookupIP <- genDomainIPLookupTable ipsPerDomain (dapDomain <$> relayDomains) + relayDomains' <- shuffle relayDomains -- ^ not strictly necessary + (srvs, _leftover) <- dealDomains [] relayDomains' relaySRVs + let srvs' = bimap srvDomain (fmap dapDomain) <$> srvs + lookupSRV <- Map.fromList . fmap (bimap (,DNS.SRV) Right) + <$> groupSrvs [] srvs' + return $ Map.union lookupIP lookupSRV + localRelaysBlocks = blocks relaysPerGroup taggedLocalRelays localRelaysMap = map Map.fromList $ zipWith zip localRelaysBlocks peerAdvertise localRootPeers = zipWith (\(h, w) g -> (h, w, g)) targets localRelaysMap - localRootDomains = [ domain - | RelayAccessDomain domain _ <- taggedLocalRelays ] - - ipsPerDomain = 2 lrpDNSMap <- Script . NonEmpty.fromList - <$> listOf1 (genDomainLookupTable ipsPerDomain localRootDomains) + <$> listOf1 (genLookup taggedLocalRelays) -- Generate PublicRootPeers -- - publicRootRelays <- vectorOf relaysNumber arbitrary - publicRootPeersAdvertise <- vectorOf relaysNumber arbitrary - - let publicRootPeers = - Map.fromList (zip (tagRelays publicRootRelays) - publicRootPeersAdvertise) + publicRootRelays <- tagRelays <$> vectorOf relaysNumber arbitrary + let publicRootAdvertise = vectorOf relaysNumber arbitrary - publicRootDomains = [ domain - | (RelayAccessDomain domain _, _) - <- Map.assocs publicRootPeers ] - - publicRootPeersDNSMap <- Script . NonEmpty.fromList - <$> listOf1 (genDomainLookupTable ipsPerDomain publicRootDomains) + publicRootPeers <- Map.fromList . zip publicRootRelays <$> publicRootAdvertise + publicRootPeersDNSMap <- Script . NonEmpty.fromList <$> listOf1 (genLookup publicRootRelays) return (MockRoots { mockLocalRootPeers = localRootPeers, @@ -162,14 +179,51 @@ genMockRoots = sized $ \relaysNumber -> do mockPublicRootPeersDNSMap = publicRootPeersDNSMap }) where + -- assigns weights and priorities to domains assigned to an SRV domain + -- such that several subdomains may have the same priority level and port + -- number, and each one will have a random weight, and result is shuffled + groupSrvs acc [] = return acc + groupSrvs acc ((srv, domains):rest) = do + let helper grouped 0 _ = shuffle grouped -- ^ check if sorting and grouping works in lookup + helper grouped count domains' = do + howMany <- chooseInt (1, count) + port <- genPort + prio <- arbitrary + wts <- vectorOf howMany arbitrary + let group = take howMany domains' + smash dom wt = (dom, prio, wt, port) + grouped' = zipWith smash group wts + <> grouped + helper grouped' (count - howMany) (drop howMany domains') + breakUp <- helper [] (length domains) domains + groupSrvs ((srv, breakUp) : acc) rest + + -- assigns some domains to SRV domains + dealDomains [] (domain : domains) srvs@(srv : srvs') = + dealDomains [(srv, [domain])] domains srvs' + + dealDomains as'@((s, ds):as) (domain : domains) srvs@(srv : srvs') = do + toss <- arbitrary + if toss + then dealDomains ((s, domain : ds):as) domains srvs + else dealDomains ((srv, [domain]):as') domains srvs' + + dealDomains as ds _srvs = return (as, ds) + + threeWay (rAddressAcc, rDomainAcc, rSRVAcc) = \case + a@RelayAccessAddress {} -> (a : rAddressAcc, rDomainAcc, rSRVAcc) + RelayAccessDomain d p -> (rAddressAcc, DomainPlain d p : rDomainAcc, rSRVAcc) + RelayAccessSRVDomain d -> (rAddressAcc, rDomainAcc, DomainSRV d : rSRVAcc) + genTargets :: Gen (HotValency, WarmValency) genTargets = do warmValency <- WarmValency <$> chooseEnum (1, 5) hotValency <- HotValency <$> chooseEnum (1, getWarmValency warmValency) return (hotValency, warmValency) - genDomainLookupTable :: Int -> [Domain] -> Gen (Map Domain [(IP, TTL)]) - genDomainLookupTable ipsPerDomain localRootDomains = do + genDomainIPLookupTable :: Int -> [DNS.Domain] -> Gen (Map (DNS.Domain, DNS.TYPE) + MockDNSLookupResult) + genDomainIPLookupTable ipsPerDomain localRootDomains = do localRootDomainIPs <- blocks ipsPerDomain -- Modules under test do not differ by IP version so we only -- generate IPv4 addresses. @@ -180,75 +234,79 @@ genMockRoots = sized $ \relaysNumber -> do (arbitrary :: Gen TTL) let localRootDomainsIP_TTls = zipWith zip localRootDomainIPs localRootDomainTTLs - lrpDNSMap = Map.fromList $ zip localRootDomains localRootDomainsIP_TTls + rootDomainKeys = (, DNS.A) <$> localRootDomains + lrpDNSMap = Map.fromList $ zip rootDomainKeys (Left <$> localRootDomainsIP_TTls) return lrpDNSMap - tagRelays relays = + tagRelays = zipWith (\tag rel -> case rel of - RelayAccessDomain domain port - -> RelayAccessDomain (domain <> (pack . show) tag) port + RelayDomainAccessPoint domain + | DomainAccessPoint (DomainPlain domain' port) <- domain -> + RelayAccessDomain (domain' <> (pack . show) tag) port + | DomainSRVAccessPoint (DomainSRV domain') <- domain -> + RelayAccessSRVDomain (domain' <> (pack . show) tag) x -> x ) [(0 :: Int), 1 .. ] - relays blocks _ [] = [] blocks s l = take s l : blocks s (drop s l) instance Arbitrary MockRoots where arbitrary = genMockRoots - shrink roots@MockRoots { mockLocalRootPeers - , mockLocalRootPeersDNSMap - , mockPublicRootPeers - , mockPublicRootPeersDNSMap - } = - [ roots { mockLocalRootPeers = lrp - , mockLocalRootPeersDNSMap = lrpDNSMap - } - | lrp <- shrinkList (const []) mockLocalRootPeers, - let lrpDomains = - Set.fromList [ domain - | RelayAccessDomain domain _ - <- concatMap (Map.keys . thrd) lrp ] - lrpDNSMap = (`Map.restrictKeys` lrpDomains) - <$> mockLocalRootPeersDNSMap - ] ++ - [ roots { mockPublicRootPeers = prp - , mockPublicRootPeersDNSMap = prpDNSMap - } - | prp <- shrink mockPublicRootPeers, - let prpDomains = Set.fromList [ domain - | (RelayAccessDomain domain _, _) - <- Map.assocs prp ] - prpDNSMap = (`Map.restrictKeys` prpDomains) - <$> mockPublicRootPeersDNSMap - ] - where - thrd (_, _, c) = c + shrink roots@MockRoots{} = undefined + -- { mockLocalRootPeers + -- , mockLocalRootPeersDNSMap + -- , mockPublicRootPeers + -- , mockPublicRootPeersDNSMap + -- } = + -- [ roots { mockLocalRootPeers = lrp + -- , mockLocalRootPeersDNSMap = lrpDNSMap + -- } + -- | lrp <- shrinkList (const []) mockLocalRootPeers, + -- let lrpDomains = + -- Set.fromList [ domain + -- | RelayAccessDomain domain _ + -- <- concatMap (Map.keys . thrd) lrp ] + -- lrpDNSMap = (`Map.restrictKeys` lrpDomains) + -- <$> mockLocalRootPeersDNSMap + -- ] ++ + -- [ roots { mockPublicRootPeers = prp + -- , mockPublicRootPeersDNSMap = prpDNSMap + -- } + -- | prp <- shrink mockPublicRootPeers, + -- let prpDomains = Set.fromList [ domain + -- | (RelayAccessDomain domain _, _) + -- <- Map.assocs prp ] + -- prpDNSMap = (`Map.restrictKeys` prpDomains) + -- <$> mockPublicRootPeersDNSMap + -- ] + -- where + -- thrd (_, _, c) = c -- | Used for debugging in GHCI -- -simpleMockRoots :: MockRoots -simpleMockRoots = MockRoots localRootPeers dnsMap Map.empty (singletonScript Map.empty) - where - localRootPeers = - [ ( 2, 2 - , Map.fromList - [ ( RelayAccessAddress (read "192.0.2.1") (read "3333") - , (DoAdvertisePeer, IsNotTrustable) - ) - , ( RelayAccessDomain "test.domain" (read "4444") - , (DoNotAdvertisePeer, IsNotTrustable) - ) - ] - ) - ] - dnsMap = singletonScript $ Map.fromList - [ ("test.domain", [read "192.1.1.1", read "192.2.2.2"]) - ] +-- simpleMockRoots :: MockRoots +-- simpleMockRoots = MockRoots localRootPeers dnsMap Map.empty (singletonScript Map.empty) (singletonScript (1 :: PortNumber)) +-- where +-- localRootPeers = +-- [ ( 2, 2 +-- , Map.fromList +-- [ ( RelayAccessAddress (read "192.0.2.1") (read "3333") +-- , (DoAdvertisePeer, IsNotTrustable) +-- ) +-- , ( RelayAccessDomain "test.domain" (read "4444") +-- , (DoNotAdvertisePeer, IsNotTrustable) +-- ) +-- ] +-- ) +-- ] +-- dnsMap = singletonScript $ Map.fromList +-- [ ("test.domain", [read "192.1.1.1", read "192.2.2.2"]) +-- ] genDiffTime :: Integer @@ -291,41 +349,53 @@ instance Arbitrary DNSLookupDelay where mockDNSActions :: forall exception m. ( MonadDelay m , MonadTimer m + , MonadAsync m ) - => StrictTVar m (Map Domain [(IP, TTL)]) + => DNSLookupType + -> StrictTVar m MockDNSMap -> StrictTVar m (Script DNSTimeout) -> StrictTVar m (Script DNSLookupDelay) -> DNSActions () exception m -mockDNSActions dnsMapVar dnsTimeoutScript dnsLookupDelayScript = +mockDNSActions ofType dnsMapVar dnsTimeoutScript dnsLookupDelayScript = DNSActions { dnsResolverResource, dnsAsyncResolverResource, - dnsLookupWithTTL + dnsLookupWithTTL = dispatchLookupWithTTL ofType mockLookup } where dnsResolverResource _ = return (Right <$> constantResource ()) dnsAsyncResolverResource _ = return (Right <$> constantResource ()) - dnsLookupWithTTL :: resolvConf - -> resolver - -> Domain - -> m ([DNSError], [(IP, TTL)]) - dnsLookupWithTTL _ _ domain = do + mockLookup :: resolver + -> resolvConf + -> DNS.Domain + -> DNS.TYPE + -> m (Maybe (Either DNSError DNSMessage)) + mockLookup _ _ domain ofType = do dnsMap <- readTVarIO dnsMapVar DNSTimeout dnsTimeout <- stepScript' dnsTimeoutScript DNSLookupDelay dnsLookupDelay <- stepScript' dnsLookupDelayScript - dnsLookup <- - MonadTimer.timeout dnsTimeout $ do - MonadTimer.threadDelay dnsLookupDelay - case Map.lookup domain dnsMap of - Nothing -> return (Left NameError) - Just x -> return (Right x) - - case dnsLookup of - Nothing -> return ([TimeoutExpired], []) - Just (Left e) -> return ([e], []) - Just (Right a) -> return ([], a) + MonadTimer.timeout dnsTimeout do + MonadTimer.threadDelay dnsLookupDelay + case Map.lookup (domain, ofType) dnsMap of + Nothing -> return (Left NameError) + Just x -> return (Right $ toDNSMessage x) + + where + toDNSMessage = \case + Left ipsttls -> + defaultResponse { + answer = [ResourceRecord domain DNS.NULL 0 ttl rdata + | (ip, ttl) <- ipsttls + , let rdata = case ip of + IPv4 ip -> DNS.RD_A ip + IPv6 ip -> DNS.RD_AAAA ip]} + Right ds -> + defaultResponse { + answer = [ResourceRecord domain DNS.NULL 0 0 rdata + | (domain', prio, weight, port) <- ds + , let rdata = DNS.RD_SRV prio weight (fromIntegral port) domain']} -- | 'localRootPeersProvider' running with a given MockRoots env -- @@ -356,24 +426,25 @@ mockLocalRootPeersProvider tracer (MockRoots localRootPeers dnsMapScript _ _) _ <- labelTVarIO resultVar "resultVar" _ <- traceTVarIO resultVar (\_ a -> pure $ TraceDynamic (LocalRootPeersResults a)) - withAsync (updateDNSMap dnsMapScriptVar dnsMapVar) $ \_ -> do - void $ MonadTimer.timeout 3600 $ - localRootPeersProvider tracer - (curry toSockAddr) - DNSResolver.defaultResolvConf - (mockDNSActions dnsMapVar - dnsTimeoutScriptVar - dnsLookupDelayScriptVar) - (readTVar localRootPeersVar) - resultVar - -- if there's no dns domain, `localRootPeersProvider` will never write - -- to `resultVar`; thus the `traceTVarIO` callback will never execute. - -- By reading & writing to the `TVar` we are forcing it to run at least - -- once. - atomically $ readTVar resultVar >>= writeTVar resultVar + return () + -- withAsync (updateDNSMap dnsMapScriptVar dnsMapVar) $ \_ -> do + -- void $ MonadTimer.timeout 3600 $ + -- localRootPeersProvider tracer + -- (curry toSockAddr) + -- DNSResolver.defaultResolvConf + -- (mockDNSActions dnsMapVar + -- dnsTimeoutScriptVar + -- dnsLookupDelayScriptVar) + -- (readTVar localRootPeersVar) + -- resultVar + -- -- if there's no dns domain, `localRootPeersProvider` will never write + -- -- to `resultVar`; thus the `traceTVarIO` callback will never execute. + -- -- By reading & writing to the `TVar` we are forcing it to run at least + -- -- once. + -- atomically $ readTVar resultVar >>= writeTVar resultVar where - updateDNSMap :: StrictTVar m (Script (Map Domain [(IP, TTL)])) - -> StrictTVar m (Map Domain [(IP, TTL)]) + updateDNSMap :: StrictTVar m (Script (Map DNS.Domain [(IP, TTL)])) + -> StrictTVar m (Map DNS.Domain [(IP, TTL)]) -> m Void updateDNSMap dnsMapScriptVar dnsMapVar = forever $ do @@ -411,20 +482,21 @@ mockPublicRootPeersProvider tracer (MockRoots _ _ publicRootPeers dnsMapScript) dnsTimeoutScriptVar <- initScript' dnsTimeoutScript dnsLookupDelayScriptVar <- initScript' dnsLookupDelayScript publicRootPeersVar <- newTVarIO publicRootPeers - replicateM_ 5 $ do - dnsMap' <- stepScript' dnsMapScriptVar - atomically (writeTVar dnsMapVar dnsMap') - - publicRootPeersProvider tracer - (curry toSockAddr) - dnsSemaphore - DNSResolver.defaultResolvConf - (readTVar publicRootPeersVar) - (mockDNSActions @Failure - dnsMapVar - dnsTimeoutScriptVar - dnsLookupDelayScriptVar) - action + return () + -- replicateM_ 5 $ do + -- dnsMap' <- stepScript' dnsMapScriptVar + -- atomically (writeTVar dnsMapVar dnsMap') + + -- publicRootPeersProvider tracer + -- (curry toSockAddr) + -- dnsSemaphore + -- DNSResolver.defaultResolvConf + -- (readTVar publicRootPeersVar) + -- (mockDNSActions @Failure + -- dnsMapVar + -- dnsTimeoutScriptVar + -- dnsLookupDelayScriptVar) + -- action -- | 'resolveDomainAddresses' running with a given MockRoots env -- @@ -447,16 +519,17 @@ mockResolveLedgerPeers tracer (MockRoots _ _ publicRootPeers dnsMapScript) dnsTimeoutScriptVar <- initScript' dnsTimeoutScript dnsLookupDelayScriptVar <- initScript' dnsLookupDelayScript - resolveLedgerPeers tracer - (curry toSockAddr) - dnsSemaphore - DNSResolver.defaultResolvConf - (mockDNSActions @Failure dnsMapVar - dnsTimeoutScriptVar - dnsLookupDelayScriptVar) - [ domain - | (RelayDomainAccessPoint domain, _) - <- Map.assocs publicRootPeers ] + return undefined + -- resolveLedgerPeers tracer + -- (curry toSockAddr) + -- dnsSemaphore + -- DNSResolver.defaultResolvConf + -- (mockDNSActions @Failure dnsMapVar + -- dnsTimeoutScriptVar + -- dnsLookupDelayScriptVar) + -- [ domain + -- | (RelayDomainAccessPoint domain, _) + -- <- Map.assocs publicRootPeers ] -- -- Utils for properties @@ -509,21 +582,21 @@ selectLocalRootGroupsEvents :: [(Time, TraceLocalRootPeers SockAddr Failure)] selectLocalRootGroupsEvents trace = [ (t, e) | (t, TraceLocalRootGroups e) <- trace ] selectLocalRootResultEvents :: [(Time, TraceLocalRootPeers SockAddr Failure)] - -> [(Time, (Domain, [IP]))] -selectLocalRootResultEvents trace = [ (t, (domain, map fst r)) - | (t, TraceLocalRootResult (DomainAccessPoint domain _) r) <- trace ] + -> [(Time, (DNS.Domain, [IP]))] +selectLocalRootResultEvents trace = undefined --[ (t, (domain, map fst r)) + -- | (t, TraceLocalRootResult (DomainAccessPoint domain _) r) <- trace ] selectPublicRootPeersEvents :: [(Time, TestTraceEvent)] -> [(Time, TracePublicRootPeers)] selectPublicRootPeersEvents trace = [ (t, e) | (t, RootPeerDNSPublic e) <- trace ] selectPublicRootFailureEvents :: [(Time, TracePublicRootPeers)] - -> [(Time, Domain)] + -> [(Time, DNS.Domain)] selectPublicRootFailureEvents trace = [ (t, domain) | (t, TracePublicRootFailure domain _) <- trace ] selectPublicRootResultEvents :: [(Time, TracePublicRootPeers)] - -> [(Time, (Domain, [IP]))] + -> [(Time, (DNS.Domain, [IP]))] selectPublicRootResultEvents trace = [ (t, (domain, map fst r)) | (t, TracePublicRootResult domain r) <- trace ] @@ -646,7 +719,7 @@ prop_local_resolvesDomainsCorrectly mockRoots@(MockRoots localRoots lDNSMap _ _) dnsLookupDelayScript -- local root domains - localRootDomains :: Set Domain + localRootDomains :: Set DNS.Domain localRootDomains = Set.fromList [ domain @@ -655,32 +728,32 @@ prop_local_resolvesDomainsCorrectly mockRoots@(MockRoots localRoots lDNSMap _ _) ] -- domains that were resolved during simulation - resultMap :: Set Domain + resultMap :: Set DNS.Domain resultMap = Set.fromList $ map (fst . snd) $ selectLocalRootResultEvents $ tr -- all domains that could have been resolved in each script - maxResultMap :: Script (Set Domain) - maxResultMap = Map.keysSet - . (`Map.restrictKeys` localRootDomains) - <$> lDNSMap + maxResultMap :: Script (Set DNS.Domain) + maxResultMap = undefined --Map.keysSet + -- . (`Map.restrictKeys` localRootDomains) + -- <$> lDNSMap -- all domains that were tried to resolve during the simulation - allTriedDomains :: Set Domain - allTriedDomains - = Set.fromList - $ catMaybes - [ mbDomain - | (_, ev) <- tr - , let mbDomain = case ev of - TraceLocalRootResult (DomainAccessPoint domain _) _ -> Just domain - TraceLocalRootFailure (DomainAccessPoint domain _) _ -> Just domain - TraceLocalRootError (DomainAccessPoint _domain _) _ -> Nothing - _ -> Nothing + allTriedDomains :: Set DNS.Domain + allTriedDomains = undefined + -- = Set.fromList + -- $ catMaybes + -- [ mbDomain + -- | (_, ev) <- tr + -- , let mbDomain = case ev of + -- TraceLocalRootResult (DomainAccessPoint domain _) _ -> Just domain + -- TraceLocalRootFailure (DomainAccessPoint domain _) _ -> Just domain + -- TraceLocalRootError (DomainAccessPoint _domain _) _ -> Nothing + -- _ -> Nothing - ] + -- ] in @@ -835,27 +908,27 @@ prop_public_resolvesDomainsCorrectly mockRoots@(MockRoots _ _ _ pDNSMap) (DelayAndTimeoutScripts dnsLookupDelayScript dnsTimeoutScript) n - = - let mockRoots' = - mockRoots { mockPublicRootPeersDNSMap = - singletonScript (scriptHead pDNSMap) - } - tr = runSimTrace - $ mockPublicRootPeersProvider tracerTracePublicRoots - mockRoots' - dnsTimeoutScript - dnsLookupDelayScript - ($ n) - - successes = selectPublicRootResultEvents - $ selectPublicRootPeersEvents - $ selectRootPeerDNSTraceEvents - $ tr - - successesMap = Map.fromList $ map snd successes - - in counterexample (show successes) - $ successesMap == (map fst <$> Map.unions pDNSMap) + = undefined + -- let mockRoots' = + -- mockRoots { mockPublicRootPeersDNSMap = + -- singletonScript (scriptHead pDNSMap) + -- } + -- tr = runSimTrace + -- $ mockPublicRootPeersProvider tracerTracePublicRoots + -- mockRoots' + -- dnsTimeoutScript + -- dnsLookupDelayScript + -- ($ n) + + -- successes = selectPublicRootResultEvents + -- $ selectPublicRootPeersEvents + -- $ selectRootPeerDNSTraceEvents + -- $ tr + + -- successesMap = Map.fromList $ map snd successes + + -- in counterexample (show successes) + -- $ successesMap == (map fst <$> Map.unions pDNSMap) -- | Create a resource from a list. diff --git a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/Testnet.hs b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/Testnet.hs index 3930aa10605..7788a393e4b 100644 --- a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/Testnet.hs +++ b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/Testnet.hs @@ -15,6 +15,7 @@ module Test.Ouroboros.Network.Testnet (tests) where +import Ouroboros.Network.PeerSelection.RelayAccessPoint import Control.Exception (AssertionFailed (..), catch, evaluate, fromException) import Control.Monad.Class.MonadFork import Control.Monad.Class.MonadTest (exploreRaces) @@ -176,8 +177,8 @@ tests = (testWithIOSim prop_diffusion_nolivelock 125000) , testProperty "dns can recover from fails" (testWithIOSim prop_diffusion_dns_can_recover 125000) - , testProperty "unit #4191" - unit_4191 + -- , testProperty "unit #4191" + -- unit_4191 , testProperty "target established public" (testWithIOSim prop_diffusion_target_established_public 125000) , testProperty "target active public" @@ -1411,7 +1412,7 @@ prop_diffusion_dns_can_recover ioSimTrace traceNumber = case ev of DiffusionLocalRootPeerTrace (TraceLocalRootFailure dap (DNSError err)) -> - let dns = dapDomain dap + let dns = extractDomainName dap ttl = fromMaybe 0 $ Map.lookup dns ttlMap ttl' = ttlForDnsError err ttl ttlMap' = Map.insert dns ttl' ttlMap @@ -1422,7 +1423,7 @@ prop_diffusion_dns_can_recover ioSimTrace traceNumber = (TraceLocalRootReconfigured _ _) -> verify Map.empty ttlMap recovered t evs DiffusionLocalRootPeerTrace (TraceLocalRootResult dap r) -> - let dns = dapDomain dap + let dns = extractDomainName dap ttls = map snd r ttlMap' = Map.insert dns (ttlForResults ttls) ttlMap in case Map.lookup dns toRecover of @@ -1436,109 +1437,112 @@ prop_diffusion_dns_can_recover ioSimTrace traceNumber = verify Map.empty ttlMap recovered t evs _ -> verify toRecover ttlMap recovered time evs + extractDomainName (DomainAccessPoint (DomainPlain d _)) = d + extractDomainName (DomainSRVAccessPoint (DomainSRV d)) = d + -- | Unit test which covers issue #4191 -- -unit_4191 :: Property -unit_4191 = testWithIOSim prop_diffusion_dns_can_recover 125000 absInfo script - where - ioerr = - IOError - { ioe_handle = Nothing, - ioe_type = ResourceVanished, - ioe_location = "AttenuationChannel", - ioe_description = "attenuation", - ioe_errno = Nothing, - ioe_filename = Nothing - } - absInfo = - AbsBearerInfo - { abiConnectionDelay = SmallDelay, - abiInboundAttenuation = NoAttenuation NormalSpeed, - abiOutboundAttenuation = ErrorInterval NormalSpeed (Time 17.666666666666) 888 ioerr, - abiInboundWriteFailure = Nothing, - abiOutboundWriteFailure = Just 2, - abiAcceptFailure = Nothing, abiSDUSize = LargeSDU - } - script = - DiffusionScript - (SimArgs 1 20) - (singletonTimedScript $ - Map.fromList - [ ("test2", [ (read "810b:4c8a:b3b5:741:8c0c:b437:64cf:1bd9", 300) - , (read "254.167.216.215", 300) - , (read "27.173.29.254", 300) - , (read "61.238.34.238", 300) - , (read "acda:b62d:6d7d:50f7:27b6:7e34:2dc6:ee3d", 300) - ]) - , ("test3", [ (read "903e:61bc:8b2f:d98f:b16e:5471:c83d:4430", 300) - , (read "19.40.90.161", 300) - ]) - ]) - [(NodeArgs - 16 - InitiatorAndResponderDiffusionMode - (Just 224) - Map.empty - PraosMode - (Script (UseBootstrapPeers [RelayAccessDomain "bootstrap" 00000] :| [])) - (TestAddress (IPAddr (read "0.0.1.236") 65527)) - PeerSharingDisabled - [ (2,2,Map.fromList [ (RelayAccessDomain "test2" 15,(DoNotAdvertisePeer, IsNotTrustable)) - , (RelayAccessDomain "test3" 4,(DoAdvertisePeer, IsNotTrustable))]) - ] - (Script (LedgerPools [] :| [])) - ConsensusModePeerTargets { - deadlineTargets = PeerSelectionTargets - { targetNumberOfRootPeers = 6, - targetNumberOfKnownPeers = 7, - targetNumberOfEstablishedPeers = 7, - targetNumberOfActivePeers = 6, - - targetNumberOfKnownBigLedgerPeers = 0, - targetNumberOfEstablishedBigLedgerPeers = 0, - targetNumberOfActiveBigLedgerPeers = 0 - }, - syncTargets = nullPeerSelectionTargets } - (Script (DNSTimeout {getDNSTimeout = 0.406} :| [ DNSTimeout {getDNSTimeout = 0.11} - , DNSTimeout {getDNSTimeout = 0.333} - , DNSTimeout {getDNSTimeout = 0.352} - , DNSTimeout {getDNSTimeout = 0.123} - , DNSTimeout {getDNSTimeout = 0.12} - , DNSTimeout {getDNSTimeout = 0.23} - , DNSTimeout {getDNSTimeout = 0.311} - , DNSTimeout {getDNSTimeout = 0.37} - , DNSTimeout {getDNSTimeout = 0.153} - , DNSTimeout {getDNSTimeout = 0.328} - , DNSTimeout {getDNSTimeout = 0.239} - , DNSTimeout {getDNSTimeout = 0.261} - , DNSTimeout {getDNSTimeout = 0.15} - , DNSTimeout {getDNSTimeout = 0.26} - , DNSTimeout {getDNSTimeout = 0.37} - , DNSTimeout {getDNSTimeout = 0.28} - ])) - (Script (DNSLookupDelay {getDNSLookupDelay = 0.124} :| [ DNSLookupDelay {getDNSLookupDelay = 0.11} - , DNSLookupDelay {getDNSLookupDelay = 0.129} - , DNSLookupDelay {getDNSLookupDelay = 0.066} - , DNSLookupDelay {getDNSLookupDelay = 0.125} - , DNSLookupDelay {getDNSLookupDelay = 0.046} - , DNSLookupDelay {getDNSLookupDelay = 0.135} - , DNSLookupDelay {getDNSLookupDelay = 0.05} - , DNSLookupDelay {getDNSLookupDelay = 0.039} - ])) - Nothing - False - (Script (FetchModeDeadline :| [])) - , [ JoinNetwork 6.710144927536 - , Kill 7.454545454545 - , JoinNetwork 10.763157894736 - , Reconfigure 0.415384615384 [(1,1,Map.empty) - , (1,1,Map.empty)] - , Reconfigure 15.550561797752 [(1,1,Map.empty) - , (1,1,Map.fromList [(RelayAccessDomain "test2" 15,(DoAdvertisePeer, IsNotTrustable))])] - , Reconfigure 82.85714285714 [] - ]) - ] +-- unit_4191 :: Property +-- unit_4191 = testWithIOSim prop_diffusion_dns_can_recover 125000 absInfo script +-- where +-- ioerr = +-- IOError +-- { ioe_handle = Nothing, +-- ioe_type = ResourceVanished, +-- ioe_location = "AttenuationChannel", +-- ioe_description = "attenuation", +-- ioe_errno = Nothing, +-- ioe_filename = Nothing +-- } +-- absInfo = +-- AbsBearerInfo +-- { abiConnectionDelay = SmallDelay, +-- abiInboundAttenuation = NoAttenuation NormalSpeed, +-- abiOutboundAttenuation = ErrorInterval NormalSpeed (Time 17.666666666666) 888 ioerr, +-- abiInboundWriteFailure = Nothing, +-- abiOutboundWriteFailure = Just 2, +-- abiAcceptFailure = Nothing, abiSDUSize = LargeSDU +-- } +-- script = +-- DiffusionScript +-- (SimArgs 1 20) +-- (singletonTimedScript $ +-- Map.fromList +-- [ ("test2", [ (read "810b:4c8a:b3b5:741:8c0c:b437:64cf:1bd9", 300) +-- , (read "254.167.216.215", 300) +-- , (read "27.173.29.254", 300) +-- , (read "61.238.34.238", 300) +-- , (read "acda:b62d:6d7d:50f7:27b6:7e34:2dc6:ee3d", 300) +-- ]) +-- , ("test3", [ (read "903e:61bc:8b2f:d98f:b16e:5471:c83d:4430", 300) +-- , (read "19.40.90.161", 300) +-- ]) +-- ]) +-- [(NodeArgs +-- 16 +-- InitiatorAndResponderDiffusionMode +-- (Just 224) +-- Map.empty +-- PraosMode +-- (Script (UseBootstrapPeers [RelayAccessDomain "bootstrap" 00000] :| [])) +-- (TestAddress (IPAddr (read "0.0.1.236") 65527)) +-- PeerSharingDisabled +-- [ (2,2,Map.fromList [ (RelayAccessDomain "test2" 15,(DoNotAdvertisePeer, IsNotTrustable)) +-- , (RelayAccessDomain "test3" 4,(DoAdvertisePeer, IsNotTrustable))]) +-- ] +-- (Script (LedgerPools [] :| [])) +-- ConsensusModePeerTargets { +-- deadlineTargets = PeerSelectionTargets +-- { targetNumberOfRootPeers = 6, +-- targetNumberOfKnownPeers = 7, +-- targetNumberOfEstablishedPeers = 7, +-- targetNumberOfActivePeers = 6, + +-- targetNumberOfKnownBigLedgerPeers = 0, +-- targetNumberOfEstablishedBigLedgerPeers = 0, +-- targetNumberOfActiveBigLedgerPeers = 0 +-- }, +-- syncTargets = nullPeerSelectionTargets } +-- (Script (DNSTimeout {getDNSTimeout = 0.406} :| [ DNSTimeout {getDNSTimeout = 0.11} +-- , DNSTimeout {getDNSTimeout = 0.333} +-- , DNSTimeout {getDNSTimeout = 0.352} +-- , DNSTimeout {getDNSTimeout = 0.123} +-- , DNSTimeout {getDNSTimeout = 0.12} +-- , DNSTimeout {getDNSTimeout = 0.23} +-- , DNSTimeout {getDNSTimeout = 0.311} +-- , DNSTimeout {getDNSTimeout = 0.37} +-- , DNSTimeout {getDNSTimeout = 0.153} +-- , DNSTimeout {getDNSTimeout = 0.328} +-- , DNSTimeout {getDNSTimeout = 0.239} +-- , DNSTimeout {getDNSTimeout = 0.261} +-- , DNSTimeout {getDNSTimeout = 0.15} +-- , DNSTimeout {getDNSTimeout = 0.26} +-- , DNSTimeout {getDNSTimeout = 0.37} +-- , DNSTimeout {getDNSTimeout = 0.28} +-- ])) +-- (Script (DNSLookupDelay {getDNSLookupDelay = 0.124} :| [ DNSLookupDelay {getDNSLookupDelay = 0.11} +-- , DNSLookupDelay {getDNSLookupDelay = 0.129} +-- , DNSLookupDelay {getDNSLookupDelay = 0.066} +-- , DNSLookupDelay {getDNSLookupDelay = 0.125} +-- , DNSLookupDelay {getDNSLookupDelay = 0.046} +-- , DNSLookupDelay {getDNSLookupDelay = 0.135} +-- , DNSLookupDelay {getDNSLookupDelay = 0.05} +-- , DNSLookupDelay {getDNSLookupDelay = 0.039} +-- ])) +-- Nothing +-- False +-- (Script (FetchModeDeadline :| [])) +-- , [ JoinNetwork 6.710144927536 +-- , Kill 7.454545454545 +-- , JoinNetwork 10.763157894736 +-- , Reconfigure 0.415384615384 [(1,1,Map.empty) +-- , (1,1,Map.empty)] +-- , Reconfigure 15.550561797752 [(1,1,Map.empty) +-- , (1,1,Map.fromList [(RelayAccessDomain "test2" 15,(DoAdvertisePeer, IsNotTrustable))])] +-- , Reconfigure 82.85714285714 [] +-- ]) +-- ] -- | Verify that some connect failures are fatal. diff --git a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/Testnet/Internal.hs b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/Testnet/Internal.hs index b8758ba8ab2..4b19a878b14 100644 --- a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/Testnet/Internal.hs +++ b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/Testnet/Internal.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE BlockArguments #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} @@ -35,6 +36,12 @@ module Test.Ouroboros.Network.Testnet.Internal , module PeerSelection ) where +import Data.Functor ((<&>)) +import Data.Bifunctor (bimap) +import Data.List (singleton, partition) +import Data.Foldable (foldlM) +import Network.DNS qualified as DNS +import Data.Functor.Classes import Control.Applicative (Alternative) import Control.Concurrent.Class.MonadMVar (MonadMVar) import Control.Concurrent.Class.MonadSTM.Strict @@ -54,7 +61,7 @@ import Control.Monad.IOSim (IOSim, traceM) import Data.ByteString.Char8 qualified as BSC import Data.ByteString.Lazy qualified as BL import Data.IP (IP (..)) -import Data.List (delete, nubBy) +import Data.List (delete, nub) import Data.List.NonEmpty qualified as NonEmpty import Data.Map (Map) import Data.Map qualified as Map @@ -66,7 +73,7 @@ import Data.Void (Void) import System.Random (StdGen, mkStdGen) import System.Random qualified as Random -import Network.DNS (Domain, TTL) +import Network.DNS (Domain) import Network.TypedProtocol.Core import Network.TypedProtocol.PingPong.Type qualified as PingPong @@ -111,7 +118,7 @@ import Simulation.Network.Snocket (BearerInfo (..), FD, SnocketTrace, import Test.Ouroboros.Network.PeerSelection.Instances qualified as PeerSelection import Test.Ouroboros.Network.PeerSelection.RootPeersDNS (DNSLookupDelay (..), - DNSTimeout (..)) + DNSTimeout (..), MockDNSMap) import Test.Ouroboros.Network.PeerSelection.RootPeersDNS qualified as PeerSelection hiding (tests) import Test.Ouroboros.Network.Testnet.Node qualified as Node @@ -130,8 +137,7 @@ import Ouroboros.Network.PeerSelection.LocalRootPeers import Ouroboros.Network.PeerSelection.PeerAdvertise (PeerAdvertise (..)) import Ouroboros.Network.PeerSelection.PeerSharing (PeerSharing) import Ouroboros.Network.PeerSelection.PeerTrustable (PeerTrustable) -import Ouroboros.Network.PeerSelection.RelayAccessPoint (DomainAccessPoint (..), - PortNumber, RelayAccessPoint (..)) +import Ouroboros.Network.PeerSelection.RelayAccessPoint import Ouroboros.Network.PeerSelection.RootPeersDNS.DNSActions (DNSLookupType) import Ouroboros.Network.PeerSelection.RootPeersDNS.LocalRootPeers (TraceLocalRootPeers) @@ -360,10 +366,10 @@ instance Arbitrary SmallPeerSelectionTargets where -- | Given a NtNAddr generate the necessary things to run a node in -- Simulation -genNodeArgs :: [RelayAccessInfo] +genNodeArgs :: [TestnetRelayInfo] -> Int -> [(HotValency, WarmValency, Map RelayAccessPoint (PeerAdvertise, PeerTrustable))] - -> RelayAccessInfo + -> TestnetRelayInfo -> Gen NodeArgs genNodeArgs relays minConnected localRootPeers relay = flip suchThat hasUpstream $ do -- Slot length needs to be greater than 0 else we get a livelock on @@ -418,14 +424,12 @@ genNodeArgs relays minConnected localRootPeers relay = flip suchThat hasUpstream let (ledgerPeersRelays, publicRootsRelays) = splitAt (length relays `div` 2) relays publicRoots = - Map.fromList [ (makeRelayAccessPoint relay', advertise) + Map.fromList [ (relay, advertise) | relay' <- publicRootsRelays , relay' /= relay - , let advertise = case relay' of - RelayAddrInfo _ip _port adv -> adv - RelayDomainInfo _dns _ip _port adv -> adv + , let (relay, _, _, (advertise, _)) = relay' ] - ledgerPeers <- fmap (map makeRelayAccessPoint) <$> listOf (sublistOf ledgerPeersRelays) + ledgerPeers <- fmap (map \(relay, _, _, _) -> relay) <$> listOf (sublistOf ledgerPeersRelays) ledgerPeerPools <- traverse genLedgerPoolsFrom ledgerPeers firstLedgerPool <- arbitrary let ledgerPeerPoolsScript = Script (firstLedgerPool :| ledgerPeerPools) @@ -448,7 +452,7 @@ genNodeArgs relays minConnected localRootPeers relay = flip suchThat hasUpstream -- `UseLedgerPeers 0`! , naConsensusMode , naBootstrapPeers = bootstrapPeersDomain - , naAddr = makeNtNAddr relay + , naAddr = TestAddress ((\(_, ip, port, _) -> IPAddr ip port) relay) , naLocalRootPeers = localRootPeers , naLedgerPeers = ledgerPeerPoolsScript , naPeerTargets = peerTargets @@ -482,83 +486,95 @@ genNodeArgs relays minConnected localRootPeers relay = flip suchThat hasUpstream -- 'DomainMapScript' describes evolution of domain name resolution. -- -type DomainMapScript = TimedScript (Map Domain [(IP, TTL)]) +type DomainMapScript = TimedScript MockDNSMap -- | Make sure that the final domain map can resolve all the domains correctly. -- -fixupDomainMapScript :: RelayAccessInfos -> DomainMapScript -> DomainMapScript -fixupDomainMapScript relays (Script (a@(_, delay) :| as)) = +fixupDomainMapScript :: MockDNSMap -> DomainMapScript -> DomainMapScript +fixupDomainMapScript mockMap (Script (a@(_, delay) :| as)) = case reverse as of - [] -> Script $ (dnsMap, delay) :| as - ((_, delay') : as') -> Script $ a :| reverse ((dnsMap, delay') : as') - where - dnsMap :: Map Domain [(IP, TTL)] - dnsMap = Map.fromListWith (++) - [ (domain, [(ip, 300)]) - | RelayDomainInfo domain ip _ _ <- getRelayAccessInfos relays - ] - + [] -> Script $ (mockMap, delay) :| as + ((_, delay') : as') -> Script $ a :| reverse ((mockMap, delay') : as') -- | Generate a `DomainMapScript`. Each step contains modification of the full -- dns map with at most 20% entries removed and 20% entries modified. The last -- scripted value is the full dns map which ensures that eventually all dns -- names resolve to correct ip addresses. -- -genDomainMapScript :: RelayAccessInfos -> Gen DomainMapScript -genDomainMapScript relays = fixupDomainMapScript relays - <$> arbitraryScriptOf 10 - ((,) <$> genDomainMap <*> arbitrary) +genDomainMapScript :: TestnetRelayInfos -> Gen DomainMapScript +genDomainMapScript relays = do + mockMap <- dnsMapGen + fixupDomainMapScript mockMap <$> + arbitraryScriptOf 10 ((,) <$> genDomainMap mockMap <*> arbitrary) where - genDomainMap :: Gen (Map Domain [(IP, TTL)]) - genDomainMap = do - rm <- removedDomains - md <- modifiedDomains - return $ Map.fromList md `Map.union` foldr Map.delete dnsMap rm - - removedDomains :: Gen [Domain] - removedDomains = do - as <- vectorOf (length domains) (frequency [(4, pure True), (1, pure False)]) + them = unTestnetRelays relays + dnsType = case relays of + TestnetRelays4 {} -> DNS.A + TestnetRelays6 {} -> DNS.AAAA + + genDomainMap mockMap = do + let dnsAssoc = Map.toList mockMap + rm <- removedDomains (fst <$> dnsAssoc) + md <- modifiedDomains dnsAssoc + return $ Map.fromList md `Map.union` foldr Map.delete mockMap rm + + removedDomains domains = do + as <- tosses (length domains) return $ map fst . filter snd $ zip domains as - where - domains = Map.keys dnsMap - - modifiedDomains :: Gen [(Domain, [(IP, TTL)])] - modifiedDomains = do - as <- vectorOf (length domains) (frequency [(4, pure True), (1, pure False)]) - let ds :: [Domain] - ds = map fst . filter snd $ zip domains as - ips <- vectorOf (length ds) (case relays of - IPv4RelayAccessInfos _ -> PeerSelection.genIPv4 - IPv6RelayAccessInfos _ -> PeerSelection.genIPv6) - return $ zip ds ((\a -> [(a,ttl)]) <$> ips) - where - domains = Map.keys dnsMap - dnsMap :: Map Domain [(IP, TTL)] - dnsMap = Map.fromListWith (++) - [ (domain, [(ip, ttl)]) - | RelayDomainInfo domain ip _ _ <- getRelayAccessInfos relays - ] + modifiedDomains assoc = do + mask' <- tosses (length assoc) + let picked = map fst . filter snd $ zip assoc mask' + forM picked \(k, v) -> + case v of + Left _ipsttls -> case relays of + TestnetRelays4 {} -> + (k,) . Left . singleton . (, ttl) <$> PeerSelection.genIPv4 + TestnetRelays6 {} -> + (k,) . Left . singleton . (, ttl) <$> PeerSelection.genIPv6 + Right _doms -> do + (k,) . Right . singleton <$> genDomain + + genDomain = do + return undefined + + tosses count = vectorOf count (frequency [(4, pure True), (1, pure False)]) + + dnsMapGen = do + foldlM step Map.empty them + + step b (relay, ip, _port, _adv) = do + case relay of + RelayAccessAddress {} -> return b + RelayAccessDomain d _p -> Map.alterF fa (d, dnsType) b + RelayAccessSRVDomain d -> Map.alterF ga (d, DNS.SRV) b + where + fa Nothing = pure . Just . Left $ [(ip, ttl)] + fa (Just (Left ipsttls)) = pure . Just . Left $ (ip, ttl) : ipsttls + fa _ = error "impossible!" + ga Nothing = undefined -- generate some domains + ga (Just (Right _ds)) = undefined -- concat ip into subdomains + ga _ = error "impossible!" ttl = 300 -shrinkDomainMapScript :: RelayAccessInfos -> DomainMapScript -> [DomainMapScript] -shrinkDomainMapScript relays script = - catMaybes $ - -- make sure `fixupDomainMapScript` didn't return something that's - -- equal to the original `script` - (\script' -> if script == script' then Nothing else Just script') - . fixupDomainMapScript relays - <$> shrinkScriptWith (shrinkTuple shrinkMap_ shrink) script - where - shrinkMap_ :: Ord a => Map a b -> [Map a b] - shrinkMap_ = map Map.fromList . shrinkList (const []) . Map.toList +-- shrinkDomainMapScript :: RelayAccessInfos -> DomainMapScript -> [DomainMapScript] +-- shrinkDomainMapScript relays script = +-- catMaybes $ +-- -- make sure `fixupDomainMapScript` didn't return something that's +-- -- equal to the original `script` +-- (\script' -> if script == script' then Nothing else Just script') +-- . fixupDomainMapScript relays +-- <$> shrinkScriptWith (shrinkTuple shrinkMap_ shrink) script +-- where +-- shrinkMap_ :: Ord a => Map a b -> [Map a b] +-- shrinkMap_ = map Map.fromList . shrinkList (const []) . Map.toList - shrinkTuple :: (a -> [a]) -> (b -> [b]) -> (a, b) -> [(a, b)] - shrinkTuple f g (a, b) = [(a', b) | a' <- f a] - ++ [(a, b') | b' <- g b] +-- shrinkTuple :: (a -> [a]) -> (b -> [b]) -> (a, b) -> [(a, b)] +-- shrinkTuple f g (a, b) = [(a', b) | a' <- f a] +-- ++ [(a, b') | b' <- g b] -- -- DiffusionScript @@ -581,129 +597,122 @@ instance Show DiffusionScript where -- | Information describing how nodes can be accessed. -- -data RelayAccessInfo - = RelayAddrInfo IP PortNumber PeerAdvertise - -- ^ relays available using ip / port pair - | RelayDomainInfo Domain IP PortNumber PeerAdvertise - -- ^ relays available either using the given domain. - deriving (Show, Eq) - -genRelayAccessInfo :: Gen IP - -> Gen RelayAccessInfo -genRelayAccessInfo genIP = - oneof [ RelayAddrInfo <$> genIP - <*> (fromIntegral <$> (arbitrary :: Gen Int)) - <*> arbitrary - , (\(DomainAccessPoint domain port) ip advertise -> RelayDomainInfo domain ip port advertise) - <$> arbitrary - <*> genIP - <*> arbitrary - ] - -makeRelayAccessPoint :: RelayAccessInfo -> RelayAccessPoint -makeRelayAccessPoint (RelayAddrInfo ip port _) = RelayAccessAddress ip port -makeRelayAccessPoint (RelayDomainInfo domain _ip port _) = RelayAccessDomain domain port - -makeNtNAddr :: RelayAccessInfo -> NtNAddr -makeNtNAddr (RelayAddrInfo ip port _) = TestAddress (IPAddr ip port) -makeNtNAddr (RelayDomainInfo _dns ip port _) = TestAddress (IPAddr ip port) - -data RelayAccessInfos - -- IPv4 only network - = IPv4RelayAccessInfos { getRelayAccessInfos :: [RelayAccessInfo] } - -- IPv6 only network - | IPv6RelayAccessInfos { getRelayAccessInfos :: [RelayAccessInfo] } - deriving Show - -fixupRelayAccessInfos :: [RelayAccessInfo] -> [RelayAccessInfo] -fixupRelayAccessInfos as = f <$> as - where +-- data RelayAccessInfo +-- = RelayAddrInfo IP PortNumber PeerAdvertise +-- -- ^ relays available using ip / port pair +-- | RelayDomainInfo Domain (Maybe (IP, PortNumber)) PeerAdvertise +-- -- ^ relays accessible via a domain name (SRV when Nothing) +-- deriving (Show, Eq) + +-- genRelayAccessInfo :: Gen IP +-- -> Gen RelayAccessInfo +-- genRelayAccessInfo genIP = +-- oneof [ RelayAddrInfo <$> genIP +-- <*> (fromIntegral <$> (arbitrary :: Gen Int)) +-- <*> arbitrary +-- , f <$> arbitrary +-- <*> genIP +-- <*> arbitrary +-- ] +-- where +-- f dom ip advertise = +-- case dom of +-- DomainAccessPoint (DomainPlain d p) -> RelayDomainInfo d (Just (ip, p)) advertise +-- DomainSRVAccessPoint (DomainSRV d) -> RelayDomainInfo d Nothing advertise + + +-- data RelayAccessInfos +-- -- IPv4 only network +-- = IPv4RelayAccessInfos { getRelayAccessInfos :: [RelayAccessInfo] } +-- -- IPv6 only network +-- | IPv6RelayAccessInfos { getRelayAccessInfos :: [RelayAccessInfo] } +-- deriving Show + +-- fixupRelayAccessInfos :: [RelayAccessInfo] -> [RelayAccessInfo] +-- fixupRelayAccessInfos as = f <$> as +-- where -- map domains to the same port number - m = Map.fromList [ (domain, port) - | RelayDomainInfo domain _ port _ <- as - ] + -- m = undefined + -- Map.fromList [ (domain, port) + -- | RelayDomainInfo domain _ port _ <- as + -- ] - f a@RelayAddrInfo {} = a - f (RelayDomainInfo domain ip _ advertise) = RelayDomainInfo domain ip (m Map.! domain) advertise + -- f a@RelayAddrInfo {} = a + --f (RelayDomainInfo domain ip _ advertise) = RelayDomainInfo domain ip (m Map.! domain) advertise -- Generate a list of either IPv4 only or IPv6 only `RelayAccessInfo`. All -- `IP`'s using the same domain name are guaranteed to use the same port -- number. -instance Arbitrary RelayAccessInfos where - arbitrary = oneof - [ do -- Limit the number of nodes to run in Simulation in order to limit - -- simulation execution (real) time. - size <- chooseInt (1,3) - IPv4RelayAccessInfos . fixupRelayAccessInfos - <$> vectorOf size (genRelayAccessInfo PeerSelection.genIPv4) +-- instance Arbitrary RelayAccessInfos where +-- arbitrary = oneof +-- [ do -- Limit the number of nodes to run in Simulation in order to limit +-- -- simulation execution (real) time. +-- size <- chooseInt (1,3) +-- IPv4RelayAccessInfos . fixupRelayAccessInfos +-- <$> vectorOf size (genRelayAccessInfo PeerSelection.genIPv4) - , do -- Limit the number of nodes to run in Simulation in order to limit - -- simulation execution (real) time. - size <- chooseInt (1,3) - IPv6RelayAccessInfos . fixupRelayAccessInfos - <$> vectorOf size (genRelayAccessInfo PeerSelection.genIPv6) - ] +-- , do -- Limit the number of nodes to run in Simulation in order to limit +-- -- simulation execution (real) time. +-- size <- chooseInt (1,3) +-- IPv6RelayAccessInfos . fixupRelayAccessInfos +-- <$> vectorOf size (genRelayAccessInfo PeerSelection.genIPv6) +-- ] - shrink (IPv4RelayAccessInfos as) = IPv4RelayAccessInfos . fixupRelayAccessInfos - <$> shrinkList (const []) as - shrink (IPv6RelayAccessInfos as) = IPv6RelayAccessInfos . fixupRelayAccessInfos - <$> shrinkList (const []) as +-- shrink (IPv4RelayAccessInfos as) = IPv4RelayAccessInfos . fixupRelayAccessInfos +-- <$> shrinkList (const []) as +-- shrink (IPv6RelayAccessInfos as) = IPv6RelayAccessInfos . fixupRelayAccessInfos +-- <$> shrinkList (const []) as -- | Relays access info and dns script. -- -data RelayAccessInfosWithDNS = RelayAccessInfosWithDNS RelayAccessInfos DomainMapScript - deriving Show - - -instance Arbitrary RelayAccessInfosWithDNS where - arbitrary = - flip suchThat (\(RelayAccessInfosWithDNS infos _) - -> length (getRelayAccessInfos infos) >= 2) $ do - infos <- arbitrary - domainMapScript <- genDomainMapScript infos - return $ RelayAccessInfosWithDNS infos domainMapScript - - shrink (RelayAccessInfosWithDNS infos dnsMapScript) = - [ RelayAccessInfosWithDNS infos (fixupDomainMapScript infos' dnsMapScript) - | infos' <- shrink infos - , length (getRelayAccessInfos infos') >= 2 - ] - ++ - [ RelayAccessInfosWithDNS infos dnsMapScript' - | dnsMapScript' <- shrinkDomainMapScript infos dnsMapScript - ] - - -genDiffusionScript :: ([RelayAccessInfo] - -> RelayAccessInfo - -> Gen [( HotValency +-- data RelayAccessInfosWithDNS = RelayAccessInfosWithDNS RelayAccessInfos DomainMapScript +-- deriving Show + + +-- instance Arbitrary RelayAccessInfosWithDNS where +-- arbitrary = undefined +-- -- flip suchThat (\(RelayAccessInfosWithDNS infos _) +-- -- -> length (getRelayAccessInfos infos) >= 2) $ do +-- -- infos <- arbitrary +-- -- domainMapScript <- genDomainMapScript infos +-- -- return $ RelayAccessInfosWithDNS infos domainMapScript + +-- shrink (RelayAccessInfosWithDNS infos dnsMapScript) = undefined +-- -- [ RelayAccessInfosWithDNS infos (fixupDomainMapScript infos' dnsMapScript) +-- -- | infos' <- shrink infos +-- -- , length (getRelayAccessInfos infos') >= 2 +-- -- ] +-- -- ++ +-- -- [ RelayAccessInfosWithDNS infos dnsMapScript' +-- -- | dnsMapScript' <- shrinkDomainMapScript infos dnsMapScript +-- -- ] + + +genDiffusionScript :: ( [TestnetRelayInfo] + -> TestnetRelayInfo + -> Gen [( HotValency , WarmValency , Map RelayAccessPoint (PeerAdvertise, PeerTrustable))]) - -> RelayAccessInfosWithDNS + -> TestnetRelayInfos -> Gen (SimArgs, DomainMapScript, [(NodeArgs, [Command])]) genDiffusionScript genLocalRootPeers - (RelayAccessInfosWithDNS relays dnsMapScript) + relays -- (RelayAccessInfosWithDNS relays dnsMapScript) = do - let simArgs = mainnetSimArgs (length relays') - nodesWithCommands <- mapM go (nubBy ((==) `on` getRelayIP) relays') + let simArgs = mainnetSimArgs (length them) + dnsMapScript <- genDomainMapScript relays + nodesWithCommands <- mapM go them return (simArgs, dnsMapScript, nodesWithCommands) where - getRelayIP :: RelayAccessInfo -> IP - getRelayIP (RelayAddrInfo ip _ _) = ip - getRelayIP (RelayDomainInfo _ ip _ _) = ip - - relays' :: [RelayAccessInfo] - relays' = getRelayAccessInfos relays - - go :: RelayAccessInfo -> Gen (NodeArgs, [Command]) - go relay = do - let otherRelays = relay `delete` relays' - minConnected = 3 `max` (length relays' - 1) - localRts <- genLocalRootPeers otherRelays relay - nodeArgs <- genNodeArgs relays' minConnected localRts relay + them = unTestnetRelays relays + go self = do + let otherRelays = self `delete` them + minConnected = 3 `max` (length them - 1) -- ^ TODO is this ever different from 3? + -- since we generate {2,3} relays? + localRts <- genLocalRootPeers otherRelays self + nodeArgs <- genNodeArgs them minConnected localRts self commands <- genCommands localRts return (nodeArgs, commands) @@ -714,27 +723,26 @@ genDiffusionScript genLocalRootPeers -- or can not be connected to one another. These nodes can also randomly die or -- have their local configuration changed. -- -genNonHotDiffusionScript :: RelayAccessInfosWithDNS +genNonHotDiffusionScript :: TestnetRelayInfos -> Gen (SimArgs, DomainMapScript, [(NodeArgs, [Command])]) genNonHotDiffusionScript = genDiffusionScript genLocalRootPeers where -- | Generate Local Root Peers -- - genLocalRootPeers :: [RelayAccessInfo] - -> RelayAccessInfo + genLocalRootPeers :: [TestnetRelayInfo] + -> TestnetRelayInfo -> Gen [( HotValency , WarmValency , Map RelayAccessPoint (PeerAdvertise, PeerTrustable) )] - genLocalRootPeers relays _relay = flip suchThat hasUpstream $ do + genLocalRootPeers others _self = flip suchThat hasUpstream $ do nrGroups <- chooseInt (1, 3) -- Remove self from local root peers - let size = length relays + let size = length others sizePerGroup = (size `div` nrGroups) + 1 - peerAdvertise <- vectorOf size arbitrary - - let relaysAdv = zip (makeRelayAccessPoint <$> relays) peerAdvertise + let relaysAdv = others <&> + \((rap, _ip, _port, advTrust)) -> (rap, advTrust) relayGroups = divvy sizePerGroup relaysAdv relayGroupsMap = Map.fromList <$> relayGroups @@ -761,9 +769,35 @@ genNonHotDiffusionScript = genDiffusionScript genLocalRootPeers )] -> Bool hasUpstream localRootPeers = - any id [ v > 0 && not (Map.null m) - | (HotValency v, _, m) <- localRootPeers - ] + or [ v > 0 && not (Map.null m) + | (HotValency v, _, m) <- localRootPeers + ] + +-- | there's some duplication of information, but saves some silly pattern +-- matches where we don't care about the particular value of RelayAccessPoint +-- +type TestnetRelayInfo = (RelayAccessPoint, IP, PortNumber, (PeerAdvertise, PeerTrustable)) +data TestnetRelayInfos = TestnetRelays4 { unTestnetRelays :: [TestnetRelayInfo] } + | TestnetRelays6 { unTestnetRelays :: [TestnetRelayInfo] } + +instance Arbitrary TestnetRelayInfos where + arbitrary = oneof [ TestnetRelays4 <$> gen PeerSelection.genIPv4 + , TestnetRelays6 <$> gen PeerSelection.genIPv6 + ] + where + uniqueIps xs = + let ips = (\(_, _, c, _) -> c) <$> xs + in length (nub ips) == length ips + + gen genIP = do + i <- choose (2,3) + (vectorOf i arbitrary >>= traverse (uncurry $ extractOrGen genIP)) `suchThat` uniqueIps + + extractOrGen genIP advTrust = \case + raa@(RelayAccessAddress ip port) -> pure (raa, ip, port, advTrust) + rad@(RelayAccessDomain _d port) -> (rad,, port, advTrust) <$> genIP + ras@(RelayAccessSRVDomain _d) -> (ras,,, advTrust) <$> genIP <*> PeerSelection.genPort + -- | Multinode Hot Diffusion Simulator Script @@ -774,26 +808,22 @@ genNonHotDiffusionScript = genDiffusionScript genLocalRootPeers -- active connections. These nodes can not randomly die or have their local -- configuration changed. Their local root peers consist of a single group. -- -genHotDiffusionScript :: RelayAccessInfosWithDNS +genHotDiffusionScript :: TestnetRelayInfos -> Gen (SimArgs, DomainMapScript, [(NodeArgs, [Command])]) genHotDiffusionScript = genDiffusionScript genLocalRootPeers where -- | Generate Local Root Peers. This only generates 1 group -- - genLocalRootPeers :: [RelayAccessInfo] - -> RelayAccessInfo + genLocalRootPeers :: [TestnetRelayInfo] + -> TestnetRelayInfo -> Gen [( HotValency , WarmValency , Map RelayAccessPoint (PeerAdvertise, PeerTrustable) )] - genLocalRootPeers relays _relay = flip suchThat hasUpstream $ do - let size = length relays - - peerAdvertise <- vectorOf size arbitrary - - let relaysAdv = zip (makeRelayAccessPoint <$> relays) peerAdvertise + genLocalRootPeers others _self = flip suchThat hasUpstream $ do + let relaysAdv = others <&> \(rap, _ip, _port, advTrust) -> (rap, advTrust) relayGroupsMap = Map.fromList relaysAdv - warmTarget = length relaysAdv + warmTarget = length relaysAdv hotTarget <- choose (0 , warmTarget) @@ -808,24 +838,23 @@ genHotDiffusionScript = genDiffusionScript genLocalRootPeers )] -> Bool hasUpstream localRootPeers = - any id [ v > 0 && not (Map.null m) - | (HotValency v, _, m) <- localRootPeers - ] + or [ v > 0 && not (Map.null m) + | (HotValency v, _, m) <- localRootPeers + ] instance Arbitrary DiffusionScript where arbitrary = (\(a,b,c) -> DiffusionScript a b c) - <$> frequency [ (1, arbitrary >>= genNonHotDiffusionScript) - , (1, arbitrary >>= genHotDiffusionScript) - ] + <$> frequency [ (1, arbitrary >>= genNonHotDiffusionScript) + , (1, arbitrary >>= genHotDiffusionScript)] -- TODO: shrink dns map -- TODO: we should write more careful shrinking than recursively shrinking -- `DiffusionScript`! shrink (DiffusionScript _ _ []) = [] shrink (DiffusionScript sargs dnsMap ((nargs, cmds):s)) = do - shrinkedCmds <- fixupCommands <$> shrinkList shrinkCommand cmds + shrunkCmds <- fixupCommands <$> shrinkList shrinkCommand cmds DiffusionScript sa dnsMap' ss <- shrink (DiffusionScript sargs dnsMap s) - return (DiffusionScript sa dnsMap' ((nargs, shrinkedCmds) : ss)) + return (DiffusionScript sa dnsMap' ((nargs, shrunkCmds) : ss)) where shrinkDelay = map fromRational . shrink . toRational @@ -1002,7 +1031,7 @@ diffusionSimulation -- ^ Node to node Snocket -> Snocket m (FD m NtCAddr) NtCAddr -- ^ Node to client Snocket - -> StrictTVar m (Map Domain [(IP, TTL)]) + -> StrictTVar m MockDNSMap -- ^ Map of domain map TVars to be updated in case a node changes its IP -> SimArgs -- ^ Simulation arguments needed in order to run a simulation -> NodeArgs -- ^ Simulation arguments needed in order to run a single node @@ -1054,7 +1083,7 @@ diffusionSimulation , WarmValency , Map RelayAccessPoint (PeerAdvertise, PeerTrustable) )] - -> StrictTVar m (Map Domain [(IP, TTL)]) + -> StrictTVar m MockDNSMap -> m Void runNode SimArgs { saSlot = bgaSlotDuration @@ -1147,11 +1176,11 @@ diffusionSimulation { Node.iNtnSnocket = ntnSnocket , Node.iNtnBearer = makeFDBearer , Node.iAcceptVersion = acceptVersion - , Node.iNtnDomainResolver = domainResolver dMapVar + , Node.iNtnDomainResolver = undefined --domainResolver dMapVar , Node.iNtcSnocket = ntcSnocket , Node.iNtcBearer = makeFDBearer , Node.iRng = rng - , Node.iDomainMap = dMapVar + , Node.iDomainMap = undefined --dMapVar , Node.iLedgerPeersConsensusInterface = LedgerPeersConsensusInterface @@ -1222,22 +1251,23 @@ diffusionSimulation `catch` \e -> traceWith (diffSimTracer addr) (TrErrored e) >> throwIO e - domainResolver :: StrictTVar m (Map Domain [(IP, TTL)]) - -> DNSLookupType - -> [DomainAccessPoint] - -> m (Map DomainAccessPoint (Set NtNAddr)) - -- TODO: we can take into account the `LookupReqs` and return only `IPv4` - -- / `IPv6` if so requested. But we should make sure the connectivity graph - -- is not severely reduced. - domainResolver dnsMapVar _ daps = do - dnsMap <- fmap (map fst) <$> atomically (readTVar dnsMapVar) - let mapDomains :: [(DomainAccessPoint, Set NtNAddr)] - mapDomains = [ ( dap - , Set.fromList [ ntnToPeerAddr a p | a <- addrs ] - ) - | dap@(DomainAccessPoint d p) <- daps - , addrs <- maybeToList (d `Map.lookup` dnsMap) ] - return (Map.fromListWith (<>) mapDomains) + -- domainResolver :: StrictTVar m (Map Domain [(IP, TTL)]) + -- -> DNSLookupType + -- -> [DomainAccessPoint] + -- -> m (Map DomainAccessPoint (Set NtNAddr)) + -- -- TODO: we can take into account the `LookupReqs` and return only `IPv4` + -- -- / `IPv6` if so requested. But we should make sure the connectivity graph + -- -- is not severely reduced. + -- domainResolver dnsMapVar _ daps = do + -- dnsMap <- fmap (map fst) <$> atomically (readTVar dnsMapVar) + -- let mapDomains :: [(DomainAccessPoint, Set NtNAddr)] + -- mapDomains = undefined + -- -- [ ( dap + -- -- , Set.fromList [ ntnToPeerAddr a p | a <- addrs ] + -- -- ) + -- -- | dap@(DomainAccessPoint d p) <- daps + -- -- , addrs <- maybeToList (d `Map.lookup` dnsMap) ] + -- return (Map.fromListWith (<>) mapDomains) diffSimTracer :: NtNAddr -> Tracer m DiffusionSimulationTrace diffSimTracer ntnAddr = contramap DiffusionDiffusionSimulationTrace diff --git a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/Testnet/Node.hs b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/Testnet/Node.hs index 27c3ba159f6..a7a2dffa615 100644 --- a/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/Testnet/Node.hs +++ b/ouroboros-network/sim-tests-lib/Test/Ouroboros/Network/Testnet/Node.hs @@ -55,7 +55,7 @@ import System.Random (StdGen, split) import Codec.CBOR.Term qualified as CBOR -import Network.DNS (Domain, TTL) +import Network.DNS (Domain, TYPE) import Ouroboros.Network.Mock.Chain (Chain, toAnchoredFragment, toOldestFirst) import Ouroboros.Network.Mock.ConcreteBlock (Block (..), BlockHeader (..), @@ -102,11 +102,11 @@ import Ouroboros.Network.PeerSelection.PeerSharing (PeerSharing (..)) import Ouroboros.Network.PeerSelection.PeerTrustable (PeerTrustable) import Ouroboros.Network.PeerSelection.RelayAccessPoint (DomainAccessPoint, RelayAccessPoint) -import Ouroboros.Network.PeerSelection.RootPeersDNS.DNSActions (DNSLookupType) +import Ouroboros.Network.PeerSelection.RootPeersDNS.DNSActions (DNSLookupType (LookupReqAAndAAAA)) import Ouroboros.Network.PeerSelection.State.LocalRootPeers (HotValency, WarmValency) import Test.Ouroboros.Network.PeerSelection.RootPeersDNS (DNSLookupDelay, - DNSTimeout, mockDNSActions) + DNSTimeout, MockDNSLookupResult, mockDNSActions) import Test.Ouroboros.Network.Testnet.Node.ChainDB (addBlock, getBlockPointSet) import Test.Ouroboros.Network.Testnet.Node.Kernel (NodeKernel (..), NtCAddr, NtCVersion, NtCVersionData, NtNAddr, NtNVersion, NtNVersionData (..)) @@ -122,7 +122,7 @@ data Interfaces m = Interfaces , iNtcSnocket :: Snocket m (NtCFD m) NtCAddr , iNtcBearer :: MakeBearer m (NtCFD m) , iRng :: StdGen - , iDomainMap :: StrictTVar m (Map Domain [(IP, TTL)]) + , iDomainMap :: StrictTVar m (Map (Domain, TYPE) MockDNSLookupResult) , iLedgerPeersConsensusInterface :: LedgerPeersConsensusInterface m , iUpdateOutboundConnectionsState @@ -242,6 +242,7 @@ run blockGeneratorArgs limits ni na tracersExtra tracerBlockFetch = , Diff.P2P.diRng = diffStgGen , Diff.P2P.diInstallSigUSR1Handler = \_ _ _ -> pure () , Diff.P2P.diDnsActions = const (mockDNSActions + LookupReqAAndAAAA (iDomainMap ni) dnsTimeoutScriptVar dnsLookupDelayScriptVar)