Skip to content

Commit 3974c04

Browse files
authored
Merge pull request #6263 from IntersectMBO/nb/refactor_topology
Enable P2P topology in `cardano-testnet`
2 parents ed274de + 38db4bf commit 3974c04

File tree

22 files changed

+389
-114
lines changed

22 files changed

+389
-114
lines changed

cardano-node/src/Cardano/Node/Configuration/Topology.hs

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
{-# LANGUAGE DeriveGeneric #-}
2+
{-# LANGUAGE DeriveTraversable #-}
3+
{-# LANGUAGE FlexibleContexts #-}
4+
{-# LANGUAGE FlexibleInstances #-}
15
{-# LANGUAGE OverloadedStrings #-}
26

37
module Cardano.Node.Configuration.Topology
@@ -30,6 +34,7 @@ import Data.Foldable
3034
import Data.Text (Text)
3135
import qualified Data.Text as Text
3236
import Data.Word (Word64)
37+
import GHC.Generics (Generic)
3338
import Text.Read (readMaybe)
3439

3540

@@ -52,7 +57,6 @@ data RemoteAddress = RemoteAddress
5257
-- a Boolean value, @0@ means to ignore the address;
5358
} deriving (Eq, Ord, Show)
5459

55-
5660
-- | Parse 'raAddress' field as an IP address; if it parses and the valency is
5761
-- non zero return corresponding NodeAddress.
5862
--
@@ -88,22 +92,22 @@ instance ToJSON RemoteAddress where
8892
, "valency" .= raValency ra
8993
]
9094

91-
data NodeSetup = NodeSetup
95+
data NodeSetup adr = NodeSetup
9296
{ nodeId :: !Word64
9397
, nodeIPv4Address :: !(Maybe NodeIPv4Address)
9498
, nodeIPv6Address :: !(Maybe NodeIPv6Address)
95-
, producers :: ![RemoteAddress]
96-
} deriving (Eq, Show)
99+
, producers :: ![adr]
100+
} deriving (Eq, Show, Generic, Functor, Foldable, Traversable)
97101

98-
instance FromJSON NodeSetup where
102+
instance (FromJSON adr) => FromJSON (NodeSetup adr) where
99103
parseJSON = withObject "NodeSetup" $ \o ->
100104
NodeSetup
101105
<$> o .: "nodeId"
102106
<*> o .: "nodeIPv4Address"
103107
<*> o .: "nodeIPv6Address"
104108
<*> o .: "producers"
105109

106-
instance ToJSON NodeSetup where
110+
instance (ToJSON adr) => ToJSON (NodeSetup adr) where
107111
toJSON ns =
108112
object
109113
[ "nodeId" .= nodeId ns
@@ -112,17 +116,23 @@ instance ToJSON NodeSetup where
112116
, "producers" .= producers ns
113117
]
114118

115-
data NetworkTopology = MockNodeTopology ![NodeSetup]
116-
| RealNodeTopology ![RemoteAddress]
117-
deriving (Eq, Show)
118-
119-
instance FromJSON NetworkTopology where
119+
-- | Describes the non-P2P topology of a node. Whenever the node actually runs,
120+
-- the type parameter `adr` should be `RemoteAddress`. However, we might want to
121+
-- use and serialize this type with `adr` being `NodeId`, or another placeholder
122+
-- type, if we want the user to be able to edit the topology without knowing the
123+
-- actual addresses of the nodes: those might only be knowable at runtime.
124+
data NetworkTopology adr
125+
= MockNodeTopology ![NodeSetup adr]
126+
| RealNodeTopology ![adr]
127+
deriving (Eq, Show, Generic, Functor, Foldable, Traversable)
128+
129+
instance (FromJSON adr) => FromJSON (NetworkTopology adr) where
120130
parseJSON = withObject "NetworkTopology" $ \o -> asum
121131
[ MockNodeTopology <$> o .: "MockProducers"
122132
, RealNodeTopology <$> o .: "Producers"
123133
]
124134

125-
instance ToJSON NetworkTopology where
135+
instance (ToJSON adr) => ToJSON (NetworkTopology adr) where
126136
toJSON top =
127137
case top of
128138
MockNodeTopology nss -> object [ "MockProducers" .= toJSON nss ]
@@ -131,7 +141,10 @@ instance ToJSON NetworkTopology where
131141
-- | Read the `NetworkTopology` configuration from the specified file.
132142
-- While running a real protocol, this gives your node its own address and
133143
-- other remote peers it will attempt to connect to.
134-
readTopologyFile :: NodeConfiguration -> IO (Either Text NetworkTopology)
144+
readTopologyFile :: ()
145+
=> (FromJSON adr)
146+
=> NodeConfiguration
147+
-> IO (Either Text (NetworkTopology adr))
135148
readTopologyFile nc = do
136149
eBs <- Exception.try $ BS.readFile (unTopology $ ncTopologyFile nc)
137150

@@ -154,7 +167,10 @@ readTopologyFile nc = do
154167
, Text.pack err
155168
]
156169

157-
readTopologyFileOrError :: NodeConfiguration -> IO NetworkTopology
170+
readTopologyFileOrError :: ()
171+
=> (FromJSON adr)
172+
=> NodeConfiguration
173+
-> IO (NetworkTopology adr)
158174
readTopologyFileOrError nc =
159175
readTopologyFile nc
160176
>>= either (\err -> error $ "Cardano.Node.Configuration.Topology.readTopologyFile: "

cardano-node/src/Cardano/Node/Configuration/TopologyP2P.hs

Lines changed: 56 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
{-# LANGUAGE DeriveGeneric #-}
2+
{-# LANGUAGE DeriveTraversable #-}
13
{-# LANGUAGE FlexibleContexts #-}
24
{-# LANGUAGE FlexibleInstances #-}
35
{-# LANGUAGE NamedFieldPuns #-}
46
{-# LANGUAGE OverloadedStrings #-}
57
{-# LANGUAGE PackageImports #-}
8+
{-# LANGUAGE RankNTypes #-}
69

710
module Cardano.Node.Configuration.TopologyP2P
811
( TopologyError(..)
@@ -38,7 +41,6 @@ import Cardano.Tracing.OrphanInstances.Network ()
3841
import Ouroboros.Network.NodeToNode (DiffusionMode (..), PeerAdvertise (..))
3942
import Ouroboros.Network.PeerSelection.LedgerPeers.Type (LedgerPeerSnapshot (..),
4043
UseLedgerPeers (..))
41-
import Ouroboros.Network.PeerSelection.RelayAccessPoint (RelayAccessPoint (..))
4244
import Ouroboros.Network.PeerSelection.State.LocalRootPeers (HotValency (..),
4345
WarmValency (..))
4446

@@ -54,17 +56,18 @@ import qualified Data.ByteString.Lazy.Char8 as LBS
5456
import Data.Text (Text)
5557
import qualified Data.Text as Text
5658
import Data.Word (Word64)
59+
import GHC.Generics (Generic)
5760
import System.FilePath (takeDirectory, (</>))
5861

59-
data NodeSetup = NodeSetup
62+
data NodeSetup adr = NodeSetup
6063
{ nodeId :: !Word64
6164
, nodeIPv4Address :: !(Maybe NodeIPv4Address)
6265
, nodeIPv6Address :: !(Maybe NodeIPv6Address)
63-
, producers :: ![RootConfig]
66+
, producers :: ![RootConfig adr]
6467
, useLedger :: !UseLedgerPeers
65-
} deriving (Eq, Show)
68+
} deriving (Eq, Show, Generic, Functor, Foldable, Traversable)
6669

67-
instance FromJSON NodeSetup where
70+
instance FromJSON adr => FromJSON (NodeSetup adr) where
6871
parseJSON = withObject "NodeSetup" $ \o ->
6972
NodeSetup
7073
<$> o .: "nodeId"
@@ -73,7 +76,7 @@ instance FromJSON NodeSetup where
7376
<*> o .: "producers"
7477
<*> o .:? "useLedgerAfterSlot" .!= DontUseLedgerPeers
7578

76-
instance ToJSON NodeSetup where
79+
instance ToJSON adr => ToJSON (NodeSetup adr) where
7780
toJSON ns =
7881
object
7982
[ "nodeId" .= nodeId ns
@@ -87,22 +90,22 @@ instance ToJSON NodeSetup where
8790
-- | Each root peer consists of a list of access points and a shared
8891
-- 'PeerAdvertise' field.
8992
--
90-
data RootConfig = RootConfig
91-
{ rootAccessPoints :: [RelayAccessPoint]
93+
data RootConfig adr = RootConfig
94+
{ rootAccessPoints :: [adr]
9295
-- ^ a list of relay access points, each of which is either an ip address
9396
-- or domain name and a port number.
9497
, rootAdvertise :: PeerAdvertise
9598
-- ^ 'advertise' configures whether the root should be advertised through
9699
-- peer sharing.
97-
} deriving (Eq, Show)
100+
} deriving (Eq, Show, Generic, Functor, Foldable, Traversable)
98101

99-
instance FromJSON RootConfig where
102+
instance FromJSON adr => FromJSON (RootConfig adr) where
100103
parseJSON = withObject "RootConfig" $ \o ->
101104
RootConfig
102105
<$> o .: "accessPoints"
103106
<*> o .:? "advertise" .!= DoNotAdvertisePeer
104107

105-
instance ToJSON RootConfig where
108+
instance ToJSON adr => ToJSON (RootConfig adr) where
106109
toJSON ra =
107110
object
108111
[ "accessPoints" .= rootAccessPoints ra
@@ -112,9 +115,9 @@ instance ToJSON RootConfig where
112115
-- | Transforms a 'RootConfig' into a pair of 'RelayAccessPoint' and its
113116
-- corresponding 'PeerAdvertise' value.
114117
--
115-
rootConfigToRelayAccessPoint
116-
:: RootConfig
117-
-> [(RelayAccessPoint, PeerAdvertise)]
118+
rootConfigToRelayAccessPoint :: ()
119+
=> forall adr. RootConfig adr
120+
-> [(adr, PeerAdvertise)]
118121
rootConfigToRelayAccessPoint RootConfig { rootAccessPoints, rootAdvertise } =
119122
[ (accessPoint, rootAdvertise) | accessPoint <- rootAccessPoints ]
120123

@@ -125,21 +128,21 @@ rootConfigToRelayAccessPoint RootConfig { rootAccessPoints, rootAdvertise } =
125128
-- 'warmValency' value is the value of warm/established connections that the node
126129
-- will attempt to maintain. By default this value will be equal to 'hotValency'.
127130
--
128-
data LocalRootPeersGroup = LocalRootPeersGroup
129-
{ localRoots :: RootConfig
131+
data LocalRootPeersGroup adr = LocalRootPeersGroup
132+
{ localRoots :: RootConfig adr
130133
, hotValency :: HotValency
131134
, warmValency :: WarmValency
132135
, trustable :: PeerTrustable
133136
-- ^ 'trustable' configures whether the root should be trusted in fallback
134137
-- state.
135138
, rootDiffusionMode :: DiffusionMode
136139
-- ^ diffusion mode; used for local root peers.
137-
} deriving (Eq, Show)
140+
} deriving (Eq, Show, Generic, Functor, Foldable, Traversable)
138141

139142
-- | Does not use the 'FromJSON' instance of 'RootConfig', so that
140143
-- 'accessPoints', 'advertise', 'valency' and 'warmValency' fields are attached to the
141144
-- same object.
142-
instance FromJSON LocalRootPeersGroup where
145+
instance FromJSON adr => FromJSON (LocalRootPeersGroup adr) where
143146
parseJSON = withObject "LocalRootPeersGroup" $ \o -> do
144147
hv@(HotValency v) <- o .: "valency"
145148
<|> o .: "hotValency"
@@ -152,7 +155,7 @@ instance FromJSON LocalRootPeersGroup where
152155
<*> (maybe InitiatorAndResponderDiffusionMode getDiffusionMode
153156
<$> o .:? "diffusionMode")
154157

155-
instance ToJSON LocalRootPeersGroup where
158+
instance ToJSON adr => ToJSON (LocalRootPeersGroup adr) where
156159
toJSON lrpg =
157160
object
158161
[ "accessPoints" .= rootAccessPoints (localRoots lrpg)
@@ -164,47 +167,53 @@ instance ToJSON LocalRootPeersGroup where
164167
, "diffusionMode" .= NodeDiffusionMode (rootDiffusionMode lrpg)
165168
]
166169

167-
newtype LocalRootPeersGroups = LocalRootPeersGroups
168-
{ groups :: [LocalRootPeersGroup]
169-
} deriving (Eq, Show)
170+
newtype LocalRootPeersGroups adr = LocalRootPeersGroups
171+
{ groups :: [LocalRootPeersGroup adr]
172+
} deriving (Eq, Show, Generic, Functor, Foldable, Traversable)
170173

171-
instance FromJSON LocalRootPeersGroups where
174+
instance FromJSON adr => FromJSON (LocalRootPeersGroups adr) where
172175
parseJSON = fmap LocalRootPeersGroups . parseJSONList
173176

174-
instance ToJSON LocalRootPeersGroups where
177+
instance ToJSON adr => ToJSON (LocalRootPeersGroups adr) where
175178
toJSON = toJSONList . groups
176179

177-
newtype PublicRootPeers = PublicRootPeers
178-
{ publicRoots :: RootConfig
179-
} deriving (Eq, Show)
180+
newtype PublicRootPeers adr = PublicRootPeers
181+
{ publicRoots :: RootConfig adr
182+
} deriving (Eq, Show, Generic, Functor, Foldable, Traversable)
180183

181-
instance FromJSON PublicRootPeers where
184+
instance FromJSON adr => FromJSON (PublicRootPeers adr) where
182185
parseJSON = fmap PublicRootPeers . parseJSON
183186

184-
instance ToJSON PublicRootPeers where
187+
instance ToJSON adr => ToJSON (PublicRootPeers adr) where
185188
toJSON = toJSON . publicRoots
186189

187-
data NetworkTopology = RealNodeTopology { ntLocalRootPeersGroups :: !LocalRootPeersGroups
188-
, ntPublicRootPeers :: ![PublicRootPeers]
189-
, ntUseLedgerPeers :: !UseLedgerPeers
190-
, ntUseBootstrapPeers :: !UseBootstrapPeers
191-
, ntPeerSnapshotPath :: !(Maybe PeerSnapshotFile)
192-
}
193-
deriving (Eq, Show)
194-
195-
instance AdjustFilePaths NetworkTopology where
190+
-- | Describes the P2P topology of a node. Whenever the node actually runs,
191+
-- the type parameter `adr` should be `RelayAccessPoint`. However, we might want to
192+
-- use and serialize this type with `adr` being `NodeId`, or another placeholder
193+
-- type, if we want the user to be able to edit the topology without knowing the
194+
-- actual addresses of the nodes: those might only be knowable at runtime.
195+
data NetworkTopology adr = RealNodeTopology
196+
{ ntLocalRootPeersGroups :: !(LocalRootPeersGroups adr)
197+
, ntPublicRootPeers :: ![PublicRootPeers adr]
198+
, ntUseLedgerPeers :: !UseLedgerPeers
199+
, ntUseBootstrapPeers :: !UseBootstrapPeers
200+
, ntPeerSnapshotPath :: !(Maybe PeerSnapshotFile)
201+
}
202+
deriving (Eq, Show, Generic, Functor, Foldable, Traversable)
203+
204+
instance AdjustFilePaths (NetworkTopology adr) where
196205
adjustFilePaths f nt@(RealNodeTopology _ _ _ _ mPeerSnapshotPath) =
197206
nt{ntPeerSnapshotPath = PeerSnapshotFile . f . unPeerSnapshotFile <$> mPeerSnapshotPath}
198207

199-
instance FromJSON NetworkTopology where
208+
instance FromJSON adr => FromJSON (NetworkTopology adr) where
200209
parseJSON = withObject "NetworkTopology" $ \o ->
201210
RealNodeTopology <$> (o .: "localRoots" )
202211
<*> (o .: "publicRoots" )
203212
<*> (o .:? "useLedgerAfterSlot" .!= DontUseLedgerPeers )
204213
<*> (o .:? "bootstrapPeers" .!= DontUseBootstrapPeers )
205214
<*> (o .:? "peerSnapshotFile")
206215

207-
instance ToJSON NetworkTopology where
216+
instance ToJSON adr => ToJSON (NetworkTopology adr) where
208217
toJSON top =
209218
case top of
210219
RealNodeTopology { ntLocalRootPeersGroups
@@ -220,7 +229,9 @@ instance ToJSON NetworkTopology where
220229
]
221230

222231
-- | Read the `NetworkTopology` configuration from the specified file.
223-
readTopologyFile :: NodeConfiguration -> CT.Tracer IO (StartupTrace blk) -> IO (Either Text NetworkTopology)
232+
readTopologyFile :: ()
233+
=> forall adr. FromJSON adr
234+
=> NodeConfiguration -> CT.Tracer IO (StartupTrace blk) -> IO (Either Text (NetworkTopology adr))
224235
readTopologyFile NodeConfiguration{ncTopologyFile=TopologyFile topologyFilePath, ncConsensusMode} tracer = runExceptT $ do
225236
bs <- handleIOExceptionsLiftWith handler $ BS.readFile topologyFilePath
226237
topology@RealNodeTopology{ntUseBootstrapPeers} <-
@@ -269,7 +280,9 @@ readTopologyFile NodeConfiguration{ncTopologyFile=TopologyFile topologyFilePath,
269280
isGenesisCompatible GenesisMode UseBootstrapPeers{} = False
270281
isGenesisCompatible _ _ = True
271282

272-
readTopologyFileOrError :: NodeConfiguration -> CT.Tracer IO (StartupTrace blk) -> IO NetworkTopology
283+
readTopologyFileOrError :: ()
284+
=> forall adr. FromJSON adr
285+
=> NodeConfiguration -> CT.Tracer IO (StartupTrace blk) -> IO (NetworkTopology adr)
273286
readTopologyFileOrError nc tr =
274287
readTopologyFile nc tr
275288
>>= either (\err -> error $ "Cardano.Node.Configuration.TopologyP2P.readTopologyFile: "
@@ -289,7 +302,7 @@ readPeerSnapshotFile (PeerSnapshotFile peerSnapshotFile) =
289302

290303
-- | This function returns false if non-trustable peers are configured
291304
--
292-
isValidTrustedPeerConfiguration :: NetworkTopology -> Bool
305+
isValidTrustedPeerConfiguration :: NetworkTopology adr -> Bool
293306
isValidTrustedPeerConfiguration (RealNodeTopology (LocalRootPeersGroups lprgs) _ _ ubp _) =
294307
case ubp of
295308
DontUseBootstrapPeers -> True

cardano-node/src/Cardano/Node/Run.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,7 +1115,7 @@ mkNonP2PArguments daIpProducers daDnsProducers =
11151115
-- | TODO: Only needed for enabling P2P switch
11161116
--
11171117
producerAddressesNonP2P
1118-
:: TopologyNonP2P.NetworkTopology
1118+
:: TopologyNonP2P.NetworkTopology TopologyNonP2P.RemoteAddress
11191119
-> ( [NodeIPAddress]
11201120
, [(NodeDnsAddress, Int)])
11211121
producerAddressesNonP2P nt =
@@ -1133,7 +1133,7 @@ producerAddressesNonP2P nt =
11331133
$ nodeSetup
11341134

11351135
producerAddresses
1136-
:: NetworkTopology
1136+
:: NetworkTopology RelayAccessPoint
11371137
-> ( [(HotValency, WarmValency, Map RelayAccessPoint (LocalRootConfig PeerTrustable))]
11381138
, Map RelayAccessPoint PeerAdvertise
11391139
)

0 commit comments

Comments
 (0)