{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Ouroboros.Consensus.Util.AnchoredFragment (
compareAnchoredFragments
, compareHeadBlockNo
, forksAtMostKBlocks
, preferAnchoredCandidate
) where
import Control.Monad.Except (throwError)
import Data.Function (on)
import Data.Maybe (isJust)
import Data.Word (Word64)
import GHC.Stack
import Ouroboros.Network.AnchoredFragment (AnchoredFragment,
AnchoredSeq (Empty, (:>)))
import qualified Ouroboros.Network.AnchoredFragment as AF
import Ouroboros.Consensus.Block
import Ouroboros.Consensus.Util.Assert
compareHeadBlockNo
:: HasHeader b
=> AnchoredFragment b
-> AnchoredFragment b
-> Ordering
compareHeadBlockNo :: AnchoredFragment b -> AnchoredFragment b -> Ordering
compareHeadBlockNo = WithOrigin BlockNo -> WithOrigin BlockNo -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (WithOrigin BlockNo -> WithOrigin BlockNo -> Ordering)
-> (AnchoredFragment b -> WithOrigin BlockNo)
-> AnchoredFragment b
-> AnchoredFragment b
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` AnchoredFragment b -> WithOrigin BlockNo
forall block.
HasHeader block =>
AnchoredFragment block -> WithOrigin BlockNo
AF.headBlockNo
forksAtMostKBlocks
:: HasHeader b
=> Word64
-> AnchoredFragment b
-> AnchoredFragment b
-> Bool
forksAtMostKBlocks :: Word64 -> AnchoredFragment b -> AnchoredFragment b -> Bool
forksAtMostKBlocks Word64
k AnchoredFragment b
ours AnchoredFragment b
theirs = case AnchoredFragment b
ours AnchoredFragment b
-> AnchoredFragment b
-> Maybe
(AnchoredFragment b, AnchoredFragment b, AnchoredFragment b,
AnchoredFragment b)
forall block1 block2.
(HasHeader block1, HasHeader block2,
HeaderHash block1 ~ HeaderHash block2) =>
AnchoredFragment block1
-> AnchoredFragment block2
-> Maybe
(AnchoredFragment block1, AnchoredFragment block2,
AnchoredFragment block1, AnchoredFragment block2)
`AF.intersect` AnchoredFragment b
theirs of
Maybe
(AnchoredFragment b, AnchoredFragment b, AnchoredFragment b,
AnchoredFragment b)
Nothing -> Bool
False
Just (AnchoredFragment b
_, AnchoredFragment b
_, AnchoredFragment b
ourSuffix, AnchoredFragment b
_) -> Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (AnchoredFragment b -> Int
forall v a b. Anchorable v a b => AnchoredSeq v a b -> Int
AF.length AnchoredFragment b
ourSuffix) Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word64
k
compareAnchoredFragments ::
forall blk. (BlockSupportsProtocol blk, HasCallStack)
=> BlockConfig blk
-> AnchoredFragment (Header blk)
-> AnchoredFragment (Header blk)
-> Ordering
compareAnchoredFragments :: BlockConfig blk
-> AnchoredFragment (Header blk)
-> AnchoredFragment (Header blk)
-> Ordering
compareAnchoredFragments BlockConfig blk
cfg AnchoredFragment (Header blk)
frag1 AnchoredFragment (Header blk)
frag2 =
Either String () -> Ordering -> Ordering
forall a. HasCallStack => Either String () -> a -> a
assertWithMsg Either String ()
precondition (Ordering -> Ordering) -> Ordering -> Ordering
forall a b. (a -> b) -> a -> b
$
case (AnchoredFragment (Header blk)
frag1, AnchoredFragment (Header blk)
frag2) of
(Empty Anchor (Header blk)
_, Empty Anchor (Header blk)
_) ->
Ordering
EQ
(Empty Anchor (Header blk)
anchor, AnchoredFragment (Header blk)
_ :> Header blk
tip') ->
if Header blk -> Point (Header blk)
forall block. HasHeader block => block -> Point block
blockPoint Header blk
tip' Point (Header blk) -> Point (Header blk) -> Bool
forall a. Eq a => a -> a -> Bool
== Anchor (Header blk) -> Point (Header blk)
forall block. Anchor block -> Point block
AF.anchorToPoint Anchor (Header blk)
anchor
then Ordering
EQ
else Ordering
LT
(AnchoredFragment (Header blk)
_ :> Header blk
tip, Empty Anchor (Header blk)
anchor') ->
if Header blk -> Point (Header blk)
forall block. HasHeader block => block -> Point block
blockPoint Header blk
tip Point (Header blk) -> Point (Header blk) -> Bool
forall a. Eq a => a -> a -> Bool
== Anchor (Header blk) -> Point (Header blk)
forall block. Anchor block -> Point block
AF.anchorToPoint Anchor (Header blk)
anchor'
then Ordering
EQ
else Ordering
GT
(AnchoredFragment (Header blk)
_ :> Header blk
tip, AnchoredFragment (Header blk)
_ :> Header blk
tip') ->
SelectView (BlockProtocol blk)
-> SelectView (BlockProtocol blk) -> Ordering
forall a. Ord a => a -> a -> Ordering
compare
(BlockConfig blk -> Header blk -> SelectView (BlockProtocol blk)
forall blk.
BlockSupportsProtocol blk =>
BlockConfig blk -> Header blk -> SelectView (BlockProtocol blk)
selectView BlockConfig blk
cfg Header blk
tip)
(BlockConfig blk -> Header blk -> SelectView (BlockProtocol blk)
forall blk.
BlockSupportsProtocol blk =>
BlockConfig blk -> Header blk -> SelectView (BlockProtocol blk)
selectView BlockConfig blk
cfg Header blk
tip')
where
precondition :: Either String ()
precondition :: Either String ()
precondition
| Bool -> Bool
not (AnchoredFragment (Header blk) -> Bool
forall v a b. AnchoredSeq v a b -> Bool
AF.null AnchoredFragment (Header blk)
frag1), Bool -> Bool
not (AnchoredFragment (Header blk) -> Bool
forall v a b. AnchoredSeq v a b -> Bool
AF.null AnchoredFragment (Header blk)
frag2)
= () -> Either String ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
| Maybe (Point (Header blk)) -> Bool
forall a. Maybe a -> Bool
isJust (AnchoredFragment (Header blk)
-> AnchoredFragment (Header blk) -> Maybe (Point (Header blk))
forall block1 block2.
(HasHeader block1, HasHeader block2,
HeaderHash block1 ~ HeaderHash block2) =>
AnchoredFragment block1
-> AnchoredFragment block2 -> Maybe (Point block1)
AF.intersectionPoint AnchoredFragment (Header blk)
frag1 AnchoredFragment (Header blk)
frag2)
= () -> Either String ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
| Bool
otherwise
= String -> Either String ()
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError
String
"precondition violated: fragments both empty or don't intersect"
preferAnchoredCandidate ::
forall blk. (BlockSupportsProtocol blk, HasCallStack)
=> BlockConfig blk
-> AnchoredFragment (Header blk)
-> AnchoredFragment (Header blk)
-> Bool
preferAnchoredCandidate :: BlockConfig blk
-> AnchoredFragment (Header blk)
-> AnchoredFragment (Header blk)
-> Bool
preferAnchoredCandidate BlockConfig blk
cfg AnchoredFragment (Header blk)
ours AnchoredFragment (Header blk)
cand =
BlockConfig blk
-> AnchoredFragment (Header blk)
-> AnchoredFragment (Header blk)
-> Ordering
forall blk.
(BlockSupportsProtocol blk, HasCallStack) =>
BlockConfig blk
-> AnchoredFragment (Header blk)
-> AnchoredFragment (Header blk)
-> Ordering
compareAnchoredFragments BlockConfig blk
cfg AnchoredFragment (Header blk)
ours AnchoredFragment (Header blk)
cand Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT