-
Notifications
You must be signed in to change notification settings - Fork 738
improve UX of topology file parsing corner cases #6309
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,14 +45,15 @@ import Ouroboros.Network.PeerSelection.State.LocalRootPeers (HotValenc | |
WarmValency (..)) | ||
|
||
import Control.Applicative (Alternative (..)) | ||
import Control.Exception.Safe (Exception (..), IOException, handleAny) | ||
import Control.Exception.Safe (Exception (..), IOException, try) | ||
import Control.Monad | ||
import Control.Monad.IO.Class | ||
import qualified "contra-tracer" Control.Tracer as CT | ||
import Data.Aeson | ||
import Data.Bifunctor (first) | ||
import qualified Data.ByteString as BS | ||
import qualified Data.ByteString.Lazy.Char8 as LBS | ||
import Data.Maybe (isJust, isNothing) | ||
import Data.Text (Text) | ||
import qualified Data.Text as Text | ||
import Data.Word (Word64) | ||
|
@@ -232,26 +233,63 @@ instance ToJSON adr => ToJSON (NetworkTopology adr) where | |
readTopologyFile :: () | ||
=> forall adr. FromJSON adr | ||
=> NodeConfiguration -> CT.Tracer IO (StartupTrace blk) -> IO (Either Text (NetworkTopology adr)) | ||
readTopologyFile NodeConfiguration{ncTopologyFile=TopologyFile topologyFilePath, ncConsensusMode} tracer = runExceptT $ do | ||
readTopologyFile NodeConfiguration{ncTopologyFile=TopologyFile topologyFilePath, ncConsensusMode, ncProtocolFiles} tracer = runExceptT $ do | ||
bs <- handleIOExceptionsLiftWith handler $ BS.readFile topologyFilePath | ||
topology@RealNodeTopology{ntUseBootstrapPeers} <- | ||
topology@RealNodeTopology{ntUseLedgerPeers, ntUseBootstrapPeers, ntPeerSnapshotPath} <- | ||
liftEither . first handlerJSON $ | ||
eitherDecode $ LBS.fromStrict bs | ||
|
||
unless (isValidTrustedPeerConfiguration topology) $ | ||
throwError handlerBootstrap | ||
|
||
when (isBlockProducer && useLedgerPeers ntUseLedgerPeers) $ | ||
liftIO $ CT.traceWith tracer | ||
$ NetworkConfigUpdateWarning | ||
$ createMsg "Use of ledger peers is not recommended for BP operation" | ||
|
||
when (isJust ntPeerSnapshotPath && not (useLedgerPeers ntUseLedgerPeers) && isBlockProducer) $ | ||
liftIO $ CT.traceWith tracer | ||
$ NetworkConfigUpdateInfo | ||
$ createMsg "Ledger peers and peer snapshot, although specified in the topology file, are disabled in line with recommended BP operation" | ||
|
||
when (inPraosMode && isJust ntPeerSnapshotPath && not (useLedgerPeers ntUseLedgerPeers)) $ | ||
if isBlockProducer | ||
then liftIO $ CT.traceWith tracer | ||
$ NetworkConfigUpdateWarning | ||
$ createMsg | ||
$ "Peer snapshot file specified but topology disables ledger peers - ignoring file. " | ||
<> "To turn off this message remove peerSnapshotFile from the topology file." | ||
else liftIO $ CT.traceWith tracer | ||
$ NetworkConfigUpdateWarning | ||
$ createMsg | ||
$ "Peer snapshot file specified but topology disables ledger peers - ignoring file. " | ||
<> "To turn off this message enable the use of ledger peers or remove peerSnapshotFile from the topology file." | ||
|
||
|
||
when (inGenesisMode && not (useLedgerPeers ntUseLedgerPeers) && not isBlockProducer) $ | ||
liftIO $ CT.traceWith tracer | ||
$ NetworkConfigUpdateWarning | ||
$ createMsg "It is recommended to use ledger peers and peer snapshot file for relay operations in Genesis mode" | ||
|
||
when (inGenesisMode && isNothing ntPeerSnapshotPath && useLedgerPeers ntUseLedgerPeers && not isBlockProducer) $ | ||
liftIO $ CT.traceWith tracer | ||
$ NetworkConfigUpdateWarning | ||
$ createMsg | ||
$ "It is recommended to specify an up-to-date ledger peer snapshot file for relay operations in Genesis mode " | ||
<> "when the use of ledger peers is enabled." | ||
Comment on lines
+274
to
+279
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we are in genesis mode and there is no peer snapshot file, we might need to exit as well. @amesgen what do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the node is syncing up not from a blank state, but maybe somewhat stale, it can use the peers it gets from the ledger it has. Also, this file is not necessary when the node is synced up and so I didn't think crashing the node at startup was warranted. [edit] We can add to the warning that the node might appear stuck as it may not be able to find any peers to connect to and start syncing. |
||
|
||
-- make all relative paths in the topology file relative to the topology file location | ||
adjustFilePaths (takeDirectory topologyFilePath </>) <$> | ||
if isGenesisCompatible ncConsensusMode ntUseBootstrapPeers | ||
then pure topology | ||
else do | ||
liftIO $ CT.traceWith tracer $ NetworkConfigUpdateError genesisIncompatible | ||
liftIO $ CT.traceWith tracer $ NetworkConfigUpdateWarning genesisIncompatible | ||
pure $ topology{ntUseBootstrapPeers = DontUseBootstrapPeers} | ||
where | ||
createMsg msg = | ||
"Cardano.Node.Configuration.Topology.readTopologyFile: " <> msg | ||
handler :: IOException -> Text | ||
handler e = Text.pack $ "Cardano.Node.Configuration.Topology.readTopologyFile: " | ||
++ displayException e | ||
handler = Text.pack . createMsg . displayException | ||
handlerJSON :: String -> Text | ||
handlerJSON err = mconcat | ||
[ "Is your topology file formatted correctly? " | ||
|
@@ -263,8 +301,8 @@ readTopologyFile NodeConfiguration{ncTopologyFile=TopologyFile topologyFilePath, | |
, Text.pack err | ||
] | ||
genesisIncompatible | ||
= Text.pack $ "Cardano.Node.Configuration.Topology.readTopologyFile: " | ||
<> "Bootstrap peers (field 'bootstrapPeers') are not compatible " | ||
= Text.pack . createMsg $ | ||
"Bootstrap peers (field 'bootstrapPeers') are not compatible " | ||
<> "with Genesis syncing mode, reverting to 'DontUseBootstrapPeers'. " | ||
<> "Big ledger peers will be leveraged for decentralized syncing - it " | ||
<> "is recommened to provide an up-to-date big ledger peer snapshot file " | ||
|
@@ -277,8 +315,13 @@ readTopologyFile NodeConfiguration{ncTopologyFile=TopologyFile topologyFilePath, | |
, "in bootstrap mode. Make sure you provide at least one bootstrap peer " | ||
, "source. " | ||
] | ||
useLedgerPeers DontUseLedgerPeers = False | ||
useLedgerPeers _ = True | ||
isGenesisCompatible GenesisMode UseBootstrapPeers{} = False | ||
isGenesisCompatible _ _ = True | ||
inPraosMode = ncConsensusMode == PraosMode | ||
inGenesisMode = ncConsensusMode == GenesisMode | ||
isBlockProducer = hasProtocolFile ncProtocolFiles | ||
|
||
readTopologyFileOrError :: () | ||
=> forall adr. FromJSON adr | ||
|
@@ -289,12 +332,18 @@ readTopologyFileOrError nc tr = | |
<> Text.unpack err) | ||
pure | ||
|
||
readPeerSnapshotFile :: PeerSnapshotFile -> IO LedgerPeerSnapshot | ||
readPeerSnapshotFile (PeerSnapshotFile peerSnapshotFile) = | ||
handleException $ | ||
either error pure =<< eitherDecodeFileStrict peerSnapshotFile | ||
readPeerSnapshotFile :: PeerSnapshotFile -> IO (Either Text LedgerPeerSnapshot) | ||
readPeerSnapshotFile (PeerSnapshotFile file) = do | ||
content <- first renderException <$> try (BS.readFile file) | ||
return $ first handler $ content >>= eitherDecodeStrict | ||
where | ||
handleException = handleAny $ \e -> error $ "Cardano.Node.Configuration.TopologyP2P.readPeerSnapshotFile: " <> displayException e | ||
renderException :: IOException -> String | ||
renderException = displayException | ||
|
||
handler :: String -> Text | ||
handler msg = | ||
Text.pack | ||
$ "Cardano.Node.Configuration.TopologyP2P.readPeerSnapshotFile: " <> msg | ||
|
||
-- | ||
-- Checking for chance of progress in bootstrap phase | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When in genesis mode and there, and ledger peers are disabled, the node should error (this message needs to be an error, and the node needs to exit - am I right that the node used to exit in this case?).
Ping @amesgen.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it can still progress if association mode is localrootsonly, and it might be useful to not have it crash for testing environments.
[edit] I think the node used to crash only when the
peerSnapshotFile
was given but was missing.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, private relays might use
LocalRootsOnly
. Generally, there isn't really any benefit to using Genesis whenLocalRootsOnly
, but it also isn't problematic either.We indeed should error if there is no chance that we will ever leave the
PreSyncing
state, ie when Network can't ever signalTrustedStateWithExternalPeers
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My main concern was a misconfiguration Daedalus node: people will notice node not starting, but won't notice a warning so they'll need to wait for node not making progress with syncing. But maybe indeed that's too conservative.