From f7799e7f3b85e37e12f1a2251467551f7ff949ff Mon Sep 17 00:00:00 2001 From: Marcin Szamotulski Date: Fri, 6 Dec 2024 06:48:26 +0100 Subject: [PATCH] Added diffusionMode to local root peers group configuration "diffusionMode" can be either `"InitiatorOnly"` or `"InitiatorAndResponder"`. If not given, the latter is the default - for backward compatibility. When "InitiatorOnly" is used, the connections to these local roots will only negotiate `InitiatorOnly` mode (it won't be possible to be reused by the other side) and will not bind to the server address, e.g. it will be made from an ephemeral port. See https://github.com/IntersectMBO/ouroboros-network/issues/5020 why this feature was requested by some SPOs. An example configuration: ```json { "localRoots": [ { "accessPoints": [ { "address": "10.0.0.1" , "port": 3001 } ] , "advertise": false , "diffusionMode": "InitiatorOnly" , "warmValency": 1 , "hotValency": 1 } , { "accessPoints": [ { "address": "10.0.0.2" , "port": 3001 } ] , "advertise": true , "diffusionMode": "InititiatorAndResponder" , "warmValency": 1 , "hotValency": 1 } ] , "publicRoots": [] , "useLedgerAfterSlot": -1 } ``` --- cabal.project | 7 ++++ .../Cardano/Node/Configuration/TopologyP2P.hs | 16 ++++++--- cardano-node/src/Cardano/Node/Run.hs | 34 +++++++++++++------ cardano-node/src/Cardano/Node/Startup.hs | 5 ++- .../src/Cardano/Node/Tracing/Tracers/P2P.hs | 6 ++-- cardano-node/src/Cardano/Node/Types.hs | 11 ++++-- .../Tracing/OrphanInstances/Network.hs | 27 +++++++++++++-- cardano-node/src/Cardano/Tracing/Tracers.hs | 1 + .../src/Testnet/Components/Configuration.hs | 2 ++ 9 files changed, 86 insertions(+), 23 deletions(-) diff --git a/cabal.project b/cabal.project index b2d4ead9872..57f900a4f06 100644 --- a/cabal.project +++ b/cabal.project @@ -154,3 +154,10 @@ source-repository-package location: https://github.com/neilmayhew/ekg-forward.git tag: 4ba8bb693093f6cf54d43d6e9bbce1e08b0457dd --sha256: sha256-g0gYqzRGjmZwxEzihJ4JifJe+GRfdLIMzaot7rUcjlI= + +source-repository-package + type: git + location: https://github.com/input-output-hk/io-sim + tag: 586ddf6b52be1bbc78f9c659907f8e3fa13ccffe + --sha256: sha256-HaCWLHhseTQsTgShuh6tM52NpS558jcPgpQZ0YTBgj4= + subdir: io-sim diff --git a/cardano-node/src/Cardano/Node/Configuration/TopologyP2P.hs b/cardano-node/src/Cardano/Node/Configuration/TopologyP2P.hs index dfad181fa7f..bc7656c7fc4 100644 --- a/cardano-node/src/Cardano/Node/Configuration/TopologyP2P.hs +++ b/cardano-node/src/Cardano/Node/Configuration/TopologyP2P.hs @@ -27,7 +27,7 @@ import Cardano.Node.Configuration.POM (NodeConfiguration (..)) import Cardano.Node.Configuration.Topology (TopologyError (..)) import Cardano.Node.Types import Cardano.Tracing.OrphanInstances.Network () -import Ouroboros.Network.NodeToNode (PeerAdvertise (..)) +import Ouroboros.Network.NodeToNode (DiffusionMode (..), PeerAdvertise (..)) import Ouroboros.Network.PeerSelection.Bootstrap (UseBootstrapPeers (..)) import Ouroboros.Network.PeerSelection.LedgerPeers.Type (UseLedgerPeers (..)) import Ouroboros.Network.PeerSelection.PeerTrustable (PeerTrustable (..)) @@ -105,7 +105,7 @@ instance ToJSON RootConfig where rootConfigToRelayAccessPoint :: RootConfig -> [(RelayAccessPoint, PeerAdvertise)] -rootConfigToRelayAccessPoint RootConfig { rootAccessPoints, rootAdvertise } = +rootConfigToRelayAccessPoint RootConfig { rootAccessPoints, rootAdvertise } = [ (ap, rootAdvertise) | ap <- rootAccessPoints ] @@ -122,6 +122,8 @@ data LocalRootPeersGroup = LocalRootPeersGroup , trustable :: PeerTrustable -- ^ 'trustable' configures whether the root should be trusted in fallback -- state. + , rootDiffusionMode :: DiffusionMode + -- ^ diffusion mode; used for local root peers. } deriving (Eq, Show) -- | Does not use the 'FromJSON' instance of 'RootConfig', so that @@ -136,6 +138,9 @@ instance FromJSON LocalRootPeersGroup where <*> pure hv <*> o .:? "warmValency" .!= WarmValency v <*> o .:? "trustable" .!= IsNotTrustable + -- deserialise via NodeDiffusionMode + <*> (maybe InitiatorAndResponderDiffusionMode getDiffusionMode + <$> o .:? "diffusionMode") instance ToJSON LocalRootPeersGroup where toJSON lrpg = @@ -145,6 +150,8 @@ instance ToJSON LocalRootPeersGroup where , "hotValency" .= hotValency lrpg , "warmValency" .= warmValency lrpg , "trustable" .= trustable lrpg + -- serialise via NodeDiffusionMode + , "diffusionMode" .= NodeDiffusionMode (rootDiffusionMode lrpg) ] newtype LocalRootPeersGroups = LocalRootPeersGroups @@ -252,10 +259,11 @@ isValidTrustedPeerConfiguration (RealNodeTopology (LocalRootPeersGroups lprgs) _ UseBootstrapPeers (_:_) -> True where anyTrustable = - any (\(LocalRootPeersGroup lr _ _ pt) -> case pt of + any (\LocalRootPeersGroup {localRoots, trustable} -> + case trustable of IsNotTrustable -> False IsTrustable -> not . null . rootAccessPoints - $ lr + $ localRoots ) lprgs diff --git a/cardano-node/src/Cardano/Node/Run.hs b/cardano-node/src/Cardano/Node/Run.hs index 671e0cbaad2..3ca523f807a 100644 --- a/cardano-node/src/Cardano/Node/Run.hs +++ b/cardano-node/src/Cardano/Node/Run.hs @@ -82,7 +82,7 @@ import Ouroboros.Network.PeerSelection.LedgerPeers.Type (UseLedgerPeer import Ouroboros.Network.PeerSelection.PeerSharing (PeerSharing (..)) import Ouroboros.Network.PeerSelection.PeerTrustable (PeerTrustable) import Ouroboros.Network.PeerSelection.RelayAccessPoint (RelayAccessPoint (..)) -import Ouroboros.Network.PeerSelection.State.LocalRootPeers (HotValency, WarmValency) +import Ouroboros.Network.PeerSelection.State.LocalRootPeers (HotValency, LocalRootConfig (..), WarmValency) import Ouroboros.Network.Protocol.ChainSync.Codec import Ouroboros.Network.Subscription (DnsSubscriptionTarget (..), IPSubscriptionTarget (..)) @@ -662,7 +662,7 @@ installP2PSigHUPHandler :: Tracer IO (StartupTrace blk) -> Api.BlockType blk -> NodeConfiguration -> NodeKernel IO RemoteAddress (ConnectionId LocalAddress) blk - -> StrictTVar IO [(HotValency, WarmValency, Map RelayAccessPoint (PeerAdvertise, PeerTrustable))] + -> StrictTVar IO [(HotValency, WarmValency, Map RelayAccessPoint LocalRootConfig)] -> StrictTVar IO (Map RelayAccessPoint PeerAdvertise) -> StrictTVar IO UseLedgerPeers -> StrictTVar IO UseBootstrapPeers @@ -757,7 +757,7 @@ updateBlockForging startupTracer blockType nodeKernel nc = do updateTopologyConfiguration :: Tracer IO (StartupTrace blk) -> NodeConfiguration - -> StrictTVar IO [(HotValency, WarmValency, Map RelayAccessPoint (PeerAdvertise, PeerTrustable))] + -> StrictTVar IO [(HotValency, WarmValency, Map RelayAccessPoint LocalRootConfig)] -> StrictTVar IO (Map RelayAccessPoint PeerAdvertise) -> StrictTVar IO UseLedgerPeers -> StrictTVar IO UseBootstrapPeers @@ -844,7 +844,7 @@ checkVRFFilePermissions (File vrfPrivKey) = do mkP2PArguments :: NodeConfiguration - -> STM IO [(HotValency, WarmValency, Map RelayAccessPoint (PeerAdvertise, PeerTrustable))] + -> STM IO [(HotValency, WarmValency, Map RelayAccessPoint LocalRootConfig)] -- ^ non-overlapping local root peers groups; the 'Int' denotes the -- valency of its group. -> STM IO (Map RelayAccessPoint PeerAdvertise) @@ -933,18 +933,32 @@ producerAddressesNonP2P nt = producerAddresses :: NetworkTopology - -> ( [(HotValency, WarmValency, Map RelayAccessPoint (PeerAdvertise, PeerTrustable))] - , Map RelayAccessPoint PeerAdvertise) + -> ( [(HotValency, WarmValency, Map RelayAccessPoint LocalRootConfig)] + , Map RelayAccessPoint PeerAdvertise + ) + -- ^ local roots & public roots producerAddresses RealNodeTopology { ntLocalRootPeersGroups , ntPublicRootPeers } = ( map (\lrp -> ( hotValency lrp , warmValency lrp - , Map.fromList $ map (fmap (, trustable lrp)) - $ rootConfigToRelayAccessPoint - $ localRoots lrp + , Map.fromList + . map (\(addr, peerAdvertise) -> + ( addr + , LocalRootConfig { + diffusionMode = rootDiffusionMode lrp, + peerAdvertise, + peerTrustable = trustable lrp + } + ) + ) + . rootConfigToRelayAccessPoint + $ localRoots lrp ) ) (groups ntLocalRootPeersGroups) - , foldMap (Map.fromList . rootConfigToRelayAccessPoint . publicRoots) ntPublicRootPeers + , foldMap ( Map.fromList + . rootConfigToRelayAccessPoint + . publicRoots + ) ntPublicRootPeers ) diff --git a/cardano-node/src/Cardano/Node/Startup.hs b/cardano-node/src/Cardano/Node/Startup.hs index 9f75890bafc..4260e2fe75c 100644 --- a/cardano-node/src/Cardano/Node/Startup.hs +++ b/cardano-node/src/Cardano/Node/Startup.hs @@ -34,9 +34,8 @@ import Ouroboros.Network.NodeToClient (LocalAddress (..), LocalSocket, NodeToClientVersion) import Ouroboros.Network.NodeToNode (DiffusionMode (..), NodeToNodeVersion, PeerAdvertise) import Ouroboros.Network.PeerSelection.LedgerPeers.Type (UseLedgerPeers) -import Ouroboros.Network.PeerSelection.PeerTrustable (PeerTrustable) import Ouroboros.Network.PeerSelection.RelayAccessPoint (RelayAccessPoint) -import Ouroboros.Network.PeerSelection.State.LocalRootPeers (HotValency, WarmValency) +import Ouroboros.Network.PeerSelection.State.LocalRootPeers (HotValency, LocalRootConfig, WarmValency) import Ouroboros.Network.Subscription.Dns (DnsSubscriptionTarget (..)) import Ouroboros.Network.Subscription.Ip (IPSubscriptionTarget (..)) @@ -106,7 +105,7 @@ data StartupTrace blk = -- | Log peer-to-peer network configuration, either on startup or when its -- updated. -- - | NetworkConfig [(HotValency, WarmValency, Map RelayAccessPoint (PeerAdvertise, PeerTrustable))] + | NetworkConfig [(HotValency, WarmValency, Map RelayAccessPoint LocalRootConfig)] (Map RelayAccessPoint PeerAdvertise) UseLedgerPeers diff --git a/cardano-node/src/Cardano/Node/Tracing/Tracers/P2P.hs b/cardano-node/src/Cardano/Node/Tracing/Tracers/P2P.hs index 6875e06d124..9ab64b08af8 100644 --- a/cardano-node/src/Cardano/Node/Tracing/Tracers/P2P.hs +++ b/cardano-node/src/Cardano/Node/Tracing/Tracers/P2P.hs @@ -1203,15 +1203,17 @@ instance (Show addr, Show versionNumber, Show agreedOptions, LogFormatting addr, , "remoteAddress" .= toJSON connId , "provenance" .= String (pack . show $ prov) ] - forMachine _dtal (TrConnect (Just localAddress) remoteAddress) = + forMachine _dtal (TrConnect (Just localAddress) remoteAddress diffusionMode) = mconcat [ "kind" .= String "ConnectTo" , "connectionId" .= toJSON ConnectionId { localAddress, remoteAddress } + , "diffusionMode" .= toJSON diffusionMode ] - forMachine dtal (TrConnect Nothing remoteAddress) = + forMachine dtal (TrConnect Nothing remoteAddress diffusionMode) = mconcat [ "kind" .= String "ConnectTo" , "remoteAddress" .= forMachine dtal remoteAddress + , "diffusionMode" .= toJSON diffusionMode ] forMachine _dtal (TrConnectError (Just localAddress) remoteAddress err) = mconcat diff --git a/cardano-node/src/Cardano/Node/Types.hs b/cardano-node/src/Cardano/Node/Types.hs index b16ca45e4aa..c8d339f61f5 100644 --- a/cardano-node/src/Cardano/Node/Types.hs +++ b/cardano-node/src/Cardano/Node/Types.hs @@ -114,11 +114,18 @@ instance FromJSON NodeConsensusMode where _ -> fail "Parsing NodeConsensusMode failed: can be either 'Genesis' or 'Praos'" parseJSON _ = fail "Parsing NodeConsensusMode failed" --- | Newtype wrapper which provides 'FromJSON' instance for 'DiffusionMode'. +-- | Newtype wrapper which provides 'ToJSON' and 'FromJSON' instances for +-- 'DiffusionMode'. -- newtype NodeDiffusionMode = NodeDiffusionMode { getDiffusionMode :: DiffusionMode } - deriving newtype Show + deriving newtype (Eq, Show) + +instance ToJSON NodeDiffusionMode where + toJSON (NodeDiffusionMode InitiatorOnlyDiffusionMode) + = String "InitiatorOnly" + toJSON (NodeDiffusionMode InitiatorAndResponderDiffusionMode) + = String "InitiatorAndResponder" instance FromJSON NodeDiffusionMode where parseJSON (String str) = diff --git a/cardano-node/src/Cardano/Tracing/OrphanInstances/Network.hs b/cardano-node/src/Cardano/Tracing/OrphanInstances/Network.hs index ab631582d98..7f3b9e17818 100644 --- a/cardano-node/src/Cardano/Tracing/OrphanInstances/Network.hs +++ b/cardano-node/src/Cardano/Tracing/OrphanInstances/Network.hs @@ -43,6 +43,7 @@ import Ouroboros.Network.ConnectionHandler (ConnectionHandlerTrace (.. import Ouroboros.Network.ConnectionId (ConnectionId (..)) import Ouroboros.Network.ConnectionManager.Core as ConnMgr (Trace (..)) import Ouroboros.Network.ConnectionManager.ConnMap (ConnMap (..), LocalAddr (..)) +import Ouroboros.Network.ConnectionManager.State (ConnStateId (..)) import Ouroboros.Network.ConnectionManager.Types (AbstractState (..), ConnectionManagerCounters (..), OperationResult (..)) @@ -81,6 +82,7 @@ import Ouroboros.Network.PeerSelection.State.KnownPeers (KnownPeerInfo import qualified Ouroboros.Network.PeerSelection.State.KnownPeers as KnownPeers import Ouroboros.Network.PeerSelection.State.LocalRootPeers (HotValency (..), LocalRootPeers, WarmValency (..)) +import Ouroboros.Network.PeerSelection.State.LocalRootPeers (LocalRootConfig (..)) import qualified Ouroboros.Network.PeerSelection.State.LocalRootPeers as LocalRootPeers import Ouroboros.Network.PeerSelection.Types (PeerStatus (..)) import Ouroboros.Network.Protocol.BlockFetch.Type (BlockFetch, Message (..)) @@ -1576,6 +1578,16 @@ instance FromJSON HotValency where instance FromJSON WarmValency where parseJSON v = WarmValency <$> parseJSON v +instance ToJSON LocalRootConfig where + toJSON LocalRootConfig { peerAdvertise, + peerTrustable, + diffusionMode } = + Aeson.object + [ "peerAdvertise" .= peerAdvertise + , "peerTrustable" .= peerTrustable + , "diffusionMode" .= show diffusionMode + ] + instance Show exception => ToObject (TraceLocalRootPeers RemoteAddress exception) where toObject _verb (TraceLocalRootDomains groups) = mconcat [ "kind" .= String "LocalRootDomains" @@ -2328,6 +2340,15 @@ instance ToJSON addr => ToJSON (LocalAddr addr) where toJSON (LocalAddr addr) = toJSON addr toJSON UnknownLocalAddr = Null +instance ToJSON NtN.DiffusionMode where + toJSON = String . pack . show + +instance ToJSON ConnStateId where + toJSON (ConnStateId connStateId) = toJSON connStateId + +instance ToObject ConnStateId where + toObject _ connStateId = mconcat [ "connStateId" .= toJSON connStateId ] + instance (Show addr, Show versionNumber, Show agreedOptions, ToObject addr, ToJSON addr, ToJSON versionNumber, ToJSON agreedOptions) => ToObject (ConnMgr.Trace addr (ConnectionHandlerTrace versionNumber agreedOptions)) where @@ -2345,15 +2366,17 @@ instance (Show addr, Show versionNumber, Show agreedOptions, ToObject addr, , "remoteAddress" .= toJSON connId , "provenance" .= String (pack . show $ prov) ] - TrConnect (Just localAddress) remoteAddress -> + TrConnect (Just localAddress) remoteAddress diffusionMode -> mconcat [ "kind" .= String "ConnectTo" , "connectionId" .= toJSON ConnectionId { localAddress, remoteAddress } + , "diffusionMode" .= toJSON diffusionMode ] - TrConnect Nothing remoteAddress -> + TrConnect Nothing remoteAddress diffusionMode -> mconcat [ "kind" .= String "ConnectTo" , "remoteAddress" .= toObject verb remoteAddress + , "diffusionMode" .= toJSON diffusionMode ] TrConnectError (Just localAddress) remoteAddress err -> mconcat diff --git a/cardano-node/src/Cardano/Tracing/Tracers.hs b/cardano-node/src/Cardano/Tracing/Tracers.hs index e253b1b40de..5a39cb11dea 100644 --- a/cardano-node/src/Cardano/Tracing/Tracers.hs +++ b/cardano-node/src/Cardano/Tracing/Tracers.hs @@ -57,6 +57,7 @@ import Cardano.Slotting.Slot (EpochNo (..), SlotNo (..), WithOrigin (. import Cardano.Tracing.Config import Cardano.Tracing.HasIssuer (BlockIssuerVerificationKeyHash (..), HasIssuer (..)) import Cardano.Tracing.Metrics +import Cardano.Tracing.OrphanInstances.Network () import Cardano.Tracing.Render (renderChainHash, renderHeaderHash) import Cardano.Tracing.Shutdown () import Cardano.Tracing.Startup () diff --git a/cardano-testnet/src/Testnet/Components/Configuration.hs b/cardano-testnet/src/Testnet/Components/Configuration.hs index 86b80aed801..ddbf7fc741f 100644 --- a/cardano-testnet/src/Testnet/Components/Configuration.hs +++ b/cardano-testnet/src/Testnet/Components/Configuration.hs @@ -27,6 +27,7 @@ import Cardano.Ledger.Alonzo.Genesis (AlonzoGenesis) import Cardano.Ledger.Conway.Genesis (ConwayGenesis) import qualified Cardano.Node.Configuration.Topology as NonP2P import qualified Cardano.Node.Configuration.TopologyP2P as P2P +import Ouroboros.Network.NodeToNode (DiffusionMode (..)) import Ouroboros.Network.PeerSelection.Bootstrap import Ouroboros.Network.PeerSelection.LedgerPeers import Ouroboros.Network.PeerSelection.PeerTrustable @@ -225,6 +226,7 @@ mkTopologyConfig numNodes allPorts port True = A.encodePretty topologyP2P (HotValency (numNodes - 1)) (WarmValency (numNodes - 1)) IsNotTrustable + InitiatorAndResponderDiffusionMode ] topologyP2P :: P2P.NetworkTopology