{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Ouroboros.Consensus.Fragment.Diff (
ChainDiff (..)
, getAnchorPoint
, getTip
, rollbackExceedsSuffix
, diff
, extend
, apply
, append
, mapM
, takeWhileOldest
, truncate
) where
import Data.Word (Word64)
import GHC.Stack (HasCallStack)
import Ouroboros.Consensus.Block
import Ouroboros.Network.AnchoredFragment (AnchoredFragment,
AnchoredSeq (..))
import qualified Ouroboros.Network.AnchoredFragment as AF
import Prelude hiding (mapM, truncate)
import qualified Prelude
data ChainDiff b = ChainDiff
{ forall b. ChainDiff b -> Word64
getRollback :: !Word64
, forall b. ChainDiff b -> AnchoredFragment b
getSuffix :: !(AnchoredFragment b)
}
deriving instance (StandardHash b, Eq b) => Eq (ChainDiff b)
deriving instance (StandardHash b, Show b) => Show (ChainDiff b)
getTip :: HasHeader b => ChainDiff b -> Point b
getTip :: forall b. HasHeader b => ChainDiff b -> Point b
getTip = Point b -> Point b
forall {k1} {k2} (b :: k1) (b' :: k2).
Coercible (HeaderHash b) (HeaderHash b') =>
Point b -> Point b'
castPoint (Point b -> Point b)
-> (ChainDiff b -> Point b) -> ChainDiff b -> Point b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AnchoredFragment b -> Point b
forall block.
HasHeader block =>
AnchoredFragment block -> Point block
AF.headPoint (AnchoredFragment b -> Point b)
-> (ChainDiff b -> AnchoredFragment b) -> ChainDiff b -> Point b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ChainDiff b -> AnchoredFragment b
forall b. ChainDiff b -> AnchoredFragment b
getSuffix
getAnchorPoint :: ChainDiff b -> Point b
getAnchorPoint :: forall b. ChainDiff b -> Point b
getAnchorPoint = Point b -> Point b
forall {k1} {k2} (b :: k1) (b' :: k2).
Coercible (HeaderHash b) (HeaderHash b') =>
Point b -> Point b'
castPoint (Point b -> Point b)
-> (ChainDiff b -> Point b) -> ChainDiff b -> Point b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AnchoredFragment b -> Point b
forall block. AnchoredFragment block -> Point block
AF.anchorPoint (AnchoredFragment b -> Point b)
-> (ChainDiff b -> AnchoredFragment b) -> ChainDiff b -> Point b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ChainDiff b -> AnchoredFragment b
forall b. ChainDiff b -> AnchoredFragment b
getSuffix
rollbackExceedsSuffix :: HasHeader b => ChainDiff b -> Bool
rollbackExceedsSuffix :: forall b. HasHeader b => ChainDiff b -> Bool
rollbackExceedsSuffix (ChainDiff Word64
nbRollback AnchoredFragment b
suffix) =
Word64
nbRollback Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
> 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
suffix)
extend :: AnchoredFragment b -> ChainDiff b
extend :: forall b. AnchoredFragment b -> ChainDiff b
extend = Word64 -> AnchoredFragment b -> ChainDiff b
forall b. Word64 -> AnchoredFragment b -> ChainDiff b
ChainDiff Word64
0
diff ::
(HasHeader b, HasHeader b', HeaderHash b ~ HeaderHash b', HasCallStack)
=> AnchoredFragment b'
-> AnchoredFragment b
-> ChainDiff b
diff :: forall b b'.
(HasHeader b, HasHeader b', HeaderHash b ~ HeaderHash b',
HasCallStack) =>
AnchoredFragment b' -> AnchoredFragment b -> ChainDiff b
diff AnchoredFragment b'
curChain AnchoredFragment b
candChain =
case 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'
curChain AnchoredFragment b
candChain of
Just (AnchoredFragment b'
_curChainPrefix, AnchoredFragment b
_candPrefix, AnchoredFragment b'
curChainSuffix, AnchoredFragment b
candSuffix)
-> Word64 -> AnchoredFragment b -> ChainDiff b
forall b. Word64 -> AnchoredFragment b -> ChainDiff b
ChainDiff
(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'
curChainSuffix))
AnchoredFragment b
candSuffix
Maybe
(AnchoredFragment b', AnchoredFragment b, AnchoredFragment b',
AnchoredFragment b)
_ -> String -> ChainDiff b
forall a. HasCallStack => String -> a
error String
"candidate fragment doesn't intersect with current chain"
apply ::
HasHeader b
=> AnchoredFragment b
-> ChainDiff b
-> Maybe (AnchoredFragment b)
apply :: forall b.
HasHeader b =>
AnchoredFragment b -> ChainDiff b -> Maybe (AnchoredFragment b)
apply AnchoredFragment b
curChain (ChainDiff Word64
nbRollback AnchoredFragment b
suffix) =
AnchoredFragment b
-> AnchoredFragment b -> Maybe (AnchoredFragment b)
forall block.
HasHeader block =>
AnchoredFragment block
-> AnchoredFragment block -> Maybe (AnchoredFragment block)
AF.join (Int -> AnchoredFragment b -> AnchoredFragment b
forall v a b.
Anchorable v a b =>
Int -> AnchoredSeq v a b -> AnchoredSeq v a b
AF.dropNewest (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
nbRollback) AnchoredFragment b
curChain) AnchoredFragment b
suffix
append :: HasHeader b => ChainDiff b -> b -> ChainDiff b
append :: forall b. HasHeader b => ChainDiff b -> b -> ChainDiff b
append (ChainDiff Word64
nbRollback AnchoredFragment b
suffix) b
b = (Word64 -> AnchoredFragment b -> ChainDiff b
forall b. Word64 -> AnchoredFragment b -> ChainDiff b
ChainDiff Word64
nbRollback (AnchoredFragment b
suffix AnchoredFragment b -> b -> AnchoredFragment b
forall v a b.
Anchorable v a b =>
AnchoredSeq v a b -> b -> AnchoredSeq v a b
:> b
b))
truncate ::
(HasHeader b, HasCallStack)
=> Point b
-> ChainDiff b
-> ChainDiff b
truncate :: forall b.
(HasHeader b, HasCallStack) =>
Point b -> ChainDiff b -> ChainDiff b
truncate Point b
pt (ChainDiff Word64
nbRollback AnchoredFragment b
suffix)
| Just AnchoredFragment b
suffix' <- Point b -> AnchoredFragment b -> Maybe (AnchoredFragment b)
forall block.
HasHeader block =>
Point block
-> AnchoredFragment block -> Maybe (AnchoredFragment block)
AF.rollback (Point b -> Point b
forall {k1} {k2} (b :: k1) (b' :: k2).
Coercible (HeaderHash b) (HeaderHash b') =>
Point b -> Point b'
castPoint Point b
pt) AnchoredFragment b
suffix
= Word64 -> AnchoredFragment b -> ChainDiff b
forall b. Word64 -> AnchoredFragment b -> ChainDiff b
ChainDiff Word64
nbRollback AnchoredFragment b
suffix'
| Bool
otherwise
= String -> ChainDiff b
forall a. HasCallStack => String -> a
error (String -> ChainDiff b) -> String -> ChainDiff b
forall a b. (a -> b) -> a -> b
$ String
"rollback point not on the candidate suffix: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Point b -> String
forall a. Show a => a -> String
show Point b
pt
takeWhileOldest ::
HasHeader b
=> (b -> Bool)
-> ChainDiff b
-> ChainDiff b
takeWhileOldest :: forall b. HasHeader b => (b -> Bool) -> ChainDiff b -> ChainDiff b
takeWhileOldest b -> Bool
accept (ChainDiff Word64
nbRollback AnchoredFragment b
suffix) =
Word64 -> AnchoredFragment b -> ChainDiff b
forall b. Word64 -> AnchoredFragment b -> ChainDiff b
ChainDiff Word64
nbRollback ((b -> Bool) -> AnchoredFragment b -> AnchoredFragment b
forall v a b.
Anchorable v a b =>
(b -> Bool) -> AnchoredSeq v a b -> AnchoredSeq v a b
AF.takeWhileOldest b -> Bool
accept AnchoredFragment b
suffix)
mapM ::
forall a b m.
( HasHeader b
, HeaderHash a ~ HeaderHash b
, Monad m
)
=> (a -> m b)
-> ChainDiff a
-> m (ChainDiff b)
mapM :: forall a b (m :: * -> *).
(HasHeader b, HeaderHash a ~ HeaderHash b, Monad m) =>
(a -> m b) -> ChainDiff a -> m (ChainDiff b)
mapM a -> m b
f (ChainDiff Word64
rollback AnchoredFragment a
suffix) =
Word64 -> AnchoredFragment b -> ChainDiff b
forall b. Word64 -> AnchoredFragment b -> ChainDiff b
ChainDiff Word64
rollback
(AnchoredFragment b -> ChainDiff b)
-> ([b] -> AnchoredFragment b) -> [b] -> ChainDiff b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Anchor b -> [b] -> AnchoredFragment b
forall v a b. Anchorable v a b => a -> [b] -> AnchoredSeq v a b
AF.fromOldestFirst (Anchor a -> Anchor b
forall a b. (HeaderHash a ~ HeaderHash b) => Anchor a -> Anchor b
AF.castAnchor (AnchoredFragment a -> Anchor a
forall v a b. AnchoredSeq v a b -> a
AF.anchor AnchoredFragment a
suffix))
([b] -> ChainDiff b) -> m [b] -> m (ChainDiff b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (a -> m b) -> [a] -> m [b]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
Prelude.mapM a -> m b
f (AnchoredFragment a -> [a]
forall v a b. AnchoredSeq v a b -> [b]
AF.toOldestFirst AnchoredFragment a
suffix)