{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# 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. This module makes the layout
-- decisions.
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.Chunks.Internal
import Ouroboros.Consensus.Storage.ImmutableDB.Impl.Types
  ( BlockOrEBB (..)
  )

{-------------------------------------------------------------------------------
  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
relativeSlotChunkNo :: ChunkNo
relativeSlotChunkSize :: ChunkSize
relativeSlotIndex :: Word64
relativeSlotIndex :: RelativeSlot -> Word64
relativeSlotChunkSize :: RelativeSlot -> ChunkSize
relativeSlotChunkNo :: RelativeSlot -> 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 :: forall a.
(HasCallStack, Integral a) =>
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 :: HasCallStack => RelativeSlot -> NextRelativeSlot
nextRelativeSlot s :: RelativeSlot
s@RelativeSlot{Word64
ChunkNo
ChunkSize
relativeSlotIndex :: RelativeSlot -> Word64
relativeSlotChunkSize :: RelativeSlot -> ChunkSize
relativeSlotChunkNo :: RelativeSlot -> ChunkNo
relativeSlotChunkNo :: ChunkNo
relativeSlotChunkSize :: ChunkSize
relativeSlotIndex :: Word64
..} =
  -- 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 = succ 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 :: HasCallStack => RelativeSlot -> RelativeSlot
unsafeNextRelativeSlot s :: RelativeSlot
s@RelativeSlot{Word64
ChunkNo
ChunkSize
relativeSlotIndex :: RelativeSlot -> Word64
relativeSlotChunkSize :: RelativeSlot -> ChunkSize
relativeSlotChunkNo :: RelativeSlot -> ChunkNo
relativeSlotChunkNo :: ChunkNo
relativeSlotChunkSize :: ChunkSize
relativeSlotIndex :: Word64
..} =
  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 = succ relativeSlotIndex}

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

chunkIndexOfSlot :: ChunkInfo -> SlotNo -> ChunkNo
chunkIndexOfSlot :: ChunkInfo -> SlotNo -> ChunkNo
chunkIndexOfSlot (UniformChunkSize ChunkSize{Bool
Word64
chunkCanContainEBB :: ChunkSize -> Bool
chunkCanContainEBB :: Bool
numRegularBlocks :: Word64
numRegularBlocks :: ChunkSize -> Word64
..}) (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
$c== :: ChunkSlot -> ChunkSlot -> Bool
== :: ChunkSlot -> ChunkSlot -> Bool
$c/= :: ChunkSlot -> ChunkSlot -> Bool
/= :: 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
$cfrom :: forall x. ChunkSlot -> Rep ChunkSlot x
from :: forall x. ChunkSlot -> Rep ChunkSlot x
$cto :: forall x. Rep ChunkSlot x -> ChunkSlot
to :: forall x. Rep ChunkSlot x -> ChunkSlot
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
$cnoThunks :: Context -> ChunkSlot -> IO (Maybe ThunkInfo)
noThunks :: Context -> ChunkSlot -> IO (Maybe ThunkInfo)
$cwNoThunks :: Context -> ChunkSlot -> IO (Maybe ThunkInfo)
wNoThunks :: Context -> ChunkSlot -> IO (Maybe ThunkInfo)
$cshowTypeOf :: Proxy ChunkSlot -> String
showTypeOf :: Proxy ChunkSlot -> String
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) -> ((# #) -> 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 :: HasCallStack =>
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
chunkCanContainEBB :: ChunkSize -> Bool
numRegularBlocks :: ChunkSize -> Word64
chunkCanContainEBB :: Bool
numRegularBlocks :: Word64
..}) (SlotNo Word64
slot) =
  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 :: HasCallStack => 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 :: forall blk. ChunkInfo -> Tip blk -> ChunkSlot
chunkSlotForTip ChunkInfo
ci Tip{SlotNo
tipSlotNo :: SlotNo
tipSlotNo :: forall blk. Tip blk -> SlotNo
tipSlotNo, IsEBB
tipIsEBB :: IsEBB
tipIsEBB :: forall blk. Tip blk -> 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
chunkIndex :: ChunkSlot -> ChunkNo
chunkRelative :: ChunkSlot -> RelativeSlot
chunkIndex :: ChunkNo
chunkRelative :: RelativeSlot
..} = ChunkInfo -> SlotNo -> ChunkSlot
chunkSlotForRegularBlock ChunkInfo
ci SlotNo
tipSlotNo
  RelativeSlot{Word64
ChunkNo
ChunkSize
relativeSlotIndex :: RelativeSlot -> Word64
relativeSlotChunkSize :: RelativeSlot -> ChunkSize
relativeSlotChunkNo :: RelativeSlot -> ChunkNo
relativeSlotChunkSize :: ChunkSize
relativeSlotChunkNo :: ChunkNo
relativeSlotIndex :: Word64
..} = 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
chunkCanContainEBB :: ChunkSize -> Bool
numRegularBlocks :: ChunkSize -> Word64
chunkCanContainEBB :: Bool
numRegularBlocks :: Word64
..}) UnsafeChunkSlot{RelativeSlot
ChunkNo
chunkIndex :: ChunkSlot -> ChunkNo
chunkRelative :: ChunkSlot -> RelativeSlot
chunkIndex :: ChunkNo
chunkRelative :: RelativeSlot
..} =
  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
relativeSlotIndex :: RelativeSlot -> Word64
relativeSlotChunkSize :: RelativeSlot -> ChunkSize
relativeSlotChunkNo :: RelativeSlot -> ChunkNo
relativeSlotIndex :: Word64
relativeSlotChunkNo :: ChunkNo
relativeSlotChunkSize :: ChunkSize
..} = 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 :: HasCallStack => 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 a. a -> Maybe a
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
chunkIndex :: ChunkSlot -> ChunkNo
chunkRelative :: ChunkSlot -> RelativeSlot
chunkIndex :: ChunkNo
chunkRelative :: RelativeSlot
..} = ChunkInfo -> SlotNo -> ChunkSlot
chunkSlotForRegularBlock ChunkInfo
ci SlotNo
slot
  RelativeSlot{Word64
ChunkNo
ChunkSize
relativeSlotIndex :: RelativeSlot -> Word64
relativeSlotChunkSize :: RelativeSlot -> ChunkSize
relativeSlotChunkNo :: RelativeSlot -> ChunkNo
relativeSlotChunkSize :: ChunkSize
relativeSlotIndex :: Word64
relativeSlotChunkNo :: 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