{-# LANGUAGE NamedFieldPuns #-}
module Test.ThreadNet.Util.Expectations (
NumBlocks (..)
, determineForkLength
) where
import Data.Foldable as Foldable (foldl')
import qualified Data.Map.Strict as Map
import Data.Word (Word64)
import Ouroboros.Consensus.Block
import Ouroboros.Consensus.Config.SecurityParam
import Ouroboros.Consensus.NodeId (CoreNodeId (..))
import Ouroboros.Consensus.Protocol.LeaderSchedule
import Test.ThreadNet.Util.NodeJoinPlan
newtype NumBlocks = NumBlocks Word64
deriving (NumBlocks -> NumBlocks -> Bool
(NumBlocks -> NumBlocks -> Bool)
-> (NumBlocks -> NumBlocks -> Bool) -> Eq NumBlocks
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: NumBlocks -> NumBlocks -> Bool
== :: NumBlocks -> NumBlocks -> Bool
$c/= :: NumBlocks -> NumBlocks -> Bool
/= :: NumBlocks -> NumBlocks -> Bool
Eq, Int -> NumBlocks -> ShowS
[NumBlocks] -> ShowS
NumBlocks -> String
(Int -> NumBlocks -> ShowS)
-> (NumBlocks -> String)
-> ([NumBlocks] -> ShowS)
-> Show NumBlocks
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> NumBlocks -> ShowS
showsPrec :: Int -> NumBlocks -> ShowS
$cshow :: NumBlocks -> String
show :: NumBlocks -> String
$cshowList :: [NumBlocks] -> ShowS
showList :: [NumBlocks] -> ShowS
Show)
data Acc = Acc
{ Acc -> Word64
maxChainLength :: !Word64
, Acc -> Word64
maxForkLength :: !Word64
}
determineForkLength ::
SecurityParam
-> NodeJoinPlan
-> LeaderSchedule
-> NumBlocks
determineForkLength :: SecurityParam -> NodeJoinPlan -> LeaderSchedule -> NumBlocks
determineForkLength SecurityParam
k (NodeJoinPlan Map CoreNodeId SlotNo
joinPlan) (LeaderSchedule Map SlotNo [CoreNodeId]
sched) =
Acc -> NumBlocks
prj (Acc -> NumBlocks) -> Acc -> NumBlocks
forall a b. (a -> b) -> a -> b
$ (Acc -> (SlotNo, [CoreNodeId]) -> Acc)
-> Acc -> [(SlotNo, [CoreNodeId])] -> Acc
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Foldable.foldl' Acc -> (SlotNo, [CoreNodeId]) -> Acc
step Acc
initial (Map SlotNo [CoreNodeId] -> [(SlotNo, [CoreNodeId])]
forall k a. Map k a -> [(k, a)]
Map.toAscList Map SlotNo [CoreNodeId]
sched)
where
prj :: Acc -> NumBlocks
prj Acc{Word64
maxForkLength :: Acc -> Word64
maxForkLength :: Word64
maxForkLength} = Word64 -> NumBlocks
NumBlocks Word64
maxForkLength
initial :: Acc
initial = Acc
{ maxChainLength :: Word64
maxChainLength = Word64
0
, maxForkLength :: Word64
maxForkLength = Word64
0
}
step :: Acc -> (SlotNo, [CoreNodeId]) -> Acc
step Acc{Word64
maxChainLength :: Acc -> Word64
maxChainLength :: Word64
maxChainLength, Word64
maxForkLength :: Acc -> Word64
maxForkLength :: Word64
maxForkLength} (SlotNo
slot, [CoreNodeId]
leaders) =
Acc
{ maxChainLength :: Word64
maxChainLength = Word64 -> Word64
grow Word64
maxChainLength
, maxForkLength :: Word64
maxForkLength = Word64 -> Word64
update Word64
maxForkLength
}
where
grow :: Word64 -> Word64
grow = if Int
0 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
pullingAhead then Word64 -> Word64
forall a. a -> a
id else (Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
1)
update :: Word64 -> Word64
update
| Word64
maxForkLength Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
> SecurityParam -> Word64
maxRollbacks SecurityParam
k = Word64 -> Word64
grow
| Int
pullingAhead Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1 = (Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
1)
| Int
pullingAhead Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 = Word64 -> Word64 -> Word64
forall a b. a -> b -> a
const Word64
0
| Int
pullingEven Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 = Word64 -> Word64 -> Word64
forall a. Ord a => a -> a -> a
max Word64
1
| Bool
otherwise = Word64 -> Word64
forall a. a -> a
id
pullingAhead :: Int
pullingAhead = Int
nlOld Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Bool -> Int
nlNew (Word64
maxChainLength Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
0)
pullingEven :: Int
pullingEven = Bool -> Int
nlNew (Word64
maxChainLength Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
1)
nlOld :: Int
nlOld = [CoreNodeId] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([CoreNodeId] -> Int) -> [CoreNodeId] -> Int
forall a b. (a -> b) -> a -> b
$ (CoreNodeId -> Bool) -> [CoreNodeId] -> [CoreNodeId]
forall a. (a -> Bool) -> [a] -> [a]
filter ((SlotNo -> SlotNo -> Bool
forall a. Ord a => a -> a -> Bool
< SlotNo
slot) (SlotNo -> Bool) -> (CoreNodeId -> SlotNo) -> CoreNodeId -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CoreNodeId -> SlotNo
joinSlot) [CoreNodeId]
leaders
nlNew :: Bool -> Int
nlNew Bool
b
| Bool -> Bool
not Bool
b = Int
0
| Bool
otherwise = [CoreNodeId] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([CoreNodeId] -> Int) -> [CoreNodeId] -> Int
forall a b. (a -> b) -> a -> b
$ (CoreNodeId -> Bool) -> [CoreNodeId] -> [CoreNodeId]
forall a. (a -> Bool) -> [a] -> [a]
filter ((SlotNo -> SlotNo -> Bool
forall a. Eq a => a -> a -> Bool
== SlotNo
slot) (SlotNo -> Bool) -> (CoreNodeId -> SlotNo) -> CoreNodeId -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CoreNodeId -> SlotNo
joinSlot) [CoreNodeId]
leaders
joinSlot :: CoreNodeId -> SlotNo
joinSlot :: CoreNodeId -> SlotNo
joinSlot CoreNodeId
nid = case CoreNodeId -> Map CoreNodeId SlotNo -> Maybe SlotNo
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup CoreNodeId
nid Map CoreNodeId SlotNo
joinPlan of
Maybe SlotNo
Nothing -> String -> SlotNo
forall a. HasCallStack => String -> a
error String
"determineForkLength: incomplete node join plan"
Just SlotNo
slot' -> SlotNo
slot'