module Cardano.Wallet.Checkpoints.Policy
( BlockHeight
, CheckpointPolicy
, nextCheckpoint
, keepWhereTip
, toListAtTip
, atGenesis
, atTip
, trailingArithmetic
, sparseArithmetic
, defaultPolicy
, gapSize
) where
import Prelude
import Data.List
( unfoldr )
type BlockHeight = Integer
newtype CheckpointPolicy = CheckpointPolicy
{ CheckpointPolicy -> BlockHeight -> BlockHeight -> Maybe BlockHeight
nextCheckpoint :: BlockHeight -> BlockHeight -> Maybe BlockHeight
}
keepWhereTip
:: CheckpointPolicy -> BlockHeight -> BlockHeight
-> Bool
keepWhereTip :: CheckpointPolicy -> BlockHeight -> BlockHeight -> Bool
keepWhereTip CheckpointPolicy
policy BlockHeight
tip BlockHeight
height =
CheckpointPolicy -> BlockHeight -> BlockHeight -> Maybe BlockHeight
nextCheckpoint CheckpointPolicy
policy BlockHeight
tip BlockHeight
height Maybe BlockHeight -> Maybe BlockHeight -> Bool
forall a. Eq a => a -> a -> Bool
== BlockHeight -> Maybe BlockHeight
forall a. a -> Maybe a
Just BlockHeight
height
toListAtTip :: CheckpointPolicy -> BlockHeight -> [BlockHeight]
toListAtTip :: CheckpointPolicy -> BlockHeight -> [BlockHeight]
toListAtTip CheckpointPolicy
policy BlockHeight
tip = (BlockHeight -> Maybe (BlockHeight, BlockHeight))
-> BlockHeight -> [BlockHeight]
forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr ((BlockHeight -> (BlockHeight, BlockHeight))
-> Maybe BlockHeight -> Maybe (BlockHeight, BlockHeight)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap BlockHeight -> (BlockHeight, BlockHeight)
forall b. Num b => b -> (b, b)
next (Maybe BlockHeight -> Maybe (BlockHeight, BlockHeight))
-> (BlockHeight -> Maybe BlockHeight)
-> BlockHeight
-> Maybe (BlockHeight, BlockHeight)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CheckpointPolicy -> BlockHeight -> BlockHeight -> Maybe BlockHeight
nextCheckpoint CheckpointPolicy
policy BlockHeight
tip) BlockHeight
0
where next :: b -> (b, b)
next b
x = (b
x,b
xb -> b -> b
forall a. Num a => a -> a -> a
+b
1)
instance Semigroup CheckpointPolicy where
CheckpointPolicy
p1 <> :: CheckpointPolicy -> CheckpointPolicy -> CheckpointPolicy
<> CheckpointPolicy
p2 = (BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy
CheckpointPolicy ((BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy)
-> (BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy
forall a b. (a -> b) -> a -> b
$ \BlockHeight
t BlockHeight
h ->
(BlockHeight -> BlockHeight -> BlockHeight)
-> Maybe BlockHeight -> Maybe BlockHeight -> Maybe BlockHeight
forall t. (t -> t -> t) -> Maybe t -> Maybe t -> Maybe t
union BlockHeight -> BlockHeight -> BlockHeight
forall a. Ord a => a -> a -> a
min (CheckpointPolicy -> BlockHeight -> BlockHeight -> Maybe BlockHeight
nextCheckpoint CheckpointPolicy
p1 BlockHeight
t BlockHeight
h) (CheckpointPolicy -> BlockHeight -> BlockHeight -> Maybe BlockHeight
nextCheckpoint CheckpointPolicy
p2 BlockHeight
t BlockHeight
h)
where
union :: (t -> t -> t) -> Maybe t -> Maybe t -> Maybe t
union t -> t -> t
_ Maybe t
Nothing Maybe t
mb = Maybe t
mb
union t -> t -> t
_ Maybe t
ma Maybe t
Nothing = Maybe t
ma
union t -> t -> t
f (Just t
a) (Just t
b) = t -> Maybe t
forall a. a -> Maybe a
Just (t -> t -> t
f t
a t
b)
instance Monoid CheckpointPolicy where
mempty :: CheckpointPolicy
mempty = (BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy
CheckpointPolicy ((BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy)
-> (BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy
forall a b. (a -> b) -> a -> b
$ \BlockHeight
_ BlockHeight
_ -> Maybe BlockHeight
forall a. Maybe a
Nothing
atGenesis :: CheckpointPolicy
atGenesis :: CheckpointPolicy
atGenesis = (BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy
CheckpointPolicy ((BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy)
-> (BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy
forall a b. (a -> b) -> a -> b
$ \BlockHeight
_tip BlockHeight
height ->
if BlockHeight
height BlockHeight -> BlockHeight -> Bool
forall a. Ord a => a -> a -> Bool
<= BlockHeight
0 then BlockHeight -> Maybe BlockHeight
forall a. a -> Maybe a
Just BlockHeight
height else Maybe BlockHeight
forall a. Maybe a
Nothing
atTip :: CheckpointPolicy
atTip :: CheckpointPolicy
atTip = (BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy
CheckpointPolicy ((BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy)
-> (BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy
forall a b. (a -> b) -> a -> b
$ \BlockHeight
tip BlockHeight
height ->
if BlockHeight
height BlockHeight -> BlockHeight -> Bool
forall a. Ord a => a -> a -> Bool
<= BlockHeight
tip then BlockHeight -> Maybe BlockHeight
forall a. a -> Maybe a
Just BlockHeight
tip else Maybe BlockHeight
forall a. Maybe a
Nothing
trailingArithmetic :: Integer -> BlockHeight -> CheckpointPolicy
trailingArithmetic :: BlockHeight -> BlockHeight -> CheckpointPolicy
trailingArithmetic BlockHeight
n BlockHeight
grid = (BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy
CheckpointPolicy ((BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy)
-> (BlockHeight -> BlockHeight -> Maybe BlockHeight)
-> CheckpointPolicy
forall a b. (a -> b) -> a -> b
$ \BlockHeight
tip BlockHeight
height ->
case [BlockHeight
h | BlockHeight
h <- BlockHeight -> [BlockHeight]
window BlockHeight
tip, BlockHeight
h BlockHeight -> BlockHeight -> Bool
forall a. Ord a => a -> a -> Bool
>= BlockHeight
height] of
[] -> Maybe BlockHeight
forall a. Maybe a
Nothing
(BlockHeight
x:[BlockHeight]
_) -> BlockHeight -> Maybe BlockHeight
forall a. a -> Maybe a
Just BlockHeight
x
where
window :: BlockHeight -> [BlockHeight]
window BlockHeight
tip = [BlockHeight
a, BlockHeight
a BlockHeight -> BlockHeight -> BlockHeight
forall a. Num a => a -> a -> a
+ BlockHeight
grid .. BlockHeight
tip]
where
m :: BlockHeight
m = BlockHeight
n BlockHeight -> BlockHeight -> BlockHeight
forall a. Num a => a -> a -> a
- BlockHeight
1
a :: BlockHeight
a = if BlockHeight
tip BlockHeight -> BlockHeight -> Bool
forall a. Ord a => a -> a -> Bool
> BlockHeight
m BlockHeight -> BlockHeight -> BlockHeight
forall a. Num a => a -> a -> a
* BlockHeight
grid then BlockHeight -> BlockHeight
toGrid (BlockHeight
tip BlockHeight -> BlockHeight -> BlockHeight
forall a. Num a => a -> a -> a
- BlockHeight
m BlockHeight -> BlockHeight -> BlockHeight
forall a. Num a => a -> a -> a
* BlockHeight
grid) else BlockHeight
0
toGrid :: BlockHeight -> BlockHeight
toGrid BlockHeight
x = (BlockHeight
x BlockHeight -> BlockHeight -> BlockHeight
forall a. Integral a => a -> a -> a
`div` BlockHeight
grid) BlockHeight -> BlockHeight -> BlockHeight
forall a. Num a => a -> a -> a
* BlockHeight
grid
sparseArithmetic :: BlockHeight -> CheckpointPolicy
sparseArithmetic :: BlockHeight -> CheckpointPolicy
sparseArithmetic BlockHeight
epochStability =
CheckpointPolicy
atGenesis
CheckpointPolicy -> CheckpointPolicy -> CheckpointPolicy
forall a. Semigroup a => a -> a -> a
<> CheckpointPolicy
atTip
CheckpointPolicy -> CheckpointPolicy -> CheckpointPolicy
forall a. Semigroup a => a -> a -> a
<> BlockHeight -> BlockHeight -> CheckpointPolicy
trailingArithmetic BlockHeight
10 BlockHeight
1
CheckpointPolicy -> CheckpointPolicy -> CheckpointPolicy
forall a. Semigroup a => a -> a -> a
<> BlockHeight -> BlockHeight -> CheckpointPolicy
trailingArithmetic BlockHeight
n BlockHeight
largeGap
where
largeGap :: BlockHeight
largeGap = BlockHeight -> BlockHeight
gapSize BlockHeight
epochStability
n :: BlockHeight
n = BlockHeight
epochStability BlockHeight -> BlockHeight -> BlockHeight
forall a. Integral a => a -> a -> a
`div` BlockHeight
largeGap
defaultPolicy :: BlockHeight -> CheckpointPolicy
defaultPolicy :: BlockHeight -> CheckpointPolicy
defaultPolicy = BlockHeight -> CheckpointPolicy
sparseArithmetic
gapSize :: BlockHeight -> Integer
gapSize :: BlockHeight -> BlockHeight
gapSize BlockHeight
epochStability = BlockHeight -> BlockHeight -> BlockHeight
forall a. Ord a => a -> a -> a
max BlockHeight
1 (BlockHeight
epochStability BlockHeight -> BlockHeight -> BlockHeight
forall a. Integral a => a -> a -> a
`div` BlockHeight
3)