Skip to content

Commit b281d8f

Browse files
Support for big ledger peer snapshot
This change introduces support for big ledger peers in the node. A new optional entry in network topology JSON parser is added that is intended to point to a path containing a serialized snapshot of big ledger peers taken from some slot a priori. When present, this file is decoded at node startup, or when a SIGHUP is triggered, and made available to the diffusion layer via reading from a TVar.
1 parent 0cc5b08 commit b281d8f

File tree

7 files changed

+112
-17
lines changed

7 files changed

+112
-17
lines changed

cardano-node/cardano-node.cabal

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ library
145145
, base16-bytestring
146146
, bytestring
147147
, cardano-api ^>= 8.44
148+
, cardano-binary
148149
, cardano-crypto-class
149150
, cardano-crypto-wrapper
150151
, cardano-git-rev ^>=0.2.2

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

+25-4
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ module Cardano.Node.Configuration.TopologyP2P
1818
, PeerAdvertise(..)
1919
, nodeAddressToSockAddr
2020
, readTopologyFile
21+
, readPeerSnapshotFile
2122
, readTopologyFileOrError
2223
, rootConfigToRelayAccessPoint
2324
)
2425
where
2526

27+
import Cardano.Binary
2628
import Cardano.Node.Configuration.NodeAddress
2729
import Cardano.Node.Configuration.POM (NodeConfiguration (..))
2830
import Cardano.Node.Configuration.Topology (TopologyError (..))
@@ -31,16 +33,20 @@ import Cardano.Node.Types
3133
import Cardano.Tracing.OrphanInstances.Network ()
3234
import Ouroboros.Network.NodeToNode (PeerAdvertise (..))
3335
import Ouroboros.Network.PeerSelection.Bootstrap (UseBootstrapPeers (..))
34-
import Ouroboros.Network.PeerSelection.LedgerPeers.Type (UseLedgerPeers (..))
36+
import Ouroboros.Network.PeerSelection.LedgerPeers.Type (LedgerPeerSnapshot (..),
37+
UseLedgerPeers (..))
3538
import Ouroboros.Network.PeerSelection.PeerTrustable (PeerTrustable (..))
3639
import Ouroboros.Network.PeerSelection.RelayAccessPoint (RelayAccessPoint (..))
3740
import Ouroboros.Network.PeerSelection.State.LocalRootPeers (HotValency (..),
3841
WarmValency (..))
3942

43+
import Codec.CBOR.Read
4044
import Control.Applicative (Alternative (..))
45+
import Control.DeepSeq
4146
import Control.Exception (IOException)
4247
import qualified Control.Exception as Exception
4348
import Control.Exception.Base (Exception (..))
49+
import Control.Monad.Trans.Except.Extra
4450
import "contra-tracer" Control.Tracer (Tracer, traceWith)
4551
import Data.Aeson
4652
import Data.Bifunctor (Bifunctor (..))
@@ -175,6 +181,7 @@ data NetworkTopology = RealNodeTopology { ntLocalRootPeersGroups :: !LocalRootPe
175181
, ntPublicRootPeers :: ![PublicRootPeers]
176182
, ntUseLedgerPeers :: !UseLedgerPeers
177183
, ntUseBootstrapPeers :: !UseBootstrapPeers
184+
, ntPeerSnapshotPath :: !(Maybe PeerSnapshotFile)
178185
}
179186
deriving (Eq, Show)
180187

@@ -183,7 +190,8 @@ instance FromJSON NetworkTopology where
183190
RealNodeTopology <$> (o .: "localRoots" )
184191
<*> (o .: "publicRoots" )
185192
<*> (o .:? "useLedgerAfterSlot" .!= DontUseLedgerPeers )
186-
<*> (o .:? "bootstrapPeers" .!= DontUseBootstrapPeers)
193+
<*> (o .:? "bootstrapPeers" .!= DontUseBootstrapPeers )
194+
<*> (o .:? "peerSnapshotFile")
187195

188196
instance ToJSON NetworkTopology where
189197
toJSON top =
@@ -192,10 +200,12 @@ instance ToJSON NetworkTopology where
192200
, ntPublicRootPeers
193201
, ntUseLedgerPeers
194202
, ntUseBootstrapPeers
203+
, ntPeerSnapshotPath
195204
} -> object [ "localRoots" .= ntLocalRootPeersGroups
196205
, "publicRoots" .= ntPublicRootPeers
197206
, "useLedgerAfterSlot" .= ntUseLedgerPeers
198207
, "bootstrapPeers" .= ntUseBootstrapPeers
208+
, "peerSnapshotFile" .= ntPeerSnapshotPath
199209
]
200210

201211
--
@@ -235,7 +245,8 @@ instance FromJSON (Legacy NetworkTopology) where
235245
RealNodeTopology <$> fmap getLegacy (o .: "LocalRoots")
236246
<*> fmap getLegacy (o .: "PublicRoots")
237247
<*> (o .:? "useLedgerAfterSlot" .!= DontUseLedgerPeers)
238-
<*> pure DontUseBootstrapPeers)
248+
<*> pure DontUseBootstrapPeers
249+
<*> pure Nothing)
239250

240251
-- | Read the `NetworkTopology` configuration from the specified file.
241252
--
@@ -297,14 +308,24 @@ readTopologyFileOrError tr nc =
297308
<> Text.unpack err)
298309
pure
299310

311+
readPeerSnapshotFile :: PeerSnapshotFile -> IO LedgerPeerSnapshot
312+
readPeerSnapshotFile (PeerSnapshotFile psf) = either error pure =<< runExceptT
313+
(handleLeftT (left . ("Cardano.Node.Configuration.TopologyP2P.readPeerSnapshotFile: " <>)) $ do
314+
contents <- BS.readFile psf `catchIOExceptT` displayException
315+
-- sweep it out eagerly
316+
let tryDecode = force . deserialiseFromBytes fromCBOR . LBS.fromStrict $ contents
317+
case tryDecode of
318+
Left _ -> left "Peer snapshot file read but decode failed - incompatible or corrupted file?"
319+
Right (_, lps) -> right lps)
320+
300321
--
301322
-- Checking for chance of progress in bootstrap phase
302323
--
303324

304325
-- | This function returns false if non-trustable peers are configured
305326
--
306327
isValidTrustedPeerConfiguration :: NetworkTopology -> Bool
307-
isValidTrustedPeerConfiguration (RealNodeTopology (LocalRootPeersGroups lprgs) _ _ ubp) =
328+
isValidTrustedPeerConfiguration (RealNodeTopology (LocalRootPeersGroups lprgs) _ _ ubp _) =
308329
case ubp of
309330
DontUseBootstrapPeers -> True
310331
UseBootstrapPeers [] -> anyTrustable

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

+52-10
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
{-# LANGUAGE NamedFieldPuns #-}
99
{-# LANGUAGE PackageImports #-}
1010
{-# LANGUAGE ScopedTypeVariables #-}
11-
{-# LANGUAGE TypeApplications #-}
1211
{-# LANGUAGE TupleSections #-}
12+
{-# LANGUAGE TypeApplications #-}
1313

1414
{-# OPTIONS_GHC -Wno-unused-imports #-}
1515

@@ -39,12 +39,14 @@ import Control.Monad.Class.MonadThrow (MonadThrow (..))
3939
import Control.Monad.IO.Class (MonadIO (..))
4040
import Control.Monad.Trans.Except (ExceptT, runExceptT)
4141
import Control.Monad.Trans.Except.Extra (left)
42+
import Control.Monad.Trans.Maybe (MaybeT (..), mapMaybeT)
4243
import "contra-tracer" Control.Tracer
4344
import Data.Either (partitionEithers)
4445
import Data.Map.Strict (Map)
4546
import qualified Data.Map.Strict as Map
4647
import Data.Maybe (catMaybes, fromMaybe, mapMaybe)
4748
import Data.Monoid (Last (..))
49+
import Data.Foldable (traverse_)
4850
import Data.Proxy (Proxy (..))
4951
import Data.Text (Text, breakOn, pack)
5052
import qualified Data.Text as Text
@@ -125,7 +127,7 @@ import Cardano.Node.TraceConstraints (TraceConstraints)
125127
import Cardano.Tracing.Tracers
126128
import Ouroboros.Network.PeerSelection.PeerSharing (PeerSharing (..))
127129
import Ouroboros.Network.PeerSelection.State.LocalRootPeers (HotValency, WarmValency)
128-
import Ouroboros.Network.PeerSelection.LedgerPeers.Type (UseLedgerPeers)
130+
import Ouroboros.Network.PeerSelection.LedgerPeers.Type (LedgerPeerSnapshot (..), UseLedgerPeers)
129131
import Ouroboros.Network.PeerSelection.PeerTrustable (PeerTrustable)
130132
import Ouroboros.Network.PeerSelection.Bootstrap (UseBootstrapPeers)
131133

@@ -420,16 +422,24 @@ handleSimpleNode blockType runP p2pMode tracers nc onKernel = do
420422
nt@TopologyP2P.RealNodeTopology
421423
{ ntUseLedgerPeers
422424
, ntUseBootstrapPeers
425+
, ntPeerSnapshotPath
423426
} <- TopologyP2P.readTopologyFileOrError (startupTracer tracers) nc
424427
let (localRoots, publicRoots) = producerAddresses nt
425428
traceWith (startupTracer tracers)
426429
$ NetworkConfig localRoots
427430
publicRoots
428431
ntUseLedgerPeers
429-
localRootsVar <- newTVarIO localRoots
430-
publicRootsVar <- newTVarIO publicRoots
431-
useLedgerVar <- newTVarIO ntUseLedgerPeers
432+
ntPeerSnapshotPath
433+
localRootsVar <- newTVarIO localRoots
434+
publicRootsVar <- newTVarIO publicRoots
435+
useLedgerVar <- newTVarIO ntUseLedgerPeers
432436
useBootstrapVar <- newTVarIO ntUseBootstrapPeers
437+
ledgerPeerSnapshotPathVar <- newTVarIO ntPeerSnapshotPath
438+
ledgerPeerSnapshotVar <- newTVarIO =<< updateLedgerPeerSnapshot
439+
(startupTracer tracers)
440+
(readTVar ledgerPeerSnapshotPathVar)
441+
(const . pure $ ())
442+
433443
let nodeArgs = RunNodeArgs
434444
{ rnTraceConsensus = consensusTracers tracers
435445
, rnTraceNTN = nodeToNodeTracers tracers
@@ -462,6 +472,11 @@ handleSimpleNode blockType runP p2pMode tracers nc onKernel = do
462472
updateTopologyConfiguration
463473
(startupTracer tracers) nc
464474
localRootsVar publicRootsVar useLedgerVar useBootstrapVar
475+
ledgerPeerSnapshotPathVar
476+
void $ updateLedgerPeerSnapshot
477+
(startupTracer tracers)
478+
(readTVar ledgerPeerSnapshotPathVar)
479+
(writeTVar ledgerPeerSnapshotVar)
465480
traceWith (startupTracer tracers) (BlockForgingUpdate NotEffective)
466481
)
467482
Nothing
@@ -473,13 +488,15 @@ handleSimpleNode blockType runP p2pMode tracers nc onKernel = do
473488
(readTVar publicRootsVar)
474489
(readTVar useLedgerVar)
475490
(readTVar useBootstrapVar)
491+
(readTVar ledgerPeerSnapshotVar)
476492
in
477493
Node.run
478494
nodeArgs {
479495
rnNodeKernelHook = \registry nodeKernel -> do
480496
-- reinstall `SIGHUP` handler
481497
installP2PSigHUPHandler (startupTracer tracers) blockType nc nodeKernel
482498
localRootsVar publicRootsVar useLedgerVar useBootstrapVar
499+
ledgerPeerSnapshotPathVar
483500
rnNodeKernelHook nodeArgs registry nodeKernel
484501
}
485502
StdRunNodeArgs
@@ -648,17 +665,19 @@ installP2PSigHUPHandler :: Tracer IO (StartupTrace blk)
648665
-> StrictTVar IO (Map RelayAccessPoint PeerAdvertise)
649666
-> StrictTVar IO UseLedgerPeers
650667
-> StrictTVar IO UseBootstrapPeers
668+
-> StrictTVar IO (Maybe PeerSnapshotFile)
651669
-> IO ()
652670
#ifndef UNIX
653671
installP2PSigHUPHandler _ _ _ _ _ _ _ _ = return ()
654672
#else
655673
installP2PSigHUPHandler startupTracer blockType nc nodeKernel localRootsVar publicRootsVar useLedgerVar
656-
useBootstrapPeersVar =
674+
useBootstrapPeersVar ledgerPeerSnapshotPathVar =
657675
void $ Signals.installHandler
658676
Signals.sigHUP
659677
(Signals.Catch $ do
660678
updateBlockForging startupTracer blockType nodeKernel nc
661-
updateTopologyConfiguration startupTracer nc localRootsVar publicRootsVar useLedgerVar useBootstrapPeersVar
679+
updateTopologyConfiguration startupTracer nc localRootsVar publicRootsVar
680+
useLedgerVar useBootstrapPeersVar ledgerPeerSnapshotPathVar
662681
)
663682
Nothing
664683
#endif
@@ -743,9 +762,10 @@ updateTopologyConfiguration :: Tracer IO (StartupTrace blk)
743762
-> StrictTVar IO (Map RelayAccessPoint PeerAdvertise)
744763
-> StrictTVar IO UseLedgerPeers
745764
-> StrictTVar IO UseBootstrapPeers
765+
-> StrictTVar IO (Maybe PeerSnapshotFile)
746766
-> IO ()
747767
updateTopologyConfiguration startupTracer nc localRootsVar publicRootsVar useLedgerVar
748-
useBootsrapPeersVar = do
768+
useBootsrapPeersVar ledgerPeerSnapshotPathVar = do
749769
traceWith startupTracer NetworkConfigUpdate
750770
result <- try $ readTopologyFileOrError startupTracer nc
751771
case result of
@@ -755,17 +775,36 @@ updateTopologyConfiguration startupTracer nc localRootsVar publicRootsVar useLed
755775
$ pack "Error reading topology configuration file:" <> err
756776
Right nt@RealNodeTopology { ntUseLedgerPeers
757777
, ntUseBootstrapPeers
778+
, ntPeerSnapshotPath
758779
} -> do
759780
let (localRoots, publicRoots) = producerAddresses nt
760781
traceWith startupTracer
761-
$ NetworkConfig localRoots publicRoots ntUseLedgerPeers
782+
$ NetworkConfig localRoots publicRoots ntUseLedgerPeers ntPeerSnapshotPath
762783
atomically $ do
763784
writeTVar localRootsVar localRoots
764785
writeTVar publicRootsVar publicRoots
765786
writeTVar useLedgerVar ntUseLedgerPeers
766787
writeTVar useBootsrapPeersVar ntUseBootstrapPeers
788+
writeTVar ledgerPeerSnapshotPathVar ntPeerSnapshotPath
767789
#endif
768790

791+
updateLedgerPeerSnapshot :: Tracer IO (StartupTrace blk)
792+
-> STM IO (Maybe PeerSnapshotFile)
793+
-> (Maybe LedgerPeerSnapshot -> STM IO ())
794+
-> IO (Maybe LedgerPeerSnapshot)
795+
updateLedgerPeerSnapshot startupTracer readLedgerPeerPath writeVar = runMaybeT $
796+
(\io_m_lps -> do
797+
m_lps <- io_m_lps
798+
traverse_ (\(LedgerPeerSnapshot (wOrigin, _)) ->
799+
traceWith startupTracer
800+
(LedgerPeerSnapshotLoaded wOrigin)) m_lps
801+
atomically . writeVar $ m_lps
802+
io_m_lps)
803+
-- ^ ensures that snapshot payload TVar is updated to Nothing
804+
-- if the path entry is removed from topology file sometime
805+
-- before sighup
806+
`mapMaybeT` (liftIO . readPeerSnapshotFile =<< MaybeT (atomically readLedgerPeerPath))
807+
769808
--------------------------------------------------------------------------------
770809
-- Helper functions
771810
--------------------------------------------------------------------------------
@@ -823,6 +862,7 @@ mkP2PArguments
823862
-> STM IO (Map RelayAccessPoint PeerAdvertise)
824863
-> STM IO UseLedgerPeers
825864
-> STM IO UseBootstrapPeers
865+
-> STM IO (Maybe LedgerPeerSnapshot)
826866
-> Diffusion.ExtraArguments 'Diffusion.P2P IO
827867
mkP2PArguments NodeConfiguration {
828868
ncTargetNumberOfRootPeers,
@@ -839,13 +879,15 @@ mkP2PArguments NodeConfiguration {
839879
daReadLocalRootPeers
840880
daReadPublicRootPeers
841881
daReadUseLedgerPeers
842-
daReadUseBootstrapPeers =
882+
daReadUseBootstrapPeers
883+
daReadLedgerPeerSnapshot =
843884
Diffusion.P2PArguments P2P.ArgumentsExtra
844885
{ P2P.daPeerSelectionTargets
845886
, P2P.daReadLocalRootPeers
846887
, P2P.daReadPublicRootPeers
847888
, P2P.daReadUseLedgerPeers
848889
, P2P.daReadUseBootstrapPeers
890+
, P2P.daReadLedgerPeerSnapshot
849891
, P2P.daProtocolIdleTimeout = ncProtocolIdleTimeout
850892
, P2P.daTimeWaitTimeout = ncTimeWaitTimeout
851893
, P2P.daDeadlineChurnInterval = 3300

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

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import Cardano.Node.Configuration.POM (NodeConfiguration (..), ncProto
1919
import Cardano.Node.Configuration.Socket
2020
import Cardano.Node.Protocol (ProtocolInstantiationError)
2121
import Cardano.Node.Protocol.Types (SomeConsensusProtocol (..))
22+
import Cardano.Node.Types (PeerSnapshotFile)
23+
import Cardano.Slotting.Slot (SlotNo, WithOrigin)
2224
import qualified Ouroboros.Consensus.BlockchainTime.WallClock.Types as WCT
2325
import Ouroboros.Consensus.Cardano.Block
2426
import Ouroboros.Consensus.Cardano.CanHardFork (shelleyLedgerConfig)
@@ -113,6 +115,7 @@ data StartupTrace blk =
113115
| NetworkConfig [(HotValency, WarmValency, Map RelayAccessPoint (PeerAdvertise, PeerTrustable))]
114116
(Map RelayAccessPoint PeerAdvertise)
115117
UseLedgerPeers
118+
(Maybe PeerSnapshotFile)
116119

117120
-- | Warn when 'DisabledP2P' is set.
118121
| NonP2PWarning
@@ -131,6 +134,7 @@ data StartupTrace blk =
131134
| BIShelley BasicInfoShelleyBased
132135
| BIByron BasicInfoByron
133136
| BINetwork BasicInfoNetwork
137+
| LedgerPeerSnapshotLoaded (WithOrigin SlotNo)
134138

135139
data EnabledBlockForging = EnabledBlockForging
136140
| DisabledBlockForging

0 commit comments

Comments
 (0)