From 4673971e52281bae69fbc0d5b427da71de7d1ef5 Mon Sep 17 00:00:00 2001 From: Alexander Esgen Date: Mon, 22 Jan 2024 13:23:21 +0100 Subject: [PATCH] Implement lightweight checkpointing Lightweight checkpointing is a mechanism to ensure that new nodes end up in the correct chain even when the chain is too sparse for normal operation of Praos and Genesis. The idea is to supply the new node with a list of block hashes that should be present on the chain at specific block numbers. This list is provided in the TopLevelConfig record, and it is used during validation of headers in validateIfCheckpoint called by validateEnvelope. If the hashes of checkpoints don't match the hashes of a supplied header for a given block number, then validation of the header fails. The substance of the change is modifying TopLevelConfig and validateEnvelope. Most other changes derive from these modifications. There are three new unit tests of validateIfCheckpoint added in ouroboros-consensus:test:consensus-test. --- ...ndo.dominguez_lightweight_checkpointing.md | 24 +++++ .../byron/Ouroboros/Consensus/Byron/Node.hs | 9 +- .../Ouroboros/Consensus/Cardano/Node.hs | 6 ++ .../Consensus/Shelley/Node/TPraos.hs | 11 +- .../Ouroboros/Consensus/ByronDual/Node.hs | 1 + .../Test/Consensus/Cardano/ProtocolInfo.hs | 2 + .../Cardano/Node/Protocol/Cardano.hs | 2 + .../Cardano/Tools/DBAnalyser/Block/Cardano.hs | 2 + .../20240122_214152_facundo.dominguez_HEAD.md | 23 ++++ .../Test/Consensus/HardFork/Combinator.hs | 1 + .../Test/Consensus/PeerSimulator/Config.hs | 12 ++- .../bench/ChainSync-client-bench/Main.hs | 9 +- .../20240122_203705_facundo.dominguez_HEAD.md | 24 +++++ ouroboros-consensus/ouroboros-consensus.cabal | 1 + .../Ouroboros/Consensus/Config.hs | 70 ++++++++---- .../Consensus/HardFork/Combinator/Basics.hs | 7 +- .../HardFork/Combinator/Embed/Binary.hs | 1 + .../HardFork/Combinator/Embed/Unary.hs | 2 + .../Ouroboros/Consensus/HeaderValidation.hs | 31 +++++- .../Ouroboros/Consensus/Ledger/Dual.hs | 11 +- .../Ouroboros/Consensus/Ledger/Extended.hs | 1 + .../Test/Util/TestBlock.hs | 9 +- .../Ouroboros/Consensus/Mock/Node/BFT.hs | 9 +- .../Ouroboros/Consensus/Mock/Node/PBFT.hs | 9 +- .../Ouroboros/Consensus/Mock/Node/Praos.hs | 9 +- .../Consensus/Mock/Node/PraosRule.hs | 9 +- .../test/consensus-test/Main.hs | 2 + .../Test/Consensus/HeaderValidation.hs | 100 ++++++++++++++++++ .../MiniProtocol/ChainSync/Client.hs | 9 +- .../MiniProtocol/LocalStateQuery/Server.hs | 9 +- .../Test/Ouroboros/Storage/TestBlock.hs | 5 +- 31 files changed, 343 insertions(+), 77 deletions(-) create mode 100644 ouroboros-consensus-cardano/changelog.d/20240111_195320_facundo.dominguez_lightweight_checkpointing.md create mode 100644 ouroboros-consensus-diffusion/changelog.d/20240122_214152_facundo.dominguez_HEAD.md create mode 100644 ouroboros-consensus/changelog.d/20240122_203705_facundo.dominguez_HEAD.md create mode 100644 ouroboros-consensus/test/consensus-test/Test/Consensus/HeaderValidation.hs diff --git a/ouroboros-consensus-cardano/changelog.d/20240111_195320_facundo.dominguez_lightweight_checkpointing.md b/ouroboros-consensus-cardano/changelog.d/20240111_195320_facundo.dominguez_lightweight_checkpointing.md new file mode 100644 index 0000000000..068986f186 --- /dev/null +++ b/ouroboros-consensus-cardano/changelog.d/20240111_195320_facundo.dominguez_lightweight_checkpointing.md @@ -0,0 +1,24 @@ + + + + +### Breaking + +- Implement lightweight checkpointing [#449](https://github.com/IntersectMBO/ouroboros-consensus/issues/449). + A validation to help nodes follow the historical chain. A new field `cardanoCheckpoints` + has been added to the record `ProtocolParams (CardanoBlock c)` record, with a new type `CheckpointsMap`. + diff --git a/ouroboros-consensus-cardano/src/byron/Ouroboros/Consensus/Byron/Node.hs b/ouroboros-consensus-cardano/src/byron/Ouroboros/Consensus/Byron/Node.hs index 2fb6697520..3977c59cc5 100644 --- a/ouroboros-consensus-cardano/src/byron/Ouroboros/Consensus/Byron/Node.hs +++ b/ouroboros-consensus-cardano/src/byron/Ouroboros/Consensus/Byron/Node.hs @@ -192,10 +192,11 @@ protocolInfoByron ProtocolParamsByron { topLevelConfigProtocol = PBftConfig { pbftParams = byronPBftParams compactedGenesisConfig mSigThresh } - , topLevelConfigLedger = compactedGenesisConfig - , topLevelConfigBlock = blockConfig - , topLevelConfigCodec = mkByronCodecConfig compactedGenesisConfig - , topLevelConfigStorage = ByronStorageConfig blockConfig + , topLevelConfigLedger = compactedGenesisConfig + , topLevelConfigBlock = blockConfig + , topLevelConfigCodec = mkByronCodecConfig compactedGenesisConfig + , topLevelConfigStorage = ByronStorageConfig blockConfig + , topLevelConfigCheckpoints = emptyCheckpointsMap } , pInfoInitLedger = ExtLedgerState { -- Important: don't pass the compacted genesis config to diff --git a/ouroboros-consensus-cardano/src/ouroboros-consensus-cardano/Ouroboros/Consensus/Cardano/Node.hs b/ouroboros-consensus-cardano/src/ouroboros-consensus-cardano/Ouroboros/Consensus/Cardano/Node.hs index 103c2b6da3..631bb91d9d 100644 --- a/ouroboros-consensus-cardano/src/ouroboros-consensus-cardano/Ouroboros/Consensus/Cardano/Node.hs +++ b/ouroboros-consensus-cardano/src/ouroboros-consensus-cardano/Ouroboros/Consensus/Cardano/Node.hs @@ -524,6 +524,7 @@ data instance ProtocolParams (CardanoBlock c) = ProtocolParamsCardano { , shelleyBasedProtocolParams :: ProtocolParamsShelleyBased c , cardanoHardForkTriggers :: CardanoHardForkTriggers , cardanoLedgerTransitionConfig :: L.TransitionConfig (L.LatestKnownEra c) + , cardanoCheckpoints :: CheckpointsMap (CardanoBlock c) } type CardanoProtocolParams c = ProtocolParams (CardanoBlock c) @@ -539,6 +540,7 @@ pattern CardanoProtocolParams :: -> ProtocolParams (ShelleyBlock (Praos c) (ConwayEra c)) -> CardanoHardForkTriggers -> L.TransitionConfig (L.LatestKnownEra c) + -> CheckpointsMap (CardanoBlock c) -> CardanoProtocolParams c pattern CardanoProtocolParams { paramsByron @@ -551,6 +553,7 @@ pattern CardanoProtocolParams { , paramsConway , hardForkTriggers , ledgerTransitionConfig + , checkpoints } = ProtocolParamsCardano { cardanoProtocolParamsPerEra = PerEraProtocolParams @@ -566,6 +569,7 @@ pattern CardanoProtocolParams { , shelleyBasedProtocolParams = paramsShelleyBased , cardanoHardForkTriggers = hardForkTriggers , cardanoLedgerTransitionConfig = ledgerTransitionConfig + , cardanoCheckpoints = checkpoints } {-# COMPLETE CardanoProtocolParams #-} @@ -618,6 +622,7 @@ protocolInfoCardano paramsCardano , triggerHardForkConway } , ledgerTransitionConfig + , checkpoints } = paramsCardano genesisShelley = ledgerTransitionConfig ^. L.tcShelleyGenesisL @@ -944,6 +949,7 @@ protocolInfoCardano paramsCardano (Shelley.ShelleyStorageConfig tpraosSlotsPerKESPeriod k) (Shelley.ShelleyStorageConfig tpraosSlotsPerKESPeriod k) (Shelley.ShelleyStorageConfig tpraosSlotsPerKESPeriod k) + , topLevelConfigCheckpoints = checkpoints } -- When the initial ledger state is not in the Byron era, register the diff --git a/ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Node/TPraos.hs b/ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Node/TPraos.hs index 7db400bb1c..81ea64bd91 100644 --- a/ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Node/TPraos.hs +++ b/ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Node/TPraos.hs @@ -295,11 +295,12 @@ protocolInfoTPraosShelleyBased ProtocolParamsShelleyBased { topLevelConfig :: TopLevelConfig (ShelleyBlock (TPraos c) era) topLevelConfig = TopLevelConfig { - topLevelConfigProtocol = consensusConfig - , topLevelConfigLedger = ledgerConfig - , topLevelConfigBlock = blockConfig - , topLevelConfigCodec = ShelleyCodecConfig - , topLevelConfigStorage = storageConfig + topLevelConfigProtocol = consensusConfig + , topLevelConfigLedger = ledgerConfig + , topLevelConfigBlock = blockConfig + , topLevelConfigCodec = ShelleyCodecConfig + , topLevelConfigStorage = storageConfig + , topLevelConfigCheckpoints = emptyCheckpointsMap } consensusConfig :: ConsensusConfig (BlockProtocol (ShelleyBlock (TPraos c) era)) diff --git a/ouroboros-consensus-cardano/src/unstable-byron-testlib/Ouroboros/Consensus/ByronDual/Node.hs b/ouroboros-consensus-cardano/src/unstable-byron-testlib/Ouroboros/Consensus/ByronDual/Node.hs index 87a59db1e8..c9ecff1b49 100644 --- a/ouroboros-consensus-cardano/src/unstable-byron-testlib/Ouroboros/Consensus/ByronDual/Node.hs +++ b/ouroboros-consensus-cardano/src/unstable-byron-testlib/Ouroboros/Consensus/ByronDual/Node.hs @@ -107,6 +107,7 @@ protocolInfoDualByron abstractGenesis@ByronSpecGenesis{..} params credss = dualStorageConfigMain = ByronStorageConfig concreteConfig , dualStorageConfigAux = ByronSpecStorageConfig } + , topLevelConfigCheckpoints = emptyCheckpointsMap } , pInfoInitLedger = ExtLedgerState { ledgerState = DualLedgerState { diff --git a/ouroboros-consensus-cardano/src/unstable-cardano-testlib/Test/Consensus/Cardano/ProtocolInfo.hs b/ouroboros-consensus-cardano/src/unstable-cardano-testlib/Test/Consensus/Cardano/ProtocolInfo.hs index f857a13185..2d020a4677 100644 --- a/ouroboros-consensus-cardano/src/unstable-cardano-testlib/Test/Consensus/Cardano/ProtocolInfo.hs +++ b/ouroboros-consensus-cardano/src/unstable-cardano-testlib/Test/Consensus/Cardano/ProtocolInfo.hs @@ -40,6 +40,7 @@ import Ouroboros.Consensus.Cardano.Node (CardanoHardForkConstraints, CardanoHardForkTriggers (..), ProtocolParams (..), TriggerHardFork (TriggerHardForkAtEpoch, TriggerHardForkNotDuringThisExecution), protocolInfoCardano) +import Ouroboros.Consensus.Config (emptyCheckpointsMap) import Ouroboros.Consensus.Config.SecurityParam (SecurityParam (..)) import qualified Ouroboros.Consensus.Mempool as Mempool import Ouroboros.Consensus.Node.ProtocolInfo (NumCoreNodes (..), @@ -326,6 +327,7 @@ mkTestProtocolInfo SL.exampleAlonzoGenesis SL.exampleConwayGenesis ) + emptyCheckpointsMap ) where diff --git a/ouroboros-consensus-cardano/src/unstable-cardano-tools/Cardano/Node/Protocol/Cardano.hs b/ouroboros-consensus-cardano/src/unstable-cardano-tools/Cardano/Node/Protocol/Cardano.hs index f45e9297ab..f63ada1f0c 100644 --- a/ouroboros-consensus-cardano/src/unstable-cardano-tools/Cardano/Node/Protocol/Cardano.hs +++ b/ouroboros-consensus-cardano/src/unstable-cardano-tools/Cardano/Node/Protocol/Cardano.hs @@ -33,6 +33,7 @@ import Ouroboros.Consensus.Cardano import qualified Ouroboros.Consensus.Cardano as Consensus import qualified Ouroboros.Consensus.Cardano.CanHardFork as Consensus import Ouroboros.Consensus.Cardano.Condense () +import Ouroboros.Consensus.Config (emptyCheckpointsMap) import Ouroboros.Consensus.HardFork.Combinator.Condense () import qualified Ouroboros.Consensus.Mempool as Mempool @@ -296,6 +297,7 @@ mkSomeConsensusProtocolCardano NodeByronProtocolConfiguration { Just epochNo -> Consensus.TriggerHardForkAtEpoch epochNo } transitionLedgerConfig + emptyCheckpointsMap ) ------------------------------------------------------------------------------ diff --git a/ouroboros-consensus-cardano/src/unstable-cardano-tools/Cardano/Tools/DBAnalyser/Block/Cardano.hs b/ouroboros-consensus-cardano/src/unstable-cardano-tools/Cardano/Tools/DBAnalyser/Block/Cardano.hs index 77db3cf039..13587a153b 100644 --- a/ouroboros-consensus-cardano/src/unstable-cardano-tools/Cardano/Tools/DBAnalyser/Block/Cardano.hs +++ b/ouroboros-consensus-cardano/src/unstable-cardano-tools/Cardano/Tools/DBAnalyser/Block/Cardano.hs @@ -54,6 +54,7 @@ import Ouroboros.Consensus.Cardano import Ouroboros.Consensus.Cardano.Block (CardanoEras) import Ouroboros.Consensus.Cardano.Node (TriggerHardFork (..), protocolInfoCardano) +import Ouroboros.Consensus.Config (emptyCheckpointsMap) import Ouroboros.Consensus.HardFork.Combinator (HardForkBlock (..), OneEraBlock (..), OneEraHash (..), getHardForkState, hardForkLedgerStatePerEra) @@ -322,6 +323,7 @@ mkCardanoProtocolInfo genesisByron signatureThreshold transitionConfig initialNo } triggers transitionConfig + emptyCheckpointsMap ) where diff --git a/ouroboros-consensus-diffusion/changelog.d/20240122_214152_facundo.dominguez_HEAD.md b/ouroboros-consensus-diffusion/changelog.d/20240122_214152_facundo.dominguez_HEAD.md new file mode 100644 index 0000000000..0556ddcfe2 --- /dev/null +++ b/ouroboros-consensus-diffusion/changelog.d/20240122_214152_facundo.dominguez_HEAD.md @@ -0,0 +1,23 @@ + + + + +### Breaking + +- Integrate changes for lightweight checkpointing [#449](https://github.com/IntersectMBO/ouroboros-consensus/issues/449), + which required adding a field to `TopLevelConfig`. + diff --git a/ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/HardFork/Combinator.hs b/ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/HardFork/Combinator.hs index 305a3c7d10..bff9180ea4 100644 --- a/ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/HardFork/Combinator.hs +++ b/ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/HardFork/Combinator.hs @@ -283,6 +283,7 @@ prop_simple_hfc_convergence testSetup@TestSetup{..} = :* SCfgB :* Nil } + , topLevelConfigCheckpoints = emptyCheckpointsMap } consensusConfigA :: CoreNodeId -> ConsensusConfig ProtocolA diff --git a/ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/PeerSimulator/Config.hs b/ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/PeerSimulator/Config.hs index 2719fcf88f..70dd3387e1 100644 --- a/ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/PeerSimulator/Config.hs +++ b/ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/PeerSimulator/Config.hs @@ -5,7 +5,8 @@ module Test.Consensus.PeerSimulator.Config (defaultCfg) where import Cardano.Crypto.DSIGN (SignKeyDSIGN (..), VerKeyDSIGN (..)) import Cardano.Slotting.Time (SlotLength, slotLengthFromSec) import qualified Data.Map.Strict as Map -import Ouroboros.Consensus.Config (SecurityParam, TopLevelConfig (..)) +import Ouroboros.Consensus.Config (SecurityParam, TopLevelConfig (..), + emptyCheckpointsMap) import qualified Ouroboros.Consensus.HardFork.History.EraParams as HardFork import Ouroboros.Consensus.Node.ProtocolInfo (NumCoreNodes (NumCoreNodes)) @@ -33,10 +34,11 @@ defaultCfg secParam = TopLevelConfig { , (CoreId (CoreNodeId 1), VerKeyMockDSIGN 1) ] } - , topLevelConfigLedger = eraParams - , topLevelConfigBlock = TestBlockConfig numCoreNodes - , topLevelConfigCodec = TestBlockCodecConfig - , topLevelConfigStorage = TestBlockStorageConfig + , topLevelConfigLedger = eraParams + , topLevelConfigBlock = TestBlockConfig numCoreNodes + , topLevelConfigCodec = TestBlockCodecConfig + , topLevelConfigStorage = TestBlockStorageConfig + , topLevelConfigCheckpoints = emptyCheckpointsMap } where -- REVIEW: Make it 1s or a parameter? diff --git a/ouroboros-consensus/bench/ChainSync-client-bench/Main.hs b/ouroboros-consensus/bench/ChainSync-client-bench/Main.hs index 0b1882ffd0..869d0f7017 100644 --- a/ouroboros-consensus/bench/ChainSync-client-bench/Main.hs +++ b/ouroboros-consensus/bench/ChainSync-client-bench/Main.hs @@ -235,10 +235,11 @@ topConfig = TopLevelConfig { , (CoreId (CoreNodeId 1), VerKeyMockDSIGN 1) ] } - , topLevelConfigLedger = eraParams - , topLevelConfigBlock = TB.TestBlockConfig numCoreNodes - , topLevelConfigCodec = TB.TestBlockCodecConfig - , topLevelConfigStorage = TB.TestBlockStorageConfig + , topLevelConfigLedger = eraParams + , topLevelConfigBlock = TB.TestBlockConfig numCoreNodes + , topLevelConfigCodec = TB.TestBlockCodecConfig + , topLevelConfigStorage = TB.TestBlockStorageConfig + , topLevelConfigCheckpoints = emptyCheckpointsMap } where eraParams :: HardFork.EraParams diff --git a/ouroboros-consensus/changelog.d/20240122_203705_facundo.dominguez_HEAD.md b/ouroboros-consensus/changelog.d/20240122_203705_facundo.dominguez_HEAD.md new file mode 100644 index 0000000000..85a4a1a53a --- /dev/null +++ b/ouroboros-consensus/changelog.d/20240122_203705_facundo.dominguez_HEAD.md @@ -0,0 +1,24 @@ + + + + +### Breaking + +- Implement lightweight checkpointing [#449](https://github.com/IntersectMBO/ouroboros-consensus/issues/449). + A validation to help nodes follow the historical chain. A new field `topLevelConfigCheckpoints` + has been added to the `TopLevelConfig` record, with a new type `CheckpointsMap`. + diff --git a/ouroboros-consensus/ouroboros-consensus.cabal b/ouroboros-consensus/ouroboros-consensus.cabal index 92e499c877..eee2c65fe2 100644 --- a/ouroboros-consensus/ouroboros-consensus.cabal +++ b/ouroboros-consensus/ouroboros-consensus.cabal @@ -493,6 +493,7 @@ test-suite consensus-test Test.Consensus.HardFork.History Test.Consensus.HardFork.Infra Test.Consensus.HardFork.Summary + Test.Consensus.HeaderValidation Test.Consensus.Mempool Test.Consensus.Mempool.Fairness Test.Consensus.Mempool.Fairness.TestBlock diff --git a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Config.hs b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Config.hs index 7c355e01e2..43c0b892e8 100644 --- a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Config.hs +++ b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Config.hs @@ -1,16 +1,21 @@ -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} -{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE UndecidableInstances #-} module Ouroboros.Consensus.Config ( -- * The top-level node configuration TopLevelConfig (..) , castTopLevelConfig , mkTopLevelConfig + -- ** Checkpoints map + , CheckpointsMap (..) + , castCheckpointsMap + , emptyCheckpointsMap -- ** Derived extraction functions , configBlock , configCodec @@ -24,6 +29,7 @@ module Ouroboros.Consensus.Config ( ) where import Data.Coerce +import Data.Map.Strict (Map) import GHC.Generics (Generic) import NoThunks.Class (NoThunks) import Ouroboros.Consensus.Block.Abstract @@ -37,11 +43,12 @@ import Ouroboros.Consensus.Protocol.Abstract -- | The top-level node configuration data TopLevelConfig blk = TopLevelConfig { - topLevelConfigProtocol :: !(ConsensusConfig (BlockProtocol blk)) - , topLevelConfigLedger :: !(LedgerConfig blk) - , topLevelConfigBlock :: !(BlockConfig blk) - , topLevelConfigCodec :: !(CodecConfig blk) - , topLevelConfigStorage :: !(StorageConfig blk) + topLevelConfigProtocol :: !(ConsensusConfig (BlockProtocol blk)) + , topLevelConfigLedger :: !(LedgerConfig blk) + , topLevelConfigBlock :: !(BlockConfig blk) + , topLevelConfigCodec :: !(CodecConfig blk) + , topLevelConfigStorage :: !(StorageConfig blk) + , topLevelConfigCheckpoints :: !(CheckpointsMap blk) } deriving (Generic) @@ -50,16 +57,36 @@ instance ( ConsensusProtocol (BlockProtocol blk) , NoThunks (BlockConfig blk) , NoThunks (CodecConfig blk) , NoThunks (StorageConfig blk) + , NoThunks (HeaderHash blk) ) => NoThunks (TopLevelConfig blk) +-- | Checkpoints are block hashes that are expected to be present in the honest +-- historical chain. +-- +-- Each checkpoint is associated with a 'BlockNo', and any block with a +-- 'BlockNo' in the checkpoints map is expected to have the corresponding hash. +-- +newtype CheckpointsMap blk = CheckpointsMap { + unCheckpointsMap :: Map BlockNo (HeaderHash blk) + } + deriving (Generic, Monoid, Semigroup) + +instance ( NoThunks (HeaderHash blk) + ) => NoThunks (CheckpointsMap blk) + +emptyCheckpointsMap :: CheckpointsMap blk +emptyCheckpointsMap = mempty + mkTopLevelConfig :: ConsensusConfig (BlockProtocol blk) -> LedgerConfig blk -> BlockConfig blk -> CodecConfig blk -> StorageConfig blk + -> CheckpointsMap blk -> TopLevelConfig blk -mkTopLevelConfig = TopLevelConfig +mkTopLevelConfig prtclCfg ledgerCfg blockCfg codecCfg storageCfg checkpointsMap = + TopLevelConfig prtclCfg ledgerCfg blockCfg codecCfg storageCfg checkpointsMap configConsensus :: TopLevelConfig blk -> ConsensusConfig (BlockProtocol blk) configConsensus = topLevelConfigProtocol @@ -87,12 +114,19 @@ castTopLevelConfig :: , Coercible (BlockConfig blk) (BlockConfig blk') , Coercible (CodecConfig blk) (CodecConfig blk') , Coercible (StorageConfig blk) (StorageConfig blk') + , Coercible (HeaderHash blk) (HeaderHash blk') ) => TopLevelConfig blk -> TopLevelConfig blk' castTopLevelConfig TopLevelConfig{..} = TopLevelConfig{ - topLevelConfigProtocol = coerce topLevelConfigProtocol - , topLevelConfigLedger = topLevelConfigLedger - , topLevelConfigBlock = coerce topLevelConfigBlock - , topLevelConfigCodec = coerce topLevelConfigCodec - , topLevelConfigStorage = coerce topLevelConfigStorage + topLevelConfigProtocol = coerce topLevelConfigProtocol + , topLevelConfigLedger = topLevelConfigLedger + , topLevelConfigBlock = coerce topLevelConfigBlock + , topLevelConfigCodec = coerce topLevelConfigCodec + , topLevelConfigStorage = coerce topLevelConfigStorage + , topLevelConfigCheckpoints = coerce topLevelConfigCheckpoints } + +castCheckpointsMap :: + Coercible (HeaderHash blk) (HeaderHash blk') + => CheckpointsMap blk -> CheckpointsMap blk' +castCheckpointsMap = coerce diff --git a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Basics.hs b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Basics.hs index a565cedb2a..c211e64390 100644 --- a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Basics.hs +++ b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Basics.hs @@ -208,7 +208,12 @@ distribTopLevelConfig ei tlc = (completeLedgerConfig' ei cfgLedger) cfgBlock cfgCodec - cfgStorage)) + cfgStorage + -- topLevelConfigCheckpoints is only used in validateEnvelope, + -- where it comes from the TopLevelConfig of the HardForkBlock. + -- + -- The checkpoints of the underlying blocks are not used. + emptyCheckpointsMap)) `hap` (getPerEraConsensusConfig $ hardForkConsensusConfigPerEra (configConsensus tlc)) diff --git a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Embed/Binary.hs b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Embed/Binary.hs index eadee53b08..1ec57daba9 100644 --- a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Embed/Binary.hs +++ b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Embed/Binary.hs @@ -77,6 +77,7 @@ protocolInfoBinary protocolInfo1 blockForging1 eraParams1 toPartialConsensusConf HardForkStorageConfig $ PerEraStorageConfig $ (storageConfig1 :* storageConfig2 :* Nil) + , topLevelConfigCheckpoints = emptyCheckpointsMap } , pInfoInitLedger = ExtLedgerState { ledgerState = diff --git a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Embed/Unary.hs b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Embed/Unary.hs index 5bfe55490d..612723d97d 100644 --- a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Embed/Unary.hs +++ b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Embed/Unary.hs @@ -264,6 +264,7 @@ instance Isomorphic TopLevelConfig where (project $ configBlock tlc) (project $ configCodec tlc) (project $ configStorage tlc) + emptyCheckpointsMap where ei :: EpochInfo (Except PastHorizonException) ei = noHardForksEpochInfo $ project tlc @@ -294,6 +295,7 @@ instance Isomorphic TopLevelConfig where (inject $ configBlock tlc) (inject $ configCodec tlc) (inject $ configStorage tlc) + emptyCheckpointsMap where eraParams = getEraParams tlc diff --git a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HeaderValidation.hs b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HeaderValidation.hs index 42f6f0caf7..302c2dbbe1 100644 --- a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HeaderValidation.hs +++ b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HeaderValidation.hs @@ -60,11 +60,12 @@ import Cardano.Binary (enforceSize) import Codec.CBOR.Decoding (Decoder) import Codec.CBOR.Encoding (Encoding, encodeListLen) import Codec.Serialise (decode, encode) -import Control.Monad (unless) +import Control.Monad (unless, when) import Control.Monad.Except (Except, runExcept, throwError, withExcept) import Data.Coerce import Data.Kind (Type) +import qualified Data.Map.Strict as Map import Data.Proxy import Data.Void (Void) import GHC.Generics (Generic) @@ -74,6 +75,7 @@ import Ouroboros.Consensus.Block import Ouroboros.Consensus.Config import Ouroboros.Consensus.Protocol.Abstract import Ouroboros.Consensus.Ticked +import Ouroboros.Consensus.Util (whenJust) import Ouroboros.Consensus.Util.Assert import qualified Ouroboros.Consensus.Util.CBOR as Util.CBOR import Ouroboros.Network.AnchoredSeq (Anchorable (..)) @@ -229,6 +231,13 @@ data HeaderEnvelopeError blk = -- We record the current tip as well as the prev hash of the new block. | UnexpectedPrevHash !(WithOrigin (HeaderHash blk)) !(ChainHash blk) + -- | The block at the given block number has a hash which does not match the + -- expected checkpoint hash. + -- + -- > CheckpointMismatch blockNo expected actual + -- + | CheckpointMismatch !BlockNo !(HeaderHash blk) !(HeaderHash blk) + -- | Block specific envelope error | OtherHeaderEnvelopeError !(OtherHeaderEnvelopeError blk) deriving (Generic) @@ -243,10 +252,11 @@ castHeaderEnvelopeError :: ( HeaderHash blk ~ HeaderHash blk' ) => HeaderEnvelopeError blk -> HeaderEnvelopeError blk' castHeaderEnvelopeError = \case - OtherHeaderEnvelopeError err -> OtherHeaderEnvelopeError err - UnexpectedBlockNo expected actual -> UnexpectedBlockNo expected actual - UnexpectedSlotNo expected actual -> UnexpectedSlotNo expected actual - UnexpectedPrevHash oldTip prevHash -> UnexpectedPrevHash oldTip (castHash prevHash) + OtherHeaderEnvelopeError err -> OtherHeaderEnvelopeError err + UnexpectedBlockNo expected actual -> UnexpectedBlockNo expected actual + UnexpectedSlotNo expected actual -> UnexpectedSlotNo expected actual + UnexpectedPrevHash oldTip prevHash -> UnexpectedPrevHash oldTip (castHash prevHash) + CheckpointMismatch bNo expected actual -> CheckpointMismatch bNo expected actual -- | Ledger-independent envelope validation (block, slot, hash) class ( HasHeader (Header blk) @@ -310,6 +320,7 @@ validateEnvelope cfg ledgerView oldTip hdr = do throwError $ UnexpectedSlotNo expectedSlotNo actualSlotNo unless (checkPrevHash' (annTipHash <$> oldTip) actualPrevHash) $ throwError $ UnexpectedPrevHash (annTipHash <$> oldTip) actualPrevHash + validateIfCheckpoint (topLevelConfigCheckpoints cfg) hdr withExcept OtherHeaderEnvelopeError $ additionalEnvelopeChecks cfg ledgerView hdr where @@ -346,6 +357,16 @@ validateEnvelope cfg ledgerView oldTip hdr = do p = Proxy @blk +validateIfCheckpoint :: + HasHeader (Header blk) + => CheckpointsMap blk + -> Header blk + -> Except (HeaderEnvelopeError blk) () +validateIfCheckpoint checkpointsMap hdr = + whenJust (Map.lookup (blockNo hdr) $ unCheckpointsMap checkpointsMap) $ + \checkpoint -> when (headerHash hdr /= checkpoint) $ + throwError $ CheckpointMismatch (blockNo hdr) checkpoint (headerHash hdr) + {------------------------------------------------------------------------------- Errors -------------------------------------------------------------------------------} diff --git a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Ledger/Dual.hs b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Ledger/Dual.hs index e6231574b0..9d1e4a7ef8 100644 --- a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Ledger/Dual.hs +++ b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Ledger/Dual.hs @@ -176,11 +176,12 @@ instance ConfigSupportsNode m => ConfigSupportsNode (DualBlock m a) where -- | This is only used for block production dualTopLevelConfigMain :: TopLevelConfig (DualBlock m a) -> TopLevelConfig m dualTopLevelConfigMain TopLevelConfig{..} = TopLevelConfig{ - topLevelConfigProtocol = topLevelConfigProtocol - , topLevelConfigLedger = dualLedgerConfigMain topLevelConfigLedger - , topLevelConfigBlock = dualBlockConfigMain topLevelConfigBlock - , topLevelConfigCodec = dualCodecConfigMain topLevelConfigCodec - , topLevelConfigStorage = dualStorageConfigMain topLevelConfigStorage + topLevelConfigProtocol = topLevelConfigProtocol + , topLevelConfigLedger = dualLedgerConfigMain topLevelConfigLedger + , topLevelConfigBlock = dualBlockConfigMain topLevelConfigBlock + , topLevelConfigCodec = dualCodecConfigMain topLevelConfigCodec + , topLevelConfigStorage = dualStorageConfigMain topLevelConfigStorage + , topLevelConfigCheckpoints = castCheckpointsMap topLevelConfigCheckpoints } {------------------------------------------------------------------------------- diff --git a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Ledger/Extended.hs b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Ledger/Extended.hs index 42363ff0e0..69a6361498 100644 --- a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Ledger/Extended.hs +++ b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Ledger/Extended.hs @@ -102,6 +102,7 @@ instance ( ConsensusProtocol (BlockProtocol blk) , NoThunks (CodecConfig blk) , NoThunks (LedgerConfig blk) , NoThunks (StorageConfig blk) + , NoThunks (HeaderHash blk) ) => NoThunks (ExtLedgerCfg blk) type instance LedgerCfg (ExtLedgerState blk) = ExtLedgerCfg blk diff --git a/ouroboros-consensus/src/unstable-consensus-testlib/Test/Util/TestBlock.hs b/ouroboros-consensus/src/unstable-consensus-testlib/Test/Util/TestBlock.hs index 1fa4f5025b..a07ba72abc 100644 --- a/ouroboros-consensus/src/unstable-consensus-testlib/Test/Util/TestBlock.hs +++ b/ouroboros-consensus/src/unstable-consensus-testlib/Test/Util/TestBlock.hs @@ -542,10 +542,11 @@ singleNodeTestConfigWith codecConfig storageConfig k = TopLevelConfig { , bftSignKey = SignKeyMockDSIGN 0 , bftVerKeys = Map.singleton (CoreId (CoreNodeId 0)) (VerKeyMockDSIGN 0) } - , topLevelConfigLedger = eraParams - , topLevelConfigBlock = TestBlockConfig numCoreNodes - , topLevelConfigCodec = codecConfig - , topLevelConfigStorage = storageConfig + , topLevelConfigLedger = eraParams + , topLevelConfigBlock = TestBlockConfig numCoreNodes + , topLevelConfigCodec = codecConfig + , topLevelConfigStorage = storageConfig + , topLevelConfigCheckpoints = emptyCheckpointsMap } where slotLength :: SlotLength diff --git a/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/BFT.hs b/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/BFT.hs index 3ae4d14fcd..4a83573a33 100644 --- a/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/BFT.hs +++ b/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/BFT.hs @@ -38,10 +38,11 @@ protocolInfoBft numCoreNodes nid securityParam eraParams = | n <- enumCoreNodes numCoreNodes ] } - , topLevelConfigLedger = SimpleLedgerConfig () eraParams - , topLevelConfigBlock = SimpleBlockConfig - , topLevelConfigCodec = SimpleCodecConfig - , topLevelConfigStorage = SimpleStorageConfig securityParam + , topLevelConfigLedger = SimpleLedgerConfig () eraParams + , topLevelConfigBlock = SimpleBlockConfig + , topLevelConfigCodec = SimpleCodecConfig + , topLevelConfigStorage = SimpleStorageConfig securityParam + , topLevelConfigCheckpoints = emptyCheckpointsMap } , pInfoInitLedger = ExtLedgerState (genesisSimpleLedgerState addrDist) (genesisHeaderState ()) diff --git a/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/PBFT.hs b/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/PBFT.hs index 5cfd0bb3aa..8d83620be0 100644 --- a/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/PBFT.hs +++ b/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/PBFT.hs @@ -36,10 +36,11 @@ protocolInfoMockPBFT params eraParams = topLevelConfigProtocol = PBftConfig { pbftParams = params } - , topLevelConfigLedger = SimpleLedgerConfig ledgerView eraParams - , topLevelConfigBlock = SimpleBlockConfig - , topLevelConfigCodec = SimpleCodecConfig - , topLevelConfigStorage = SimpleStorageConfig (pbftSecurityParam params) + , topLevelConfigLedger = SimpleLedgerConfig ledgerView eraParams + , topLevelConfigBlock = SimpleBlockConfig + , topLevelConfigCodec = SimpleCodecConfig + , topLevelConfigStorage = SimpleStorageConfig (pbftSecurityParam params) + , topLevelConfigCheckpoints = emptyCheckpointsMap } , pInfoInitLedger = ExtLedgerState (genesisSimpleLedgerState addrDist) (genesisHeaderState S.empty) diff --git a/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/Praos.hs b/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/Praos.hs index d685f1d74f..d69260979a 100644 --- a/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/Praos.hs +++ b/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/Praos.hs @@ -48,10 +48,11 @@ protocolInfoPraos numCoreNodes nid params eraParams eta0 evolvingStakeDist = , praosEvolvingStake = evolvingStakeDist , praosVerKeys = verKeys } - , topLevelConfigLedger = SimpleLedgerConfig addrDist eraParams - , topLevelConfigBlock = SimpleBlockConfig - , topLevelConfigCodec = SimpleCodecConfig - , topLevelConfigStorage = SimpleStorageConfig (praosSecurityParam params) + , topLevelConfigLedger = SimpleLedgerConfig addrDist eraParams + , topLevelConfigBlock = SimpleBlockConfig + , topLevelConfigCodec = SimpleCodecConfig + , topLevelConfigStorage = SimpleStorageConfig (praosSecurityParam params) + , topLevelConfigCheckpoints = emptyCheckpointsMap } , pInfoInitLedger = ExtLedgerState { ledgerState = genesisSimpleLedgerState addrDist diff --git a/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/PraosRule.hs b/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/PraosRule.hs index d97b633c7f..a4a728cc25 100644 --- a/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/PraosRule.hs +++ b/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Node/PraosRule.hs @@ -50,10 +50,11 @@ protocolInfoPraosRule numCoreNodes } , wlsConfigNodeId = nid } - , topLevelConfigLedger = SimpleLedgerConfig () eraParams - , topLevelConfigBlock = SimpleBlockConfig - , topLevelConfigCodec = SimpleCodecConfig - , topLevelConfigStorage = SimpleStorageConfig (praosSecurityParam params) + , topLevelConfigLedger = SimpleLedgerConfig () eraParams + , topLevelConfigBlock = SimpleBlockConfig + , topLevelConfigCodec = SimpleCodecConfig + , topLevelConfigStorage = SimpleStorageConfig (praosSecurityParam params) + , topLevelConfigCheckpoints = emptyCheckpointsMap } , pInfoInitLedger = ExtLedgerState { ledgerState = genesisSimpleLedgerState addrDist diff --git a/ouroboros-consensus/test/consensus-test/Main.hs b/ouroboros-consensus/test/consensus-test/Main.hs index 20ef73c725..3d044cec75 100644 --- a/ouroboros-consensus/test/consensus-test/Main.hs +++ b/ouroboros-consensus/test/consensus-test/Main.hs @@ -4,6 +4,7 @@ import qualified Test.Consensus.BlockchainTime.Simple (tests) import qualified Test.Consensus.HardFork.Forecast (tests) import qualified Test.Consensus.HardFork.History (tests) import qualified Test.Consensus.HardFork.Summary (tests) +import qualified Test.Consensus.HeaderValidation (tests) import qualified Test.Consensus.Mempool (tests) import qualified Test.Consensus.Mempool.Fairness (tests) import qualified Test.Consensus.MiniProtocol.BlockFetch.Client (tests) @@ -24,6 +25,7 @@ tests :: TestTree tests = testGroup "ouroboros-consensus" [ Test.Consensus.BlockchainTime.Simple.tests + , Test.Consensus.HeaderValidation.tests , Test.Consensus.MiniProtocol.BlockFetch.Client.tests , Test.Consensus.MiniProtocol.ChainSync.Client.tests , Test.Consensus.MiniProtocol.LocalStateQuery.Server.tests diff --git a/ouroboros-consensus/test/consensus-test/Test/Consensus/HeaderValidation.hs b/ouroboros-consensus/test/consensus-test/Test/Consensus/HeaderValidation.hs new file mode 100644 index 0000000000..a2b893a2cb --- /dev/null +++ b/ouroboros-consensus/test/consensus-test/Test/Consensus/HeaderValidation.hs @@ -0,0 +1,100 @@ +-- | Property tests for header validations +module Test.Consensus.HeaderValidation (tests) where + +import Control.Monad.Except (runExcept) +import Data.List.NonEmpty (NonEmpty (..)) +import qualified Data.Map.Strict as Map +import Data.Word (Word64) +import Ouroboros.Consensus.Block.Abstract +import Ouroboros.Consensus.Config +import Ouroboros.Consensus.HeaderValidation +import qualified Test.QuickCheck as QC +import Test.Tasty (TestTree, testGroup) +import Test.Tasty.QuickCheck (testProperty) +import Test.Util.TestBlock + +tests :: TestTree +tests = testGroup "HeaderValidation" + [ testGroup "validateIfCheckpoint" + [ testProperty "non-checkpoints are ignored" prop_validateIfCheckpoint_nonCheckpoint + , testProperty "checkpoint matches should be accepted" prop_validateIfCheckpoint_checkpoint_matches + , testProperty "checkpoint mismatches should be rejected" prop_validateIfCheckpoint_checkpoint_mismatches + ] + ] + +-- | Make a test block from the length of the hash and the Word64 +-- to create it. +mkTestBlock :: QC.NonNegative Int -> Word64 -> TestBlock +mkTestBlock (QC.NonNegative n) h = + successorBlockWithPayload + (TestHash $ h :| replicate n h) + (fromIntegral n + 1) + () + +-- | Like 'validateHeader', but takes a list of blocks to use as +-- checkpoints. +validateHeaderBlocks :: + [TestBlock] + -> TestBlock + -> Either (HeaderError TestBlock) (HeaderState TestBlock) +validateHeaderBlocks xs x = + let + checkpoints = CheckpointsMap $ Map.fromList [ (blockNo b, blockHash b) | b <- xs] + cfg = singleNodeTestConfig {topLevelConfigCheckpoints = checkpoints} + h = getHeader x + -- Chose the header state carefully so it doesn't cause validation to fail + annTip = + case headerPrevHash h of + GenesisHash -> Origin + BlockHash hsh -> NotOrigin $ AnnTip (blockSlot x - 1) (blockNo x - 1) hsh + headerState = + tickHeaderState + (topLevelConfigProtocol cfg) + () + 0 + (HeaderState annTip ()) + in + runExcept $ + validateHeader cfg () h headerState + +prop_validateIfCheckpoint_nonCheckpoint + :: [QC.NonNegative Int] -> QC.NonNegative Int -> QC.Property +prop_validateIfCheckpoint_nonCheckpoint xs x0 = + let + blks = map (`mkTestBlock` 0) $ filter (/= x0) xs + in + case validateHeaderBlocks blks (mkTestBlock x0 0) of + Left e -> + QC.counterexample "checkpoint validation should not fail on other blocks than checkpoints" $ + QC.counterexample (show e) $ + QC.property False + Right _ -> QC.property True + +prop_validateIfCheckpoint_checkpoint_matches + :: [QC.NonNegative Int] -> QC.NonNegative Int -> QC.Property +prop_validateIfCheckpoint_checkpoint_matches xs x = + let + blks = map (`mkTestBlock` 0) (x:xs) + in + case validateHeaderBlocks blks (mkTestBlock x 0) of + Left e -> + QC.counterexample "checkpoint matches should be accepted" $ + QC.counterexample (show e) $ + QC.property False + Right _ -> QC.property True + +prop_validateIfCheckpoint_checkpoint_mismatches + :: [QC.NonNegative Int] -> QC.NonNegative Int -> QC.Property +prop_validateIfCheckpoint_checkpoint_mismatches xs x = + let + blks = map (`mkTestBlock` 0) (x:xs) + in + case validateHeaderBlocks blks (mkTestBlock x 1) of + Left (HeaderEnvelopeError CheckpointMismatch{}) -> QC.property True + Left e -> + QC.counterexample "checkpoint mismatches should be rejected with CheckpointMismatched" $ + QC.counterexample (show e) $ + QC.property False + Right _ -> + QC.counterexample "checkpoint mismatches should be rejected" $ + QC.property False diff --git a/ouroboros-consensus/test/consensus-test/Test/Consensus/MiniProtocol/ChainSync/Client.hs b/ouroboros-consensus/test/consensus-test/Test/Consensus/MiniProtocol/ChainSync/Client.hs index e5411d8d84..d950a9103b 100644 --- a/ouroboros-consensus/test/consensus-test/Test/Consensus/MiniProtocol/ChainSync/Client.hs +++ b/ouroboros-consensus/test/consensus-test/Test/Consensus/MiniProtocol/ChainSync/Client.hs @@ -596,10 +596,11 @@ runChainSync skew securityParam (ClientUpdates clientUpdates) , (CoreId (CoreNodeId 1), VerKeyMockDSIGN 1) ] } - , topLevelConfigLedger = eraParams - , topLevelConfigBlock = TestBlockConfig numCoreNodes - , topLevelConfigCodec = TestBlockCodecConfig - , topLevelConfigStorage = TestBlockStorageConfig + , topLevelConfigLedger = eraParams + , topLevelConfigBlock = TestBlockConfig numCoreNodes + , topLevelConfigCodec = TestBlockCodecConfig + , topLevelConfigStorage = TestBlockStorageConfig + , topLevelConfigCheckpoints = emptyCheckpointsMap } eraParams :: HardFork.EraParams diff --git a/ouroboros-consensus/test/consensus-test/Test/Consensus/MiniProtocol/LocalStateQuery/Server.hs b/ouroboros-consensus/test/consensus-test/Test/Consensus/MiniProtocol/LocalStateQuery/Server.hs index 9ff9cc5dfe..e0b01e4703 100644 --- a/ouroboros-consensus/test/consensus-test/Test/Consensus/MiniProtocol/LocalStateQuery/Server.hs +++ b/ouroboros-consensus/test/consensus-test/Test/Consensus/MiniProtocol/LocalStateQuery/Server.hs @@ -238,10 +238,11 @@ testCfg securityParam = TopLevelConfig { , bftSignKey = SignKeyMockDSIGN 0 , bftVerKeys = Map.singleton (CoreId (CoreNodeId 0)) (VerKeyMockDSIGN 0) } - , topLevelConfigLedger = eraParams - , topLevelConfigBlock = TestBlockConfig numCoreNodes - , topLevelConfigCodec = TestBlockCodecConfig - , topLevelConfigStorage = TestBlockStorageConfig + , topLevelConfigLedger = eraParams + , topLevelConfigBlock = TestBlockConfig numCoreNodes + , topLevelConfigCodec = TestBlockCodecConfig + , topLevelConfigStorage = TestBlockStorageConfig + , topLevelConfigCheckpoints = emptyCheckpointsMap } where slotLength :: SlotLength diff --git a/ouroboros-consensus/test/storage-test/Test/Ouroboros/Storage/TestBlock.hs b/ouroboros-consensus/test/storage-test/Test/Ouroboros/Storage/TestBlock.hs index d78f81d844..ae5328e2d3 100644 --- a/ouroboros-consensus/test/storage-test/Test/Ouroboros/Storage/TestBlock.hs +++ b/ouroboros-consensus/test/storage-test/Test/Ouroboros/Storage/TestBlock.hs @@ -660,8 +660,9 @@ mkTestConfig k ChunkSize { chunkCanContainEBB, numRegularBlocks } = testBlockEBBsAllowed = chunkCanContainEBB , testBlockNumCoreNodes = numCoreNodes } - , topLevelConfigCodec = TestBlockCodecConfig - , topLevelConfigStorage = TestBlockStorageConfig + , topLevelConfigCodec = TestBlockCodecConfig + , topLevelConfigStorage = TestBlockStorageConfig + , topLevelConfigCheckpoints = emptyCheckpointsMap } where slotLength :: SlotLength