Skip to content

Commit ee232fb

Browse files
authored
Sanity checking for node configuration on startup (#874)
- This PR adds a a new mechanism for sanity checking node configuration on startup - These checks are intended to operate as a warning to users that they may have misconfigured their node, and are designed to be easily bypassed by a user who is _intentionally_ configuring their node in an unusual but possibly acceptable way - For safety reasons, the first change to `cardano-node` to support this will only log the exception in the standard way, though in future it should cause the node to terminate. We plan to add a way for the `cardano-node` tracer implementation to distinguish between sanity check issues which are fatal and those which are only warnings. - The first of these checks is simply to ensure that K, the security parameter, is consistent between all known eras. If eras' security parameters are different, a `SanityCheckIssue` exception will be traced in the new `sanityCheckIssueTracer`. There is an [associated branch in the cardano-node repository](https://github.com/IntersectMBO/cardano-node/tree/fraser-iohk/consensus-startup-sanity-checks) with changes required to support this additional `Tracer`.
2 parents 486753d + 8448a91 commit ee232fb

File tree

22 files changed

+357
-5
lines changed

22 files changed

+357
-5
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<!--
2+
A new scriv changelog fragment.
3+
4+
Uncomment the section that is right (remove the HTML comment wrapper).
5+
-->
6+
7+
<!--
8+
### Patch
9+
10+
- A bullet item for the Patch category.
11+
12+
-->
13+
14+
<!--
15+
16+
### Non-Breaking
17+
18+
- A bullet item for the Non-Breaking category
19+
20+
-->
21+
22+
<!--
23+
### Breaking
24+
25+
- A bullet item for the Breaking category.
26+
27+
-->

ouroboros-consensus-cardano/ouroboros-consensus-cardano.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ test-suite cardano-test
422422
Test.Consensus.Cardano.MiniProtocol.LocalTxSubmission.Server
423423
Test.Consensus.Cardano.Serialisation
424424
Test.Consensus.Cardano.SupportedNetworkProtocolVersion
425+
Test.Consensus.Cardano.SupportsSanityCheck
425426
Test.ThreadNet.AllegraMary
426427
Test.ThreadNet.Cardano
427428
Test.ThreadNet.MaryAlonzo

ouroboros-consensus-cardano/src/byron/Ouroboros/Consensus/Byron/Node.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ instance NodeInitStorage ByronBlock where
288288
instance BlockSupportsMetrics ByronBlock where
289289
isSelfIssued = isSelfIssuedConstUnknown
290290

291+
instance BlockSupportsSanityCheck ByronBlock where
292+
configAllSecurityParams =
293+
pure . pbftSecurityParam . pbftParams . topLevelConfigProtocol
294+
291295
deriving via SelectViewDiffusionPipelining ByronBlock
292296
instance BlockSupportsDiffusionPipelining ByronBlock
293297

ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Node.hs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ import qualified Cardano.Ledger.Shelley.API as SL
3232
import Data.Map.Strict (Map)
3333
import qualified Data.Map.Strict as Map
3434
import Ouroboros.Consensus.Block
35+
import Ouroboros.Consensus.Config
3536
import Ouroboros.Consensus.Ledger.SupportsProtocol
3637
(LedgerSupportsProtocol)
3738
import Ouroboros.Consensus.Node.ProtocolInfo
3839
import Ouroboros.Consensus.Node.Run
40+
import Ouroboros.Consensus.Protocol.Abstract
3941
import Ouroboros.Consensus.Protocol.TPraos
4042
import Ouroboros.Consensus.Shelley.Eras (EraCrypto)
4143
import Ouroboros.Consensus.Shelley.Ledger
@@ -104,6 +106,11 @@ instance ShelleyCompatible proto era => BlockSupportsMetrics (ShelleyBlock proto
104106
(SL.VKey 'SL.BlockIssuer (EraCrypto era))
105107
issuerVKeys = shelleyBlockIssuerVKeys cfg
106108

109+
instance ConsensusProtocol proto => BlockSupportsSanityCheck (ShelleyBlock proto era) where
110+
configAllSecurityParams = pure . protocolSecurityParam . topLevelConfigProtocol
107111

108-
instance (ShelleyCompatible proto era, LedgerSupportsProtocol (ShelleyBlock proto era))
109-
=> RunNode (ShelleyBlock proto era)
112+
instance
113+
( ShelleyCompatible proto era
114+
, LedgerSupportsProtocol (ShelleyBlock proto era)
115+
, BlockSupportsSanityCheck (ShelleyBlock proto era)
116+
) => RunNode (ShelleyBlock proto era)

ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/ShelleyHFC.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ shelleyTransition ShelleyPartialLedgerConfig{..}
162162
return newPParamsEpochNo
163163

164164
instance
165-
( ShelleyCompatible proto era,
166-
LedgerSupportsProtocol (ShelleyBlock proto era)
165+
( ShelleyCompatible proto era
166+
, LedgerSupportsProtocol (ShelleyBlock proto era)
167167
) => SingleEraBlock (ShelleyBlock proto era) where
168168
singleEraTransition pcfg _eraParams _eraStart ledgerState =
169169
-- TODO: We might be evaluating 'singleEraTransition' more than once when

ouroboros-consensus-cardano/src/unstable-byron-testlib/Ouroboros/Consensus/ByronDual/Node.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,9 @@ instance NodeInitStorage DualByronBlock where
249249
instance BlockSupportsMetrics DualByronBlock where
250250
isSelfIssued = isSelfIssuedConstUnknown
251251

252+
instance BlockSupportsSanityCheck DualByronBlock where
253+
configAllSecurityParams = pure . configSecurityParam
254+
252255
deriving via SelectViewDiffusionPipelining DualByronBlock
253256
instance BlockSupportsDiffusionPipelining DualByronBlock
254257

ouroboros-consensus-cardano/test/cardano-test/Main.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import qualified Test.Consensus.Cardano.Golden
77
import qualified Test.Consensus.Cardano.MiniProtocol.LocalTxSubmission.Server
88
import qualified Test.Consensus.Cardano.Serialisation
99
import qualified Test.Consensus.Cardano.SupportedNetworkProtocolVersion
10+
import qualified Test.Consensus.Cardano.SupportsSanityCheck
1011
import Test.Tasty
1112
import qualified Test.ThreadNet.AllegraMary
1213
import qualified Test.ThreadNet.Cardano
@@ -28,6 +29,7 @@ tests =
2829
, Test.Consensus.Cardano.Golden.tests
2930
, Test.Consensus.Cardano.Serialisation.tests
3031
, Test.Consensus.Cardano.SupportedNetworkProtocolVersion.tests
32+
, Test.Consensus.Cardano.SupportsSanityCheck.tests
3133
, Test.ThreadNet.AllegraMary.tests
3234
, Test.ThreadNet.Cardano.tests
3335
, Test.ThreadNet.MaryAlonzo.tests
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{-# LANGUAGE NamedFieldPuns #-}
2+
module Test.Consensus.Cardano.SupportsSanityCheck (tests) where
3+
4+
import Ouroboros.Consensus.Cardano.Block
5+
import Ouroboros.Consensus.Config
6+
import Ouroboros.Consensus.HardFork.Combinator.Basics
7+
import Ouroboros.Consensus.Node.ProtocolInfo
8+
import Ouroboros.Consensus.Shelley.Ledger.SupportsProtocol ()
9+
import Test.Consensus.Cardano.ProtocolInfo
10+
import qualified Test.QuickCheck as QC
11+
import qualified Test.QuickCheck.Gen as Gen
12+
import Test.Tasty
13+
import Test.Tasty.QuickCheck
14+
import qualified Test.ThreadNet.Infra.Shelley as Shelley
15+
import Test.Util.SanityCheck
16+
17+
tests :: TestTree
18+
tests = testGroup "SupportsSanityCheck"
19+
[ testProperty "cardano block top level config passes a sanity check" prop_cardanoBlockSanityChecks
20+
, testProperty "intentionally-misconfigured top level config fails a sanity check" prop_intentionallyBrokenConfigDoesNotSanityCheck
21+
]
22+
23+
prop_cardanoBlockSanityChecks :: QC.Property
24+
prop_cardanoBlockSanityChecks =
25+
forAllBlind genSimpleTestProtocolInfo (prop_sanityChecks . pInfoConfig)
26+
27+
prop_intentionallyBrokenConfigDoesNotSanityCheck :: QC.Property
28+
prop_intentionallyBrokenConfigDoesNotSanityCheck =
29+
forAllBlind genSimpleTestProtocolInfo $ \pinfo ->
30+
let saneTopLevelConfig =
31+
pInfoConfig pinfo
32+
brokenConfig = breakTopLevelConfig saneTopLevelConfig
33+
in expectFailure $ prop_sanityChecks brokenConfig
34+
35+
breakTopLevelConfig :: TopLevelConfig (CardanoBlock StandardCrypto) -> TopLevelConfig (CardanoBlock StandardCrypto)
36+
breakTopLevelConfig tlc =
37+
let TopLevelConfig{topLevelConfigProtocol} = tlc
38+
HardForkConsensusConfig{hardForkConsensusConfigK} = topLevelConfigProtocol
39+
SecurityParam k = hardForkConsensusConfigK
40+
in tlc
41+
{ topLevelConfigProtocol = topLevelConfigProtocol
42+
{ hardForkConsensusConfigK = SecurityParam (succ k)
43+
}
44+
}
45+
46+
genSimpleTestProtocolInfo :: Gen (ProtocolInfo (CardanoBlock StandardCrypto))
47+
genSimpleTestProtocolInfo = do
48+
setup <- arbitrary
49+
pure $
50+
mkSimpleTestProtocolInfo
51+
(decentralizationParam setup)
52+
(securityParam setup)
53+
(byronSlotLength setup)
54+
(shelleySlotLength setup)
55+
(hardForkSpec setup)
56+
57+
data SimpleTestProtocolInfoSetup = SimpleTestProtocolInfoSetup
58+
{ decentralizationParam :: Shelley.DecentralizationParam
59+
, securityParam :: SecurityParam
60+
, byronSlotLength :: ByronSlotLengthInSeconds
61+
, shelleySlotLength :: ShelleySlotLengthInSeconds
62+
, hardForkSpec :: HardForkSpec
63+
}
64+
65+
instance Arbitrary SimpleTestProtocolInfoSetup where
66+
arbitrary = do
67+
SimpleTestProtocolInfoSetup
68+
<$> arbitrary
69+
<*> genSecurityParam
70+
<*> genByronSlotLength
71+
<*> genShelleySlotLength
72+
<*> genHardForkSpec
73+
where
74+
genSecurityParam =
75+
SecurityParam <$> Gen.choose (8, 12)
76+
genByronSlotLength =
77+
ByronSlotLengthInSeconds <$> Gen.choose (1, 4)
78+
genShelleySlotLength =
79+
ShelleySlotLengthInSeconds <$> Gen.choose (1, 4)
80+
genHardForkSpec =
81+
hardForkInto <$> Gen.chooseEnum (Byron, Conway)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!--
2+
A new scriv changelog fragment.
3+
4+
Uncomment the section that is right (remove the HTML comment wrapper).
5+
-->
6+
7+
<!--
8+
### Patch
9+
10+
- A bullet item for the Patch category.
11+
12+
-->
13+
14+
### Non-Breaking
15+
16+
- Adds a Tracer for startup sanity check warnings in Ouroboros.Consensus.Node.Tracers (see BlockSupportsSanityCheck in ouroboros-consensus)
17+
18+
19+
<!--
20+
### Breaking
21+
22+
- A bullet item for the Breaking category.
23+
24+
-->

ouroboros-consensus-diffusion/src/ouroboros-consensus-diffusion/Ouroboros/Consensus/Node.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ import qualified Codec.CBOR.Encoding as CBOR
6060
import Codec.Serialise (DeserialiseFailure)
6161
import qualified Control.Concurrent.Class.MonadSTM.Strict as StrictSTM
6262
import Control.DeepSeq (NFData)
63-
import Control.Monad (when)
63+
import Control.Monad (forM_, when)
6464
import Control.Monad.Class.MonadTime.SI (MonadTime)
6565
import Control.Monad.Class.MonadTimer.SI (MonadTimer)
6666
import Control.Tracer (Tracer, contramap, traceWith)
@@ -422,6 +422,9 @@ runWith RunNodeArgs{..} encAddrNtN decAddrNtN LowLevelRunNodeArgs{..} =
422422
-- ChainDB to detect and recover from any disk corruption.
423423
= ChainDB.ensureValidateAll
424424

425+
forM_ (sanityCheckConfig cfg) $ \issue ->
426+
traceWith (consensusSanityCheckTracer rnTraceConsensus) issue
427+
425428
(chainDB, finalArgs) <- openChainDB
426429
registry
427430
inFuture

0 commit comments

Comments
 (0)