{-# LANGUAGE DataKinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}

module Cardano.Ledger.BHeaderView where

import Cardano.Ledger.BaseTypes (BoundedRational (..), UnitInterval)
import Cardano.Ledger.Hashes (EraIndependentBlockBody)
import Cardano.Ledger.Keys (Hash, KeyHash, KeyRole (..))
import Cardano.Ledger.Slot (SlotNo (..), (-*))
import Data.Word (Word32)

-- | 'BHeaderView' provides an interface between block headers
-- from different Cardano protocols and packages that should be
-- agnostic of Cardano protocol specific details,
-- such as those in TPraos, Praos, Genesis, etc.
--
-- In particular, the 'BBODY' rule comprises most of the ledger logic
-- and should work independently of the protocol. The values in
-- 'BHeaderView' provide 'BBODY' all the data that it needs from the
-- block headers.
data BHeaderView c = BHeaderView
  { forall c. BHeaderView c -> KeyHash 'BlockIssuer c
bhviewID :: KeyHash 'BlockIssuer c
  -- ^ The block issuer. In the TPraos protocol, this can be a
  --  Genesis delegate, everywhere else it is the stake pool ID.
  , forall c. BHeaderView c -> Word32
bhviewBSize :: Word32
  -- ^ The purported size (in bytes) of the block body.
  , forall c. BHeaderView c -> Int
bhviewHSize :: Int
  -- ^ The purported size (in bytes) of the block header.
  , forall c. BHeaderView c -> Hash c EraIndependentBlockBody
bhviewBHash :: Hash c EraIndependentBlockBody
  -- ^ The purported hash of the block body.
  , forall c. BHeaderView c -> SlotNo
bhviewSlot :: SlotNo
  -- ^ The slot for which this block was submitted to the chain.
  }

-- | Determine if the given slot is reserved for the overlay schedule.
isOverlaySlot ::
  -- | The first slot of the given epoch.
  SlotNo ->
  -- | The decentralization parameter.
  UnitInterval ->
  -- | The slot to check.
  SlotNo ->
  Bool
isOverlaySlot :: SlotNo -> UnitInterval -> SlotNo -> Bool
isOverlaySlot SlotNo
firstSlotNo UnitInterval
dval SlotNo
slot = Rational -> Integer
step Rational
s forall a. Ord a => a -> a -> Bool
< Rational -> Integer
step (Rational
s forall a. Num a => a -> a -> a
+ Rational
1)
  where
    s :: Rational
s = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ SlotNo
slot SlotNo -> SlotNo -> Duration
-* SlotNo
firstSlotNo
    d :: Rational
d = forall r. BoundedRational r => r -> Rational
unboundRational UnitInterval
dval
    step :: Rational -> Integer
    step :: Rational -> Integer
step Rational
x = forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Rational
x forall a. Num a => a -> a -> a
* Rational
d)