From af697b5e555632d61ac1d0769c1a3a3fb492144c 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 8901a83a651..ded8436de7a 100644 --- a/cabal.project +++ b/cabal.project @@ -122,3 +122,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 62f1cb78b19..a0f0a81dac4 100644 --- a/cardano-node/src/Cardano/Node/Configuration/TopologyP2P.hs +++ b/cardano-node/src/Cardano/Node/Configuration/TopologyP2P.hs @@ -29,7 +29,7 @@ import Cardano.Node.Configuration.Topology (TopologyError (..)) import Cardano.Node.Types import Cardano.Tracing.OrphanInstances.Network () import Ouroboros.Network.ConsensusMode -import Ouroboros.Network.NodeToNode (PeerAdvertise (..)) +import Ouroboros.Network.NodeToNode (DiffusionMode (..), PeerAdvertise (..)) import Ouroboros.Network.PeerSelection.Bootstrap (UseBootstrapPeers (..)) import Ouroboros.Network.PeerSelection.LedgerPeers.Type (LedgerPeerSnapshot (..), UseLedgerPeers (..)) @@ -109,7 +109,7 @@ instance ToJSON RootConfig where rootConfigToRelayAccessPoint :: RootConfig -> [(RelayAccessPoint, PeerAdvertise)] -rootConfigToRelayAccessPoint RootConfig { rootAccessPoints, rootAdvertise } = +rootConfigToRelayAccessPoint RootConfig { rootAccessPoints, rootAdvertise } = [ (ap, rootAdvertise) | ap <- rootAccessPoints ] @@ -126,6 +126,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 @@ -140,6 +142,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 = @@ -149,6 +154,8 @@ instance ToJSON LocalRootPeersGroup where , "hotValency" .= hotValency lrpg , "warmValency" .= warmValency lrpg , "trustable" .= trustable lrpg + -- serialise via NodeDiffusionMode + , "diffusionMode" .= NodeDiffusionMode (rootDiffusionMode lrpg) ] newtype LocalRootPeersGroups = LocalRootPeersGroups @@ -277,10 +284,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 0405ae461cc..5a022274bda 100644 --- a/cardano-node/src/Cardano/Node/Run.hs +++ b/cardano-node/src/Cardano/Node/Run.hs @@ -83,7 +83,7 @@ import Ouroboros.Network.PeerSelection.LedgerPeers.Type (LedgerPeerSna 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 (..)) @@ -678,7 +678,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 @@ -780,7 +780,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 @@ -882,7 +882,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) @@ -980,18 +980,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 d2f2e30c09a..420ff47d5ac 100644 --- a/cardano-node/src/Cardano/Node/Startup.hs +++ b/cardano-node/src/Cardano/Node/Startup.hs @@ -36,9 +36,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 (..)) @@ -108,7 +107,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 (Maybe PeerSnapshotFile) diff --git a/cardano-node/src/Cardano/Node/Tracing/Tracers/P2P.hs b/cardano-node/src/Cardano/Node/Tracing/Tracers/P2P.hs index 91d94e5bb22..a1d50a249c4 100644 --- a/cardano-node/src/Cardano/Node/Tracing/Tracers/P2P.hs +++ b/cardano-node/src/Cardano/Node/Tracing/Tracers/P2P.hs @@ -1212,15 +1212,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 7932bf89e82..174d6d2f0db 100644 --- a/cardano-node/src/Cardano/Node/Types.hs +++ b/cardano-node/src/Cardano/Node/Types.hs @@ -123,11 +123,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 e47334060ba..2cc66ffa79d 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 (..)) @@ -1579,6 +1581,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" @@ -2334,6 +2346,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 @@ -2351,15 +2372,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