{-# LANGUAGE LambdaCase #-}
module Ouroboros.Consensus.Block.SupportsSanityCheck (
BlockSupportsSanityCheck (..)
, SanityCheckIssue (..)
, checkSecurityParamConsistency
, sanityCheckConfig
) where
import Control.Exception
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NonEmpty
import Data.Maybe (catMaybes)
import Ouroboros.Consensus.Config (TopLevelConfig)
import Ouroboros.Consensus.Config.SecurityParam
data SanityCheckIssue
= InconsistentSecurityParam (NonEmpty SecurityParam)
deriving (Int -> SanityCheckIssue -> ShowS
[SanityCheckIssue] -> ShowS
SanityCheckIssue -> String
(Int -> SanityCheckIssue -> ShowS)
-> (SanityCheckIssue -> String)
-> ([SanityCheckIssue] -> ShowS)
-> Show SanityCheckIssue
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SanityCheckIssue -> ShowS
showsPrec :: Int -> SanityCheckIssue -> ShowS
$cshow :: SanityCheckIssue -> String
show :: SanityCheckIssue -> String
$cshowList :: [SanityCheckIssue] -> ShowS
showList :: [SanityCheckIssue] -> ShowS
Show, SanityCheckIssue -> SanityCheckIssue -> Bool
(SanityCheckIssue -> SanityCheckIssue -> Bool)
-> (SanityCheckIssue -> SanityCheckIssue -> Bool)
-> Eq SanityCheckIssue
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SanityCheckIssue -> SanityCheckIssue -> Bool
== :: SanityCheckIssue -> SanityCheckIssue -> Bool
$c/= :: SanityCheckIssue -> SanityCheckIssue -> Bool
/= :: SanityCheckIssue -> SanityCheckIssue -> Bool
Eq)
instance Exception SanityCheckIssue where
displayException :: SanityCheckIssue -> String
displayException = \case
InconsistentSecurityParam NonEmpty SecurityParam
ks -> [String] -> String
forall a. Monoid a => [a] -> a
mconcat
[ String
"InconsistentSecurityParam: "
, String
"SecurityParams (K) were found to be inconsistent between constituent "
, String
"eras of a HardForkBlock: "
, [SecurityParam] -> String
forall a. Show a => a -> String
show (NonEmpty SecurityParam -> [SecurityParam]
forall a. NonEmpty a -> [a]
NonEmpty.toList NonEmpty SecurityParam
ks)
]
class BlockSupportsSanityCheck blk where
configAllSecurityParams
:: TopLevelConfig blk
-> NonEmpty SecurityParam
checkSecurityParamConsistency
:: BlockSupportsSanityCheck blk
=> TopLevelConfig blk
-> Maybe SanityCheckIssue
checkSecurityParamConsistency :: forall blk.
BlockSupportsSanityCheck blk =>
TopLevelConfig blk -> Maybe SanityCheckIssue
checkSecurityParamConsistency TopLevelConfig blk
cfg = do
let allParams :: NonEmpty SecurityParam
allParams = TopLevelConfig blk -> NonEmpty SecurityParam
forall blk.
BlockSupportsSanityCheck blk =>
TopLevelConfig blk -> NonEmpty SecurityParam
configAllSecurityParams TopLevelConfig blk
cfg
if NonEmpty SecurityParam -> Bool
forall a. Eq a => NonEmpty a -> Bool
allSame NonEmpty SecurityParam
allParams
then Maybe SanityCheckIssue
forall a. Maybe a
Nothing
else SanityCheckIssue -> Maybe SanityCheckIssue
forall a. a -> Maybe a
Just (NonEmpty SecurityParam -> SanityCheckIssue
InconsistentSecurityParam NonEmpty SecurityParam
allParams)
allSame :: Eq a => NonEmpty a -> Bool
allSame :: forall a. Eq a => NonEmpty a -> Bool
allSame (a
x :| [a]
xs) = (a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
==) [a]
xs
sanityCheckConfig
:: BlockSupportsSanityCheck blk
=> TopLevelConfig blk
-> [SanityCheckIssue]
sanityCheckConfig :: forall blk.
BlockSupportsSanityCheck blk =>
TopLevelConfig blk -> [SanityCheckIssue]
sanityCheckConfig TopLevelConfig blk
cfg =
[Maybe SanityCheckIssue] -> [SanityCheckIssue]
forall a. [Maybe a] -> [a]
catMaybes [TopLevelConfig blk -> Maybe SanityCheckIssue
forall blk.
BlockSupportsSanityCheck blk =>
TopLevelConfig blk -> Maybe SanityCheckIssue
checkSecurityParamConsistency TopLevelConfig blk
cfg]