Skip to content

Commit 69abbd9

Browse files
committed
WIP implementing PerasVoteForging integration
Integrate Peras vote forging in cardano-node
1 parent 82ce1ce commit 69abbd9

5 files changed

Lines changed: 147 additions & 8 deletions

File tree

‎cardano-node/cardano-node.cabal‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ library
8181
Cardano.Node.Handlers.Shutdown
8282
Cardano.Node.Handlers.TopLevel
8383
Cardano.Node.Orphans
84+
Cardano.Node.Peras.Trace
8485
Cardano.Node.Parsers
8586
Cardano.Node.Pretty
8687
Cardano.Node.Protocol
@@ -255,6 +256,7 @@ test-suite cardano-node-test
255256
, hedgehog-corpus
256257
, hedgehog-extras ^>= 0.10
257258
, iproute
259+
, io-classes:{io-classes}
258260
, mtl
259261
, ouroboros-consensus:{ouroboros-consensus, diffusion}
260262
, ouroboros-network:{api, framework, ouroboros-network}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module Cardano.Node.Peras.Trace
2+
( PerasVoteForgingUpdateResult (..)
3+
) where
4+
5+
data PerasVoteForgingUpdateResult
6+
= PerasVoteForgingInstalled
7+
| PerasVoteForgingDisabledUnsupported
8+
| PerasVoteForgingCleared
9+
| PerasVoteForgingRetainedAfterError String
10+
| PerasVoteForgingAmbiguousCredentials Int
11+
deriving (Eq, Show)

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

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ module Cardano.Node.Run
2626
import Cardano.Api (File (..), FileDirection (..))
2727
import Cardano.Api.Error (displayError)
2828
import qualified Cardano.Api as Api
29+
import Cardano.Ledger.Keys (coerceKeyRole, hashKey)
2930
import System.Random (randomIO)
3031

3132
import qualified Cardano.Crypto.Init as Crypto
@@ -48,7 +49,8 @@ import Cardano.Node.Protocol (ProtocolInstantiationError (..), mkConse
4849
import Cardano.Node.Protocol.Byron (ByronProtocolInstantiationError (CredentialsError))
4950
import Cardano.Node.Protocol.Cardano (CardanoProtocolInstantiationError (..))
5051
import Cardano.Node.Protocol.Shelley (PraosLeaderCredentialsError (..),
51-
ShelleyProtocolInstantiationError (PraosLeaderCredentialsError), readGenesis)
52+
ShelleyProtocolInstantiationError (PraosLeaderCredentialsError), readGenesis)
53+
import Cardano.Node.Peras.Trace (PerasVoteForgingUpdateResult (..))
5254
import Cardano.Node.Protocol.Types
5355
import Cardano.Node.Queries
5456
import Cardano.Rpc.Server
@@ -69,7 +71,13 @@ import Cardano.Slotting.Slot (WithOrigin (..))
6971
import Cardano.Logging.Types (LogFormatting, TraceConfig)
7072
import Cardano.Logging.Utils (showT)
7173

74+
import Ouroboros.Consensus.Cardano.Peras (mkCardanoPerasVoteForging)
75+
import Ouroboros.Consensus.Committee.Types (PoolId (..))
76+
import Ouroboros.Consensus.Peras.Crypto.BLS.Unsafe (unsafePerasBLSPrivateKeyFromEnv)
77+
import Ouroboros.Consensus.Protocol.Praos.Common (PraosCanBeLeader (..))
78+
import qualified Ouroboros.Consensus.Cardano.Node as CardanoConsensus
7279
import qualified Ouroboros.Consensus.Config as Consensus
80+
import Ouroboros.Consensus.Shelley.Node.Common (ProtocolParamsShelleyBased (..), ShelleyLeaderCredentials (..))
7381
import Ouroboros.Consensus.Config.SupportsNode (ConfigSupportsNode (..))
7482
import Ouroboros.Consensus.Node (SnapshotPolicyArgs (..),
7583
NodeDatabasePaths (..), nonImmutableDbPath, RunNodeArgs (..), StdRunNodeArgs (..))
@@ -164,6 +172,7 @@ import System.Directory (canonicalizePath, createDirectoryIfMissing, d
164172
makeAbsolute)
165173
import System.Environment (lookupEnv)
166174
import System.FilePath (takeDirectory, (</>))
175+
import System.IO.Error (isDoesNotExistError)
167176
import System.IO (hPutStrLn)
168177
#ifdef UNIX
169178
import System.Posix.Files
@@ -417,8 +426,19 @@ handleSimpleNode blockType runP tracers forgingStateVar nc cmdPc networkMagic on
417426
-- set the initial block forging
418427
blockForging <- mkBlockForging (Consensus.kesAgentTracer $ consensusTracers tracers)
419428

420-
unless (ncStartAsNonProducingNode nc) $
421-
setBlockForging nodeKernel blockForging
429+
let installedBlockForging =
430+
if ncStartAsNonProducingNode nc then [] else blockForging
431+
blockForgingStatus =
432+
if null installedBlockForging
433+
then BlockForgingDisabled
434+
else BlockForgingEnabled runP
435+
setBlockForging nodeKernel installedBlockForging
436+
437+
updatePerasVoteForging
438+
(startupTracer tracers)
439+
blockType
440+
nodeKernel
441+
blockForgingStatus
422442

423443
maybeSpawnOnSlotSyncedShutdownHandler
424444
(ncShutdownConfig nc)
@@ -502,6 +522,7 @@ handleSimpleNode blockType runP tracers forgingStateVar nc cmdPc networkMagic on
502522
blockType nc cmdPc networkMagic nodeKernel localRootsVar publicRootsVar useLedgerVar
503523
useBootstrapVar ledgerPeerSnapshotPathVar ledgerPeerSnapshotVar
504524
rpcConfigVar
525+
rnNodeKernelHook nodeArgs registry nodeKernel
505526
-- populate node kernel access for RPC server
506527
(shelleyGenesisHash, shelleyGenesisFile) <- case ncProtocolConfig nc of
507528
NodeProtocolConfigurationCardano _ shelleyCfg _ _ _ _ _ ->
@@ -631,7 +652,9 @@ installSigHUPHandler startupTracer kesAgentTracer forgingStateVar blockType nc c
631652
void $ Signals.installHandler
632653
Signals.sigHUP
633654
(Signals.Catch $ do
634-
updateBlockForging startupTracer kesAgentTracer forgingStateVar blockType nodeKernel nc
655+
blockForgingStatus <-
656+
updateBlockForging startupTracer kesAgentTracer forgingStateVar blockType nodeKernel nc
657+
updatePerasVoteForging startupTracer blockType nodeKernel blockForgingStatus
635658
updateTopologyConfiguration startupTracer nc localRootsVar publicRootsVar
636659
useLedgerVar useBootstrapPeersVar ledgerPeerSnapshotPathVar
637660
void $ updateLedgerPeerSnapshot
@@ -648,14 +671,22 @@ installSigHUPHandler startupTracer kesAgentTracer forgingStateVar blockType nc c
648671
#endif
649672

650673

674+
-- | Whether reloading produced a protocol snapshot and whether block forging
675+
-- is installed. 'BlockForgingUnchanged' means the reload was rejected and both
676+
-- the current block and Peras forgers must be preserved.
677+
data BlockForgingStatus blk
678+
= BlockForgingEnabled (Api.ProtocolInfoArgs IO blk)
679+
| BlockForgingDisabled
680+
| BlockForgingUnchanged
681+
651682
#ifdef UNIX
652683
updateBlockForging :: Tracer IO (StartupTrace blk)
653684
-> Tracer IO KESAgentClientTrace
654685
-> ForgingStateVar
655686
-> Api.BlockType blk
656687
-> NodeKernel IO RemoteAddress (ConnectionId LocalAddress) blk
657688
-> NodeConfiguration
658-
-> IO ()
689+
-> IO (BlockForgingStatus blk)
659690
updateBlockForging startupTracer kesAgentTracer forgingStateVar blockType nodeKernel nc = do
660691
eitherSomeProtocol <-
661692
runExceptT $
@@ -669,8 +700,10 @@ updateBlockForging startupTracer kesAgentTracer forgingStateVar blockType nodeKe
669700
noteForgingState forgingStateVar False
670701
traceWith startupTracer (BlockForgingUpdate DisabledBlockForging)
671702
setBlockForging nodeKernel []
672-
_NothingOrOtherFileError ->
703+
pure BlockForgingDisabled
704+
_NothingOrOtherFileError -> do
673705
traceWith startupTracer (BlockForgingUpdateError err)
706+
pure BlockForgingUnchanged
674707
Right (SomeConsensusProtocol blockType' runP', _) ->
675708
case Api.reflBlockType blockType blockType' of
676709
Just Refl -> do
@@ -689,12 +722,15 @@ updateBlockForging startupTracer kesAgentTracer forgingStateVar blockType nodeKe
689722
then EnabledBlockForging
690723
else DisabledBlockForging))
691724
setBlockForging nodeKernel blockForging
692-
Nothing ->
725+
pure $ if enabled
726+
then BlockForgingEnabled runP'
727+
else BlockForgingDisabled
728+
Nothing -> do
693729
traceWith startupTracer
694730
$ BlockForgingBlockTypeMismatch
695731
(Api.SomeBlockType blockType)
696732
(Api.SomeBlockType blockType')
697-
return ()
733+
pure BlockForgingUnchanged
698734
where
699735
wasFileRemovedFromScope :: ProtocolInstantiationError
700736
-> Maybe (Api.FileError Api.TextEnvelopeError)
@@ -712,7 +748,63 @@ updateBlockForging startupTracer kesAgentTracer forgingStateVar blockType nodeKe
712748
wasFileRemovedFromScope (ShelleyProtocolInstantiationError _) = Nothing
713749
wasFileRemovedFromScope (CardanoProtocolInstantiationError _) = Nothing
714750

751+
#endif
752+
753+
updatePerasVoteForging
754+
:: forall blk.
755+
Tracer IO (StartupTrace blk)
756+
-> Api.BlockType blk
757+
-> NodeKernel IO RemoteAddress (ConnectionId LocalAddress) blk
758+
-> BlockForgingStatus blk
759+
-> IO ()
760+
updatePerasVoteForging startupTracer blockType nodeKernel blockForgingStatus = do
761+
case blockForgingStatus of
762+
BlockForgingUnchanged ->
763+
pure ()
764+
BlockForgingDisabled -> do
765+
setPerasVoteForging nodeKernel Nothing
766+
tracePerasVoteForgingUpdate PerasVoteForgingCleared
767+
BlockForgingEnabled args ->
768+
updateFromProtocolArgs args
769+
where
770+
updateFromProtocolArgs args =
771+
case blockType of
772+
Api.CardanoBlockType ->
773+
case poolIdFromProtocolInfoArgs args of
774+
Nothing -> do
775+
setPerasVoteForging nodeKernel Nothing
776+
tracePerasVoteForgingUpdate PerasVoteForgingCleared
777+
Just poolId -> do
778+
case perasPrivateKey of
779+
Left err ->
780+
tracePerasVoteForgingUpdate (PerasVoteForgingRetainedAfterError (show err))
781+
Right privateKey -> do
782+
let voteForging = mkCardanoPerasVoteForging poolId privateKey
783+
setPerasVoteForging nodeKernel (Just voteForging)
784+
tracePerasVoteForgingUpdate PerasVoteForgingInstalled
785+
_ -> do
786+
setPerasVoteForging nodeKernel Nothing
787+
tracePerasVoteForgingUpdate PerasVoteForgingDisabledUnsupported
788+
789+
perasPrivateKey =
790+
unsafePerasBLSPrivateKeyFromEnv
791+
792+
poolIdFromProtocolInfoArgs (Api.ProtocolInfoArgsCardano _ params) =
793+
case shelleyBasedLeaderCredentials (CardanoConsensus.shelleyBasedProtocolParams params) of
794+
[credential] -> Just (poolIdFromShelleyLeaderCredentials credential)
795+
_ -> Nothing
796+
797+
poolIdFromShelleyLeaderCredentials =
798+
PoolId
799+
. hashKey
800+
. coerceKeyRole
801+
. praosCanBeLeaderColdVerKey
802+
. shelleyLeaderCredentialsCanBeLeader
803+
804+
tracePerasVoteForgingUpdate =
805+
traceWith startupTracer . PerasVoteForgingUpdate
715806

807+
#ifdef UNIX
716808
updateTopologyConfiguration :: Tracer IO (StartupTrace blk)
717809
-> NodeConfiguration
718810
-> StrictTVar IO [(HotValency, WarmValency, Map RelayAccessPoint (LocalRootConfig PeerTrustable))]

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import Cardano.Network.NodeToClient (NodeToClientVersion)
2727
import Cardano.Network.NodeToNode (DiffusionMode (..), NodeToNodeVersion, PeerAdvertise)
2828
import Cardano.Node.Configuration.POM (NodeConfiguration (..), ncProtocol)
2929
import Cardano.Node.Configuration.Socket
30+
import Cardano.Node.Peras.Trace (PerasVoteForgingUpdateResult)
3031
import Cardano.Node.Protocol (ProtocolInstantiationError)
3132
import Cardano.Node.Types (PeerSnapshotFile (..))
3233
import Cardano.Rpc.Server.Config (RpcEndpoint (..))
@@ -94,6 +95,9 @@ data StartupTrace blk =
9495
Api.SomeBlockType -- ^ expected
9596
Api.SomeBlockType -- ^ provided
9697

98+
-- | Node-owned Peras vote-forging lifecycle update.
99+
| PerasVoteForgingUpdate PerasVoteForgingUpdateResult
100+
97101
-- | Log that the network configuration is being updated.
98102
--
99103
| NetworkConfigUpdate

‎cardano-node/src/Cardano/Node/Tracing/Tracers/Startup.hs‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import Cardano.Network.NodeToNode (DiffusionMode (..))
2727
import Cardano.Network.OrphanInstances ()
2828
import Cardano.Node.Configuration.POM (NodeConfiguration, ncProtocol)
2929
import Cardano.Node.Configuration.Socket
30+
import Cardano.Node.Peras.Trace (PerasVoteForgingUpdateResult (..))
3031
import Cardano.Node.Startup
3132
import Cardano.Node.Types (PeerSnapshotFile (..))
3233
import Cardano.Rpc.Server.Config (RpcEndpoint (..))
@@ -212,6 +213,10 @@ instance ( Show (BlockNodeToNodeVersion blk)
212213
, "expected" .= String (showT expected)
213214
, "provided" .= String (showT provided)
214215
]
216+
forMachine _dtal (PerasVoteForgingUpdate outcome) =
217+
mconcat [ "kind" .= String "PerasVoteForgingUpdate"
218+
, "message" .= String (ppPerasVoteForgingUpdateResult outcome)
219+
]
215220
forMachine _dtal NetworkConfigUpdate =
216221
mconcat [ "kind" .= String "NetworkConfigUpdate"
217222
, "message" .= String "network configuration update" ]
@@ -345,6 +350,8 @@ instance MetaTrace (StartupTrace blk) where
345350
Namespace [] ["BlockForgingUpdateError"]
346351
namespaceFor BlockForgingBlockTypeMismatch {} =
347352
Namespace [] ["BlockForgingBlockTypeMismatch"]
353+
namespaceFor PerasVoteForgingUpdate {} =
354+
Namespace [] ["PerasVoteForgingUpdate"]
348355
namespaceFor NetworkConfigUpdate {} =
349356
Namespace [] ["NetworkConfigUpdate"]
350357
namespaceFor (LedgerPeerSnapshotLoaded {}) =
@@ -411,6 +418,13 @@ instance MetaTrace (StartupTrace blk) where
411418
severityFor (Namespace _ ["RpcTlsPrivateKeyPermissive"]) _ = Just Warning
412419
severityFor (Namespace _ ["BlockForgingUpdateError"]) _ = Just Error
413420
severityFor (Namespace _ ["BlockForgingBlockTypeMismatch"]) _ = Just Error
421+
severityFor (Namespace _ ["PerasVoteForgingUpdate"]) (Just (PerasVoteForgingUpdate outcome)) =
422+
Just $ case outcome of
423+
PerasVoteForgingDisabledUnsupported -> Warning
424+
PerasVoteForgingAmbiguousCredentials _ -> Warning
425+
PerasVoteForgingRetainedAfterError _ -> Error
426+
PerasVoteForgingInstalled -> Info
427+
PerasVoteForgingCleared -> Info
414428
severityFor (Namespace _ ["MovedTopLevelOption"]) _ = Just Warning
415429
severityFor (Namespace _ ["LedgerPeerSnapshot"]) _ = Just Notice
416430
severityFor (Namespace _ ["LedgerPeerSnapshot", "Incompatible"]) _ = Just Warning
@@ -435,6 +449,8 @@ instance MetaTrace (StartupTrace blk) where
435449
""
436450
documentFor (Namespace [] ["BlockForgingBlockTypeMismatch"]) = Just
437451
""
452+
documentFor (Namespace [] ["PerasVoteForgingUpdate"]) = Just
453+
"Peras vote-forging lifecycle update."
438454
documentFor (Namespace [] ["RpcConfigUpdate"]) = Just
439455
""
440456
documentFor (Namespace [] ["RpcConfigUpdateError"]) = Just
@@ -521,6 +537,7 @@ instance MetaTrace (StartupTrace blk) where
521537
, Namespace [] ["BlockForgingUpdate"]
522538
, Namespace [] ["BlockForgingUpdateError"]
523539
, Namespace [] ["BlockForgingBlockTypeMismatch"]
540+
, Namespace [] ["PerasVoteForgingUpdate"]
524541
, Namespace [] ["RpcConfigUpdate"]
525542
, Namespace [] ["RpcConfigUpdateError"]
526543
, Namespace [] ["RpcUnsupportedBlockType"]
@@ -559,6 +576,17 @@ nodeToNodeVersionToInt = \case
559576

560577
-- | Pretty print 'StartupInfoTrace'
561578
--
579+
ppPerasVoteForgingUpdateResult :: PerasVoteForgingUpdateResult -> Text
580+
ppPerasVoteForgingUpdateResult = \case
581+
PerasVoteForgingInstalled -> "installed Peras vote forging"
582+
PerasVoteForgingDisabledUnsupported ->
583+
"Peras vote forging disabled: resolved consensus package lacks the vote-forging API"
584+
PerasVoteForgingCleared -> "cleared Peras vote forging"
585+
PerasVoteForgingRetainedAfterError err ->
586+
"retained Peras vote forging after credential load error: " <> pack err
587+
PerasVoteForgingAmbiguousCredentials count ->
588+
"cleared Peras vote forging: " <> showT count <> " credentials are ambiguous"
589+
562590
ppStartupInfoTrace :: StartupTrace blk -> Text
563591
ppStartupInfoTrace (StartupInfo addresses
564592
localSocket
@@ -615,6 +643,8 @@ ppStartupInfoTrace (BlockForgingBlockTypeMismatch expected provided) =
615643
<> showT expected
616644
<> " provided "
617645
<> showT provided
646+
ppStartupInfoTrace (PerasVoteForgingUpdate outcome) =
647+
"Peras vote-forging lifecycle: " <> ppPerasVoteForgingUpdateResult outcome
618648

619649
ppStartupInfoTrace NetworkConfigUpdate = "Performing topology configuration update"
620650
ppStartupInfoTrace NetworkConfigUpdateUnsupported =

0 commit comments

Comments
 (0)