{-# LANGUAGE DeriveAnyClass             #-}
{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE DerivingStrategies         #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase                 #-}
{-# LANGUAGE NamedFieldPuns             #-}
{-# LANGUAGE PatternSynonyms            #-}
{-# LANGUAGE RecordWildCards            #-}

-- | Layout of individual chunks on disk
--
-- This module is not re-exported from the public Chunks API, since it's only
-- relevant internally in the immutable DB.
module Ouroboros.Consensus.Storage.ImmutableDB.Chunks.Layout (
    -- * Relative slots
    NextRelativeSlot (..)
  , firstBlockOrEBB
  , maxRelativeSlot
  , nextRelativeSlot
  , nthBlockOrEBB
  , relativeSlotIsEBB
  , unsafeNextRelativeSlot
    -- ** Opaque
  , RelativeSlot
    -- * Chunks
  , chunkIndexOfSlot
    -- * Slots within a chunk
  , ChunkSlot (..)
  , pattern ChunkSlot
    -- ** Translation /to/ 'ChunkSlot'
  , chunkSlotForBlockOrEBB
  , chunkSlotForBoundaryBlock
  , chunkSlotForRegularBlock
  , chunkSlotForRelativeSlot
  , chunkSlotForTip
  , chunkSlotForUnknownBlock
    -- ** Translation /from/ 'ChunkSlot'
  , chunkSlotToBlockOrEBB
  , chunkSlotToSlot
    -- ** Support for EBBs
  , slotMightBeEBB
  , slotNoOfBlockOrEBB
  , slotNoOfEBB
  ) where

import           Control.Monad
import           GHC.Generics (Generic)
import           GHC.Stack
import           NoThunks.Class (NoThunks)

import           Ouroboros.Consensus.Block

import           Ouroboros.Consensus.Storage.ImmutableDB.API (Tip (..))
import           Ouroboros.Consensus.Storage.ImmutableDB.Impl.Types
                     (BlockOrEBB (..))

-- Most types in the Chunks interface are opaque in the public API, since their
-- interpretation is subject to layout decisions. In this module we /make/ those
-- layout decisions, however, and so here we need access to the internal types.
import           Ouroboros.Consensus.Storage.ImmutableDB.Chunks.Internal

{-------------------------------------------------------------------------------
  Relative slots
-------------------------------------------------------------------------------}

-- | The last relative slot within a chunk of the given size
maxRelativeSlot :: ChunkInfo -> ChunkNo -> RelativeSlot
maxRelativeSlot :: ChunkInfo -> ChunkNo -> RelativeSlot
maxRelativeSlot ChunkInfo
ci ChunkNo
chunk =
    HasCallStack => ChunkInfo -> ChunkNo -> Word64 -> RelativeSlot
ChunkInfo -> ChunkNo -> Word64 -> RelativeSlot
mkRelativeSlot ChunkInfo
ci ChunkNo
chunk (ChunkSize -> Word64
maxRelativeIndex ChunkSize
size)
  where
    size :: ChunkSize
size = ChunkInfo -> ChunkNo -> ChunkSize
getChunkSize ChunkInfo
ci ChunkNo
chunk

-- | Is this relative slot reserved for an EBB?
relativeSlotIsEBB :: RelativeSlot -> IsEBB
relativeSlotIsEBB :: RelativeSlot -> IsEBB
relativeSlotIsEBB RelativeSlot{Word64
ChunkNo
ChunkSize
relativeSlotIndex :: RelativeSlot -> Word64
relativeSlotChunkSize :: RelativeSlot -> ChunkSize
relativeSlotChunkNo :: RelativeSlot -> ChunkNo
relativeSlotIndex :: Word64
relativeSlotChunkSize :: ChunkSize
relativeSlotChunkNo :: ChunkNo
..}
  | Word64
relativeSlotIndex Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
0
  , ChunkSize -> Bool
chunkCanContainEBB ChunkSize
relativeSlotChunkSize
  = IsEBB
IsEBB
  | Bool
otherwise
  = IsEBB
IsNotEBB

-- | The @n@'th relative slot for an arbitrary block
--
-- NOTE: Offset @0@ refers to an EBB only if the 'ChunkSize' supports it.
nthBlockOrEBB :: (HasCallStack, Integral a)
              => ChunkInfo -> ChunkNo -> a -> RelativeSlot
nthBlockOrEBB :: ChunkInfo -> ChunkNo -> a -> RelativeSlot
nthBlockOrEBB ChunkInfo
ci ChunkNo
chunk = HasCallStack => ChunkInfo -> ChunkNo -> Word64 -> RelativeSlot
ChunkInfo -> ChunkNo -> Word64 -> RelativeSlot
mkRelativeSlot ChunkInfo
ci ChunkNo
chunk (Word64 -> RelativeSlot) -> (a -> Word64) -> a -> RelativeSlot
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral

-- | The first relative slot
--
-- NOTE: This refers to an EBB only if the 'ChunkSize' supports it.
firstBlockOrEBB :: ChunkInfo -> ChunkNo -> RelativeSlot
firstBlockOrEBB :: ChunkInfo -> ChunkNo -> RelativeSlot
firstBlockOrEBB ChunkInfo
ci ChunkNo
chunk = HasCallStack => ChunkInfo -> ChunkNo -> Word64 -> RelativeSlot
ChunkInfo -> ChunkNo -> Word64 -> RelativeSlot
mkRelativeSlot ChunkInfo
ci ChunkNo
chunk Word64
0

-- | Result of 'nextRelativeSlot'
data NextRelativeSlot =
    -- | There is a next negative slot
    NextRelativeSlot RelativeSlot

    -- | We reached the end of the chunk
  | NoMoreRelativeSlots

-- | Next relative slot
nextRelativeSlot :: HasCallStack => RelativeSlot -> NextRelativeSlot
nextRelativeSlot :: RelativeSlot -> NextRelativeSlot
nextRelativeSlot s :: RelativeSlot
s@RelativeSlot{Word64
ChunkNo
ChunkSize
relativeSlotIndex :: Word64
relativeSlotChunkSize :: ChunkSize
relativeSlotChunkNo :: ChunkNo
relativeSlotIndex :: RelativeSlot -> Word64
relativeSlotChunkSize :: RelativeSlot -> ChunkSize
relativeSlotChunkNo :: RelativeSlot -> ChunkNo
..} =
    -- Assert that the /current/ value is within bounds
    Word64 -> ChunkSize -> NextRelativeSlot -> NextRelativeSlot
forall a. HasCallStack => Word64 -> ChunkSize -> a -> a
assertWithinBounds Word64
relativeSlotIndex ChunkSize
relativeSlotChunkSize (NextRelativeSlot -> NextRelativeSlot)
-> NextRelativeSlot -> NextRelativeSlot
forall a b. (a -> b) -> a -> b
$
      if Word64
relativeSlotIndex Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== ChunkSize -> Word64
maxRelativeIndex ChunkSize
relativeSlotChunkSize
        then NextRelativeSlot
NoMoreRelativeSlots
        else RelativeSlot -> NextRelativeSlot
NextRelativeSlot (RelativeSlot -> NextRelativeSlot)
-> RelativeSlot -> NextRelativeSlot
forall a b. (a -> b) -> a -> b
$ RelativeSlot
s { relativeSlotIndex :: Word64
relativeSlotIndex = Word64 -> Word64
forall a. Enum a => a -> a
succ Word64
relativeSlotIndex }

-- | Variation on 'nextRelativeSlot' where the caller /knows/ that there must
-- be a next slot
--
-- Throws an assertion failure (if assertions are enabled) if there is no
-- next slot.
unsafeNextRelativeSlot :: HasCallStack => RelativeSlot -> RelativeSlot
unsafeNextRelativeSlot :: RelativeSlot -> RelativeSlot
unsafeNextRelativeSlot s :: RelativeSlot
s@RelativeSlot{Word64
ChunkNo
ChunkSize
relativeSlotIndex :: Word64
relativeSlotChunkSize :: ChunkSize
relativeSlotChunkNo :: ChunkNo
relativeSlotIndex :: RelativeSlot -> Word64
relativeSlotChunkSize :: RelativeSlot -> ChunkSize
relativeSlotChunkNo :: RelativeSlot -> ChunkNo
..} =
    Word64 -> ChunkSize -> RelativeSlot -> RelativeSlot
forall a. HasCallStack => Word64 -> ChunkSize -> a -> a
assertWithinBounds (Word64 -> Word64
forall a. Enum a => a -> a
succ Word64
relativeSlotIndex) ChunkSize
relativeSlotChunkSize (RelativeSlot -> RelativeSlot) -> RelativeSlot -> RelativeSlot
forall a b. (a -> b) -> a -> b
$
      RelativeSlot
s { relativeSlotIndex :: Word64
relativeSlotIndex = Word64 -> Word64
forall a. Enum a => a -> a
succ Word64
relativeSlotIndex }

{-------------------------------------------------------------------------------
  Chucks
-------------------------------------------------------------------------------}

chunkIndexOfSlot :: ChunkInfo -> SlotNo -> ChunkNo
chunkIndexOfSlot :: ChunkInfo -> SlotNo -> ChunkNo
chunkIndexOfSlot (UniformChunkSize ChunkSize{Bool
Word64
numRegularBlocks :: ChunkSize -> Word64
numRegularBlocks :: Word64
chunkCanContainEBB :: Bool
chunkCanContainEBB :: ChunkSize -> Bool
..}) (SlotNo Word64
slot) = Word64 -> ChunkNo
ChunkNo (Word64 -> ChunkNo) -> Word64 -> ChunkNo
forall a b. (a -> b) -> a -> b
$
    Word64
slot Word64 -> Word64 -> Word64
forall a. Integral a => a -> a -> a
`div` Word64
numRegularBlocks

{-------------------------------------------------------------------------------
  Slot within an epoch
-------------------------------------------------------------------------------}

-- | Uniquely identify a block within the immutable DB
--
-- Constructor marked as 'Unsafe'; construction should normally happen inside
-- this module only (though see the 'ChunkSlot' pattern synonym).
data ChunkSlot = UnsafeChunkSlot
  { ChunkSlot -> ChunkNo
chunkIndex    :: !ChunkNo
  , ChunkSlot -> RelativeSlot
chunkRelative :: !RelativeSlot
  } deriving (ChunkSlot -> ChunkSlot -> Bool
(ChunkSlot -> ChunkSlot -> Bool)
-> (ChunkSlot -> ChunkSlot -> Bool) -> Eq ChunkSlot
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ChunkSlot -> ChunkSlot -> Bool
$c/= :: ChunkSlot -> ChunkSlot -> Bool
== :: ChunkSlot -> ChunkSlot -> Bool
$c== :: ChunkSlot -> ChunkSlot -> Bool
Eq, (forall x. ChunkSlot -> Rep ChunkSlot x)
-> (forall x. Rep ChunkSlot x -> ChunkSlot) -> Generic ChunkSlot
forall x. Rep ChunkSlot x -> ChunkSlot
forall x. ChunkSlot -> Rep ChunkSlot x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ChunkSlot x -> ChunkSlot
$cfrom :: forall x. ChunkSlot -> Rep ChunkSlot x
Generic, Context -> ChunkSlot -> IO (Maybe ThunkInfo)
Proxy ChunkSlot -> String
(Context -> ChunkSlot -> IO (Maybe ThunkInfo))
-> (Context -> ChunkSlot -> IO (Maybe ThunkInfo))
-> (Proxy ChunkSlot -> String)
-> NoThunks ChunkSlot
forall a.
(Context -> a -> IO (Maybe ThunkInfo))
-> (Context -> a -> IO (Maybe ThunkInfo))
-> (Proxy a -> String)
-> NoThunks a
showTypeOf :: Proxy ChunkSlot -> String
$cshowTypeOf :: Proxy ChunkSlot -> String
wNoThunks :: Context -> ChunkSlot -> IO (Maybe ThunkInfo)
$cwNoThunks :: Context -> ChunkSlot -> IO (Maybe ThunkInfo)
noThunks :: Context -> ChunkSlot -> IO (Maybe ThunkInfo)
$cnoThunks :: Context -> ChunkSlot -> IO (Maybe ThunkInfo)
NoThunks)

-- | We provide a manual 'Ord' instance because 'RelativeSlot' does not
-- (and cannot) define one. By comparing the 'chunkIndex' before the index here,
-- we establish the precondition to 'compareRelativeSlot'.
instance Ord ChunkSlot where
  compare :: ChunkSlot -> ChunkSlot -> Ordering
compare ChunkSlot
a ChunkSlot
b = [Ordering] -> Ordering
forall a. Monoid a => [a] -> a
mconcat [
      ChunkNo -> ChunkNo -> Ordering
forall a. Ord a => a -> a -> Ordering
compare             (ChunkSlot -> ChunkNo
chunkIndex    ChunkSlot
a) (ChunkSlot -> ChunkNo
chunkIndex    ChunkSlot
b)
    , HasCallStack => RelativeSlot -> RelativeSlot -> Ordering
RelativeSlot -> RelativeSlot -> Ordering
compareRelativeSlot (ChunkSlot -> RelativeSlot
chunkRelative ChunkSlot
a) (ChunkSlot -> RelativeSlot
chunkRelative ChunkSlot
b)
    ]

{-# COMPLETE ChunkSlot #-}
pattern ChunkSlot :: ChunkNo -> RelativeSlot -> ChunkSlot
pattern $mChunkSlot :: forall r.
ChunkSlot -> (ChunkNo -> RelativeSlot -> r) -> (Void# -> r) -> r
ChunkSlot index relative <- UnsafeChunkSlot index relative

instance Show ChunkSlot where
  show :: ChunkSlot -> String
show (ChunkSlot ChunkNo
e RelativeSlot
s) = (Word64, Word64) -> String
forall a. Show a => a -> String
show (ChunkNo -> Word64
unChunkNo ChunkNo
e, RelativeSlot -> Word64
relativeSlotIndex RelativeSlot
s)

{-------------------------------------------------------------------------------
  Translation /to/ 'ChunkSlot'
-------------------------------------------------------------------------------}

-- | Chunk slot for an unknown block
--
-- This returns /two/ 'ChunkSlot's: one in case the block could be an EBB,
-- and one in case the block is a regular block. In addition, it also returns
-- the 'ChunkNo' that both of these 'ChunkSlot's must necessarily share.
chunkSlotForUnknownBlock :: HasCallStack
                         => ChunkInfo
                         -> SlotNo
                         -> (ChunkNo, Maybe ChunkSlot, ChunkSlot)
chunkSlotForUnknownBlock :: ChunkInfo -> SlotNo -> (ChunkNo, Maybe ChunkSlot, ChunkSlot)
chunkSlotForUnknownBlock ChunkInfo
ci SlotNo
slot = (
      (case Maybe ChunkSlot
mIfBoundary of
         Maybe ChunkSlot
Nothing         -> ChunkNo -> ChunkNo
forall a. a -> a
id
         Just ChunkSlot
ifBoundary -> ChunkNo -> ChunkNo -> ChunkNo -> ChunkNo
forall a. HasCallStack => ChunkNo -> ChunkNo -> a -> a
assertSameChunk (ChunkSlot -> ChunkNo
chunkIndex ChunkSlot
ifBoundary)
                                            (ChunkSlot -> ChunkNo
chunkIndex ChunkSlot
ifRegular)) (ChunkNo -> ChunkNo) -> ChunkNo -> ChunkNo
forall a b. (a -> b) -> a -> b
$
        ChunkSlot -> ChunkNo
chunkIndex ChunkSlot
ifRegular
    , Maybe ChunkSlot
mIfBoundary
    , ChunkSlot
ifRegular
    )
  where
    ifRegular :: ChunkSlot
ifRegular   = ChunkInfo -> SlotNo -> ChunkSlot
chunkSlotForRegularBlock  ChunkInfo
ci SlotNo
slot
    mIfBoundary :: Maybe ChunkSlot
mIfBoundary = HasCallStack => ChunkInfo -> EpochNo -> ChunkSlot
ChunkInfo -> EpochNo -> ChunkSlot
chunkSlotForBoundaryBlock ChunkInfo
ci (EpochNo -> ChunkSlot) -> Maybe EpochNo -> Maybe ChunkSlot
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ChunkInfo -> SlotNo -> Maybe EpochNo
slotMightBeEBB ChunkInfo
ci SlotNo
slot

-- | Chunk slot for a regular block (i.e., not an EBB)
chunkSlotForRegularBlock :: ChunkInfo -> SlotNo -> ChunkSlot
chunkSlotForRegularBlock :: ChunkInfo -> SlotNo -> ChunkSlot
chunkSlotForRegularBlock (UniformChunkSize sz :: ChunkSize
sz@ChunkSize{Bool
Word64
numRegularBlocks :: Word64
chunkCanContainEBB :: Bool
numRegularBlocks :: ChunkSize -> Word64
chunkCanContainEBB :: ChunkSize -> Bool
..}) (SlotNo Word64
slot) =
    UnsafeChunkSlot :: ChunkNo -> RelativeSlot -> ChunkSlot
UnsafeChunkSlot {
        chunkIndex :: ChunkNo
chunkIndex    = Word64 -> ChunkNo
ChunkNo Word64
chunk
      , chunkRelative :: RelativeSlot
chunkRelative = ChunkNo -> ChunkSize -> Word64 -> RelativeSlot
RelativeSlot (Word64 -> ChunkNo
ChunkNo Word64
chunk) ChunkSize
sz (Word64 -> RelativeSlot) -> Word64 -> RelativeSlot
forall a b. (a -> b) -> a -> b
$
                          if Bool
chunkCanContainEBB
                            then Word64
withinChunk Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
1
                            else Word64
withinChunk
      }
  where
    (Word64
chunk, Word64
withinChunk) = Word64
slot Word64 -> Word64 -> (Word64, Word64)
forall a. Integral a => a -> a -> (a, a)
`divMod` Word64
numRegularBlocks

-- | Chunk slot for EBB
chunkSlotForBoundaryBlock :: HasCallStack => ChunkInfo -> EpochNo -> ChunkSlot
chunkSlotForBoundaryBlock :: ChunkInfo -> EpochNo -> ChunkSlot
chunkSlotForBoundaryBlock ChunkInfo
ci EpochNo
epoch =
    ChunkNo -> ChunkSize -> ChunkSlot -> ChunkSlot
forall a. HasCallStack => ChunkNo -> ChunkSize -> a -> a
assertChunkCanContainEBB ChunkNo
chunk ChunkSize
size (ChunkSlot -> ChunkSlot) -> ChunkSlot -> ChunkSlot
forall a b. (a -> b) -> a -> b
$
      ChunkNo -> RelativeSlot -> ChunkSlot
UnsafeChunkSlot ChunkNo
chunk (RelativeSlot -> ChunkSlot) -> RelativeSlot -> ChunkSlot
forall a b. (a -> b) -> a -> b
$ ChunkInfo -> ChunkNo -> RelativeSlot
firstBlockOrEBB ChunkInfo
ci ChunkNo
chunk
  where
    chunk :: ChunkNo
chunk = EpochNo -> ChunkNo
unsafeEpochNoToChunkNo EpochNo
epoch
    size :: ChunkSize
size  = ChunkInfo -> ChunkNo -> ChunkSize
getChunkSize ChunkInfo
ci ChunkNo
chunk

-- | Chunk slot for 'BlockOrEBB'
chunkSlotForBlockOrEBB :: ChunkInfo -> BlockOrEBB -> ChunkSlot
chunkSlotForBlockOrEBB :: ChunkInfo -> BlockOrEBB -> ChunkSlot
chunkSlotForBlockOrEBB ChunkInfo
ci = \case
    Block SlotNo
slot  -> ChunkInfo -> SlotNo -> ChunkSlot
chunkSlotForRegularBlock  ChunkInfo
ci SlotNo
slot
    EBB   EpochNo
epoch -> HasCallStack => ChunkInfo -> EpochNo -> ChunkSlot
ChunkInfo -> EpochNo -> ChunkSlot
chunkSlotForBoundaryBlock ChunkInfo
ci EpochNo
epoch

-- | Chunk slot for 'Tip'
chunkSlotForTip :: ChunkInfo -> Tip blk -> ChunkSlot
chunkSlotForTip :: ChunkInfo -> Tip blk -> ChunkSlot
chunkSlotForTip ChunkInfo
ci Tip { SlotNo
tipSlotNo :: forall blk. Tip blk -> SlotNo
tipSlotNo :: SlotNo
tipSlotNo, IsEBB
tipIsEBB :: forall blk. Tip blk -> IsEBB
tipIsEBB :: IsEBB
tipIsEBB } = case IsEBB
tipIsEBB of
    IsEBB
IsNotEBB -> ChunkInfo -> SlotNo -> ChunkSlot
chunkSlotForRegularBlock ChunkInfo
ci SlotNo
tipSlotNo
    IsEBB
IsEBB    -> ChunkNo -> ChunkSize -> ChunkSlot -> ChunkSlot
forall a. HasCallStack => ChunkNo -> ChunkSize -> a -> a
assertChunkCanContainEBB ChunkNo
chunkIndex ChunkSize
relativeSlotChunkSize (ChunkSlot -> ChunkSlot) -> ChunkSlot -> ChunkSlot
forall a b. (a -> b) -> a -> b
$
                 ChunkNo -> RelativeSlot -> ChunkSlot
UnsafeChunkSlot ChunkNo
chunkIndex (RelativeSlot -> ChunkSlot) -> RelativeSlot -> ChunkSlot
forall a b. (a -> b) -> a -> b
$ ChunkInfo -> ChunkNo -> RelativeSlot
firstBlockOrEBB ChunkInfo
ci ChunkNo
chunkIndex
  where
    UnsafeChunkSlot{RelativeSlot
ChunkNo
chunkRelative :: RelativeSlot
chunkIndex :: ChunkNo
chunkRelative :: ChunkSlot -> RelativeSlot
chunkIndex :: ChunkSlot -> ChunkNo
..} = ChunkInfo -> SlotNo -> ChunkSlot
chunkSlotForRegularBlock ChunkInfo
ci SlotNo
tipSlotNo
    RelativeSlot{Word64
ChunkNo
ChunkSize
relativeSlotIndex :: Word64
relativeSlotChunkNo :: ChunkNo
relativeSlotChunkSize :: ChunkSize
relativeSlotIndex :: RelativeSlot -> Word64
relativeSlotChunkSize :: RelativeSlot -> ChunkSize
relativeSlotChunkNo :: RelativeSlot -> ChunkNo
..}    = RelativeSlot
chunkRelative

chunkSlotForRelativeSlot :: ChunkNo -> RelativeSlot -> ChunkSlot
chunkSlotForRelativeSlot :: ChunkNo -> RelativeSlot -> ChunkSlot
chunkSlotForRelativeSlot ChunkNo
chunk RelativeSlot
relSlot =
    ChunkNo -> ChunkNo -> ChunkSlot -> ChunkSlot
forall a. HasCallStack => ChunkNo -> ChunkNo -> a -> a
assertSameChunk (RelativeSlot -> ChunkNo
relativeSlotChunkNo RelativeSlot
relSlot) ChunkNo
chunk (ChunkSlot -> ChunkSlot) -> ChunkSlot -> ChunkSlot
forall a b. (a -> b) -> a -> b
$
      ChunkNo -> RelativeSlot -> ChunkSlot
UnsafeChunkSlot ChunkNo
chunk RelativeSlot
relSlot

{-------------------------------------------------------------------------------
  Translation /from/ 'ChunkSlot'

  Reminder:

  * EBB shares its slot number with its successor
  * EBB shares its block number with its predecessor
-------------------------------------------------------------------------------}

-- | From relative to absolute slot
--
-- This can be used for EBBs and regular blocks, since they don't share a
-- relative slot.
chunkSlotToSlot :: ChunkInfo -> ChunkSlot -> SlotNo
chunkSlotToSlot :: ChunkInfo -> ChunkSlot -> SlotNo
chunkSlotToSlot (UniformChunkSize ChunkSize{Bool
Word64
numRegularBlocks :: Word64
chunkCanContainEBB :: Bool
numRegularBlocks :: ChunkSize -> Word64
chunkCanContainEBB :: ChunkSize -> Bool
..}) UnsafeChunkSlot{RelativeSlot
ChunkNo
chunkRelative :: RelativeSlot
chunkIndex :: ChunkNo
chunkRelative :: ChunkSlot -> RelativeSlot
chunkIndex :: ChunkSlot -> ChunkNo
..} = Word64 -> SlotNo
SlotNo (Word64 -> SlotNo) -> Word64 -> SlotNo
forall a b. (a -> b) -> a -> b
$
      Word64
chunk Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
numRegularBlocks
    Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ case (Bool
chunkCanContainEBB, Word64
relativeSlotIndex) of
        (Bool
_    , Word64
0) -> Word64
0
        (Bool
True , Word64
n) -> Word64
n Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
1
        (Bool
False, Word64
n) -> Word64
n
  where
    ChunkNo Word64
chunk    = ChunkNo
chunkIndex
    RelativeSlot{Word64
ChunkNo
ChunkSize
relativeSlotChunkSize :: ChunkSize
relativeSlotChunkNo :: ChunkNo
relativeSlotIndex :: Word64
relativeSlotIndex :: RelativeSlot -> Word64
relativeSlotChunkSize :: RelativeSlot -> ChunkSize
relativeSlotChunkNo :: RelativeSlot -> ChunkNo
..} = RelativeSlot
chunkRelative

chunkSlotToBlockOrEBB :: ChunkInfo -> ChunkSlot -> BlockOrEBB
chunkSlotToBlockOrEBB :: ChunkInfo -> ChunkSlot -> BlockOrEBB
chunkSlotToBlockOrEBB ChunkInfo
chunkInfo chunkSlot :: ChunkSlot
chunkSlot@(ChunkSlot ChunkNo
chunk RelativeSlot
relSlot) =
    case RelativeSlot -> IsEBB
relativeSlotIsEBB RelativeSlot
relSlot of
      IsEBB
IsEBB    -> EpochNo -> BlockOrEBB
EBB   (EpochNo -> BlockOrEBB) -> EpochNo -> BlockOrEBB
forall a b. (a -> b) -> a -> b
$ ChunkNo -> EpochNo
unsafeChunkNoToEpochNo ChunkNo
chunk
      IsEBB
IsNotEBB -> SlotNo -> BlockOrEBB
Block (SlotNo -> BlockOrEBB) -> SlotNo -> BlockOrEBB
forall a b. (a -> b) -> a -> b
$ ChunkInfo -> ChunkSlot -> SlotNo
chunkSlotToSlot ChunkInfo
chunkInfo ChunkSlot
chunkSlot

{-------------------------------------------------------------------------------
  Support for EBBs
-------------------------------------------------------------------------------}

slotNoOfEBB :: HasCallStack => ChunkInfo -> EpochNo -> SlotNo
slotNoOfEBB :: ChunkInfo -> EpochNo -> SlotNo
slotNoOfEBB ChunkInfo
ci = ChunkInfo -> ChunkSlot -> SlotNo
chunkSlotToSlot ChunkInfo
ci (ChunkSlot -> SlotNo)
-> (EpochNo -> ChunkSlot) -> EpochNo -> SlotNo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => ChunkInfo -> EpochNo -> ChunkSlot
ChunkInfo -> EpochNo -> ChunkSlot
chunkSlotForBoundaryBlock ChunkInfo
ci

slotMightBeEBB :: ChunkInfo -> SlotNo -> Maybe EpochNo
slotMightBeEBB :: ChunkInfo -> SlotNo -> Maybe EpochNo
slotMightBeEBB ChunkInfo
ci SlotNo
slot = do
    Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ ChunkSize -> Bool
chunkCanContainEBB ChunkSize
relativeSlotChunkSize Bool -> Bool -> Bool
&& Word64
relativeSlotIndex Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
1
    EpochNo -> Maybe EpochNo
forall (m :: * -> *) a. Monad m => a -> m a
return (EpochNo -> Maybe EpochNo) -> EpochNo -> Maybe EpochNo
forall a b. (a -> b) -> a -> b
$ ChunkNo -> EpochNo
unsafeChunkNoToEpochNo ChunkNo
chunkIndex
  where
    UnsafeChunkSlot{RelativeSlot
ChunkNo
chunkRelative :: RelativeSlot
chunkIndex :: ChunkNo
chunkRelative :: ChunkSlot -> RelativeSlot
chunkIndex :: ChunkSlot -> ChunkNo
..} = ChunkInfo -> SlotNo -> ChunkSlot
chunkSlotForRegularBlock ChunkInfo
ci SlotNo
slot
    RelativeSlot{Word64
ChunkNo
ChunkSize
relativeSlotChunkNo :: ChunkNo
relativeSlotIndex :: Word64
relativeSlotChunkSize :: ChunkSize
relativeSlotIndex :: RelativeSlot -> Word64
relativeSlotChunkSize :: RelativeSlot -> ChunkSize
relativeSlotChunkNo :: RelativeSlot -> ChunkNo
..}    = RelativeSlot
chunkRelative

slotNoOfBlockOrEBB :: ChunkInfo -> BlockOrEBB -> SlotNo
slotNoOfBlockOrEBB :: ChunkInfo -> BlockOrEBB -> SlotNo
slotNoOfBlockOrEBB ChunkInfo
_  (Block SlotNo
slot)  = SlotNo
slot
slotNoOfBlockOrEBB ChunkInfo
ci (EBB   EpochNo
epoch) = HasCallStack => ChunkInfo -> EpochNo -> SlotNo
ChunkInfo -> EpochNo -> SlotNo
slotNoOfEBB ChunkInfo
ci EpochNo
epoch