{-# LANGUAGE DerivingVia                #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE NamedFieldPuns             #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE StandaloneDeriving         #-}

{-# OPTIONS_GHC -Wno-orphans #-}

module Test.Ouroboros.Network.PeerSelection.Instances
  ( -- test types
    PeerAddr (..)
  , TestSeed (..)
    -- generators
  , genIPv4
  , genIPv6
  , genPort
    -- generator tests
  , prop_arbitrary_PeerSelectionTargets
  , prop_shrink_PeerSelectionTargets
  ) where

import Data.ByteString.Char8 qualified as BSC
import Data.Hashable
import Data.IP qualified as IP
import Data.Word (Word16, Word32, Word64)

import Cardano.Slotting.Slot (SlotNo (..))

import Ouroboros.Network.NodeToNode.Version (DiffusionMode (..))
import Ouroboros.Network.PeerSelection.Governor

import Ouroboros.Network.PeerSelection.LedgerPeers.Type (AfterSlot (..),
           UseLedgerPeers (..))
import Ouroboros.Network.PeerSelection.PeerAdvertise (PeerAdvertise (..))
import Ouroboros.Network.PeerSelection.PeerSharing (PeerSharing (..))
import Ouroboros.Network.PeerSelection.RelayAccessPoint
import Ouroboros.Network.PeerSelection.State.LocalRootPeers
           (LocalRootConfig (..))

import Test.Ouroboros.Network.Utils (ShrinkCarefully, prop_shrink_nonequal,
           prop_shrink_valid)
import Test.QuickCheck


--
-- QuickCheck instances
--

-- | Seed for domain lookups
--
newtype TestSeed = TestSeed { TestSeed -> Int
unTestSeed :: Int }
  deriving (TestSeed -> TestSeed -> Bool
(TestSeed -> TestSeed -> Bool)
-> (TestSeed -> TestSeed -> Bool) -> Eq TestSeed
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TestSeed -> TestSeed -> Bool
== :: TestSeed -> TestSeed -> Bool
$c/= :: TestSeed -> TestSeed -> Bool
/= :: TestSeed -> TestSeed -> Bool
Eq, Int -> TestSeed -> ShowS
[TestSeed] -> ShowS
TestSeed -> String
(Int -> TestSeed -> ShowS)
-> (TestSeed -> String) -> ([TestSeed] -> ShowS) -> Show TestSeed
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TestSeed -> ShowS
showsPrec :: Int -> TestSeed -> ShowS
$cshow :: TestSeed -> String
show :: TestSeed -> String
$cshowList :: [TestSeed] -> ShowS
showList :: [TestSeed] -> ShowS
Show)

instance Arbitrary TestSeed where
  arbitrary :: Gen TestSeed
arbitrary = Int -> TestSeed
TestSeed (Int -> TestSeed) -> Gen Int -> Gen TestSeed
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Int, Int) -> Gen Int
chooseInt(Int
forall a. Bounded a => a
minBound, Int
forall a. Bounded a => a
maxBound)
  shrink :: TestSeed -> [TestSeed]
shrink TestSeed
_ = []

-- | Simple address representation for the tests
--
newtype PeerAddr = PeerAddr Int
  deriving (PeerAddr -> PeerAddr -> Bool
(PeerAddr -> PeerAddr -> Bool)
-> (PeerAddr -> PeerAddr -> Bool) -> Eq PeerAddr
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PeerAddr -> PeerAddr -> Bool
== :: PeerAddr -> PeerAddr -> Bool
$c/= :: PeerAddr -> PeerAddr -> Bool
/= :: PeerAddr -> PeerAddr -> Bool
Eq, Eq PeerAddr
Eq PeerAddr =>
(PeerAddr -> PeerAddr -> Ordering)
-> (PeerAddr -> PeerAddr -> Bool)
-> (PeerAddr -> PeerAddr -> Bool)
-> (PeerAddr -> PeerAddr -> Bool)
-> (PeerAddr -> PeerAddr -> Bool)
-> (PeerAddr -> PeerAddr -> PeerAddr)
-> (PeerAddr -> PeerAddr -> PeerAddr)
-> Ord PeerAddr
PeerAddr -> PeerAddr -> Bool
PeerAddr -> PeerAddr -> Ordering
PeerAddr -> PeerAddr -> PeerAddr
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: PeerAddr -> PeerAddr -> Ordering
compare :: PeerAddr -> PeerAddr -> Ordering
$c< :: PeerAddr -> PeerAddr -> Bool
< :: PeerAddr -> PeerAddr -> Bool
$c<= :: PeerAddr -> PeerAddr -> Bool
<= :: PeerAddr -> PeerAddr -> Bool
$c> :: PeerAddr -> PeerAddr -> Bool
> :: PeerAddr -> PeerAddr -> Bool
$c>= :: PeerAddr -> PeerAddr -> Bool
>= :: PeerAddr -> PeerAddr -> Bool
$cmax :: PeerAddr -> PeerAddr -> PeerAddr
max :: PeerAddr -> PeerAddr -> PeerAddr
$cmin :: PeerAddr -> PeerAddr -> PeerAddr
min :: PeerAddr -> PeerAddr -> PeerAddr
Ord, Int -> PeerAddr -> ShowS
[PeerAddr] -> ShowS
PeerAddr -> String
(Int -> PeerAddr -> ShowS)
-> (PeerAddr -> String) -> ([PeerAddr] -> ShowS) -> Show PeerAddr
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PeerAddr -> ShowS
showsPrec :: Int -> PeerAddr -> ShowS
$cshow :: PeerAddr -> String
show :: PeerAddr -> String
$cshowList :: [PeerAddr] -> ShowS
showList :: [PeerAddr] -> ShowS
Show, Eq PeerAddr
Eq PeerAddr =>
(Int -> PeerAddr -> Int) -> (PeerAddr -> Int) -> Hashable PeerAddr
Int -> PeerAddr -> Int
PeerAddr -> Int
forall a. Eq a => (Int -> a -> Int) -> (a -> Int) -> Hashable a
$chashWithSalt :: Int -> PeerAddr -> Int
hashWithSalt :: Int -> PeerAddr -> Int
$chash :: PeerAddr -> Int
hash :: PeerAddr -> Int
Hashable)

-- | We mostly avoid using this instance since we need careful control over
-- the peer addrs, e.g. to make graphs work, and sets overlap etc. But it's
-- here for the few cases that need it, and it is used for (lack-of) shrinking.
--
instance Arbitrary PeerAddr where
  arbitrary :: Gen PeerAddr
arbitrary = Int -> PeerAddr
PeerAddr (Int -> PeerAddr) -> Gen Int -> Gen PeerAddr
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Int
forall a. Integral a => Gen a
arbitrarySizedNatural
  shrink :: PeerAddr -> [PeerAddr]
shrink PeerAddr
_  = []

deriving via Word64 instance Arbitrary SlotNo

instance Arbitrary PeerAdvertise where
  arbitrary :: Gen PeerAdvertise
arbitrary = [PeerAdvertise] -> Gen PeerAdvertise
forall a. [a] -> Gen a
elements [ PeerAdvertise
DoAdvertisePeer, PeerAdvertise
DoNotAdvertisePeer ]

  shrink :: PeerAdvertise -> [PeerAdvertise]
shrink PeerAdvertise
DoAdvertisePeer    = []
  shrink PeerAdvertise
DoNotAdvertisePeer = [PeerAdvertise
DoAdvertisePeer]

instance Arbitrary PeerSharing where
  arbitrary :: Gen PeerSharing
arbitrary = [PeerSharing] -> Gen PeerSharing
forall a. [a] -> Gen a
elements [ PeerSharing
PeerSharingDisabled, PeerSharing
PeerSharingEnabled ]
  shrink :: PeerSharing -> [PeerSharing]
shrink PeerSharing
PeerSharingDisabled = []
  shrink PeerSharing
PeerSharingEnabled  = [PeerSharing
PeerSharingDisabled]

instance Arbitrary AfterSlot where
  arbitrary :: Gen AfterSlot
arbitrary = [Gen AfterSlot] -> Gen AfterSlot
forall a. [Gen a] -> Gen a
oneof [ AfterSlot -> Gen AfterSlot
forall a. a -> Gen a
forall (f :: * -> *) a. Applicative f => a -> f a
pure AfterSlot
Always
                    , SlotNo -> AfterSlot
After (SlotNo -> AfterSlot) -> Gen SlotNo -> Gen AfterSlot
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen SlotNo
forall a. Arbitrary a => Gen a
arbitrary
                    ]

instance Arbitrary UseLedgerPeers where
    arbitrary :: Gen UseLedgerPeers
arbitrary = [(Int, Gen UseLedgerPeers)] -> Gen UseLedgerPeers
forall a. [(Int, Gen a)] -> Gen a
frequency
      [ (Int
2, UseLedgerPeers -> Gen UseLedgerPeers
forall a. a -> Gen a
forall (f :: * -> *) a. Applicative f => a -> f a
pure UseLedgerPeers
DontUseLedgerPeers)
      , (Int
8, AfterSlot -> UseLedgerPeers
UseLedgerPeers (AfterSlot -> UseLedgerPeers)
-> Gen AfterSlot -> Gen UseLedgerPeers
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen AfterSlot
forall a. Arbitrary a => Gen a
arbitrary)
      ]

instance Arbitrary PeerSelectionTargets where
  arbitrary :: Gen PeerSelectionTargets
arbitrary = do
    targetNumberOfKnownPeers       <- NonNegative Int -> Int
forall a. NonNegative a -> a
getNonNegative (NonNegative Int -> Int) -> Gen (NonNegative Int) -> Gen Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Gen (NonNegative Int) -> Gen (NonNegative Int)
forall a. Int -> Gen a -> Gen a
resize Int
1000 Gen (NonNegative Int)
forall a. Arbitrary a => Gen a
arbitrary
    targetNumberOfRootPeers        <- choose (0, min 100  targetNumberOfKnownPeers)
    targetNumberOfEstablishedPeers <- choose (0, min 1000 targetNumberOfKnownPeers)
    targetNumberOfActivePeers      <- choose (0, min 100  targetNumberOfEstablishedPeers)

    targetNumberOfKnownBigLedgerPeers
      <- getNonNegative <$> resize 1000 arbitrary
    targetNumberOfEstablishedBigLedgerPeers
      <- choose (0 , min 1000 targetNumberOfKnownBigLedgerPeers)
    targetNumberOfActiveBigLedgerPeers
      <- choose (0, min 100 targetNumberOfEstablishedBigLedgerPeers)

    return PeerSelectionTargets {
      targetNumberOfRootPeers,
      targetNumberOfKnownPeers,
      targetNumberOfEstablishedPeers,
      targetNumberOfActivePeers,
      targetNumberOfKnownBigLedgerPeers,
      targetNumberOfEstablishedBigLedgerPeers,
      targetNumberOfActiveBigLedgerPeers
    }

  shrink :: PeerSelectionTargets -> [PeerSelectionTargets]
shrink (PeerSelectionTargets Int
r Int
k Int
e Int
a Int
kb Int
eb Int
ab) =
    [ PeerSelectionTargets
targets'
    | (Int
r',Int
k',Int
e',Int
a',Int
kb',Int
eb',Int
ab') <- (Int, Int, Int, Int, Int, Int, Int)
-> [(Int, Int, Int, Int, Int, Int, Int)]
forall a. Arbitrary a => a -> [a]
shrink (Int
r,Int
k,Int
e,Int
a,Int
kb,Int
eb,Int
ab)
    , let targets' :: PeerSelectionTargets
targets' = Int
-> Int -> Int -> Int -> Int -> Int -> Int -> PeerSelectionTargets
PeerSelectionTargets Int
r' Int
k' Int
e' Int
a' Int
kb' Int
eb' Int
ab'
    , PeerSelectionTargets -> Bool
sanePeerSelectionTargets PeerSelectionTargets
targets' ]

genIPv4 :: Gen IP.IP
genIPv4 :: Gen IP
genIPv4 =
    IPv4 -> IP
IP.IPv4 (IPv4 -> IP) -> (Word32 -> IPv4) -> Word32 -> IP
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> IPv4
IP.toIPv4w (Word32 -> IP) -> Gen Word32 -> Gen IP
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Gen Word32 -> Gen Word32
forall a. Int -> Gen a -> Gen a
resize Int
200 Gen Word32
forall a. Arbitrary a => Gen a
arbitrary Gen Word32 -> (Word32 -> Bool) -> Gen Word32
forall a. Gen a -> (a -> Bool) -> Gen a
`suchThat` (Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
> Word32
100)

genPort :: Gen PortNumber
genPort :: Gen PortNumber
genPort =
    Word16 -> PortNumber
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16 -> PortNumber) -> Gen Word16 -> Gen PortNumber
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Gen Word16
forall a. Arbitrary a => Gen a
arbitrary :: Gen Word16)

genIPv6 :: Gen IP.IP
genIPv6 :: Gen IP
genIPv6 =
    IPv6 -> IP
IP.IPv6 (IPv6 -> IP)
-> ((Word32, Word32, Word32, Word32) -> IPv6)
-> (Word32, Word32, Word32, Word32)
-> IP
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word32, Word32, Word32, Word32) -> IPv6
IP.toIPv6w ((Word32, Word32, Word32, Word32) -> IP)
-> Gen (Word32, Word32, Word32, Word32) -> Gen IP
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen (Word32, Word32, Word32, Word32)
genFourWord32
  where
    genFourWord32 :: Gen (Word32, Word32, Word32, Word32)
    genFourWord32 :: Gen (Word32, Word32, Word32, Word32)
genFourWord32 =
       (,,,) (Word32
 -> Word32 -> Word32 -> Word32 -> (Word32, Word32, Word32, Word32))
-> Gen Word32
-> Gen
     (Word32 -> Word32 -> Word32 -> (Word32, Word32, Word32, Word32))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Gen Word32 -> Gen Word32
forall a. Int -> Gen a -> Gen a
resize Int
200 Gen Word32
forall a. Arbitrary a => Gen a
arbitrary Gen Word32 -> (Word32 -> Bool) -> Gen Word32
forall a. Gen a -> (a -> Bool) -> Gen a
`suchThat` (Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
> Word32
100)
             Gen
  (Word32 -> Word32 -> Word32 -> (Word32, Word32, Word32, Word32))
-> Gen Word32
-> Gen (Word32 -> Word32 -> (Word32, Word32, Word32, Word32))
forall a b. Gen (a -> b) -> Gen a -> Gen b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Word32
forall a. Arbitrary a => Gen a
arbitrary
             Gen (Word32 -> Word32 -> (Word32, Word32, Word32, Word32))
-> Gen Word32 -> Gen (Word32 -> (Word32, Word32, Word32, Word32))
forall a b. Gen (a -> b) -> Gen a -> Gen b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Word32
forall a. Arbitrary a => Gen a
arbitrary
             Gen (Word32 -> (Word32, Word32, Word32, Word32))
-> Gen Word32 -> Gen (Word32, Word32, Word32, Word32)
forall a b. Gen (a -> b) -> Gen a -> Gen b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Word32
forall a. Arbitrary a => Gen a
arbitrary

instance Arbitrary RelayAccessPoint where
  arbitrary :: Gen RelayAccessPoint
arbitrary =
      [(Int, Gen RelayAccessPoint)] -> Gen RelayAccessPoint
forall a. [(Int, Gen a)] -> Gen a
frequency [ (Int
4, IP -> PortNumber -> RelayAccessPoint
RelayAccessAddress (IP -> PortNumber -> RelayAccessPoint)
-> Gen IP -> Gen (PortNumber -> RelayAccessPoint)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Gen IP] -> Gen IP
forall a. [Gen a] -> Gen a
oneof [Gen IP
genIPv4, Gen IP
genIPv6] Gen (PortNumber -> RelayAccessPoint)
-> Gen PortNumber -> Gen RelayAccessPoint
forall a b. Gen (a -> b) -> Gen a -> Gen b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen PortNumber
genPort)
                , (Int
4, Domain -> PortNumber -> RelayAccessPoint
RelayAccessDomain (Domain -> PortNumber -> RelayAccessPoint)
-> Gen Domain -> Gen (PortNumber -> RelayAccessPoint)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Domain
genDomainName Gen (PortNumber -> RelayAccessPoint)
-> Gen PortNumber -> Gen RelayAccessPoint
forall a b. Gen (a -> b) -> Gen a -> Gen b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen PortNumber
genPort)
                , (Int
1, Domain -> RelayAccessPoint
RelayAccessSRVDomain (Domain -> RelayAccessPoint) -> Gen Domain -> Gen RelayAccessPoint
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Domain
genDomainName)]
    where
      genDomainName :: Gen Domain
genDomainName = [Domain] -> Gen Domain
forall a. [a] -> Gen a
elements ([Domain] -> Gen Domain) -> [Domain] -> Gen Domain
forall a b. (a -> b) -> a -> b
$ (\Int
i -> Domain
"test" Domain -> Domain -> Domain
forall a. Semigroup a => a -> a -> a
<> (String -> Domain
BSC.pack (String -> Domain) -> (Int -> String) -> Int -> Domain
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show (Int -> Domain) -> Int -> Domain
forall a b. (a -> b) -> a -> b
$ Int
i)) (Int -> Domain) -> [Int] -> [Domain]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Int
1..Int
6 :: Int]

prop_arbitrary_PeerSelectionTargets :: PeerSelectionTargets -> Bool
prop_arbitrary_PeerSelectionTargets :: PeerSelectionTargets -> Bool
prop_arbitrary_PeerSelectionTargets =
    PeerSelectionTargets -> Bool
sanePeerSelectionTargets

prop_shrink_PeerSelectionTargets :: ShrinkCarefully PeerSelectionTargets -> Property
prop_shrink_PeerSelectionTargets :: ShrinkCarefully PeerSelectionTargets -> Property
prop_shrink_PeerSelectionTargets ShrinkCarefully PeerSelectionTargets
x =
      (PeerSelectionTargets -> Bool)
-> ShrinkCarefully PeerSelectionTargets -> Property
forall a prop.
(Arbitrary a, Show a, Testable prop) =>
(a -> prop) -> ShrinkCarefully a -> Property
prop_shrink_valid PeerSelectionTargets -> Bool
sanePeerSelectionTargets ShrinkCarefully PeerSelectionTargets
x
 Property -> Property -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. ShrinkCarefully PeerSelectionTargets -> Property
forall a.
(Arbitrary a, Eq a, Show a) =>
ShrinkCarefully a -> Property
prop_shrink_nonequal ShrinkCarefully PeerSelectionTargets
x


instance Arbitrary extraFlags => Arbitrary (LocalRootConfig extraFlags) where
  arbitrary :: Gen (LocalRootConfig extraFlags)
arbitrary = PeerAdvertise
-> DiffusionMode -> extraFlags -> LocalRootConfig extraFlags
forall extraFlags.
PeerAdvertise
-> DiffusionMode -> extraFlags -> LocalRootConfig extraFlags
LocalRootConfig
                (PeerAdvertise
 -> DiffusionMode -> extraFlags -> LocalRootConfig extraFlags)
-> Gen PeerAdvertise
-> Gen (DiffusionMode -> extraFlags -> LocalRootConfig extraFlags)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen PeerAdvertise
forall a. Arbitrary a => Gen a
arbitrary
                Gen (DiffusionMode -> extraFlags -> LocalRootConfig extraFlags)
-> Gen DiffusionMode
-> Gen (extraFlags -> LocalRootConfig extraFlags)
forall a b. Gen (a -> b) -> Gen a -> Gen b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [DiffusionMode] -> Gen DiffusionMode
forall a. [a] -> Gen a
elements [DiffusionMode
InitiatorAndResponderDiffusionMode, DiffusionMode
InitiatorOnlyDiffusionMode]
                Gen (extraFlags -> LocalRootConfig extraFlags)
-> Gen extraFlags -> Gen (LocalRootConfig extraFlags)
forall a b. Gen (a -> b) -> Gen a -> Gen b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen extraFlags
forall a. Arbitrary a => Gen a
arbitrary
  shrink :: LocalRootConfig extraFlags -> [LocalRootConfig extraFlags]
shrink a :: LocalRootConfig extraFlags
a@LocalRootConfig { PeerAdvertise
peerAdvertise :: PeerAdvertise
peerAdvertise :: forall extraFlags. LocalRootConfig extraFlags -> PeerAdvertise
peerAdvertise, extraFlags
extraFlags :: extraFlags
extraFlags :: forall extraFlags. LocalRootConfig extraFlags -> extraFlags
extraFlags, DiffusionMode
diffusionMode :: DiffusionMode
diffusionMode :: forall extraFlags. LocalRootConfig extraFlags -> DiffusionMode
diffusionMode } =
    [ LocalRootConfig extraFlags
a { extraFlags = peerTrustable' }
    | extraFlags
peerTrustable' <- extraFlags -> [extraFlags]
forall a. Arbitrary a => a -> [a]
shrink extraFlags
extraFlags
    ]
    [LocalRootConfig extraFlags]
-> [LocalRootConfig extraFlags] -> [LocalRootConfig extraFlags]
forall a. [a] -> [a] -> [a]
++
    [ LocalRootConfig extraFlags
a { peerAdvertise = peerAdvertise' }
    | PeerAdvertise
peerAdvertise' <- PeerAdvertise -> [PeerAdvertise]
forall a. Arbitrary a => a -> [a]
shrink PeerAdvertise
peerAdvertise
    ]
    [LocalRootConfig extraFlags]
-> [LocalRootConfig extraFlags] -> [LocalRootConfig extraFlags]
forall a. [a] -> [a] -> [a]
++
    [ LocalRootConfig extraFlags
a { diffusionMode = diffusionMode' }
    | DiffusionMode
diffusionMode' <- case DiffusionMode
diffusionMode of
        DiffusionMode
InitiatorOnlyDiffusionMode         -> []
        DiffusionMode
InitiatorAndResponderDiffusionMode -> [DiffusionMode
InitiatorOnlyDiffusionMode]
    ]