content: {-# LANGUAGE TypeFamilies #-}
  
  -- | Richmen computation for delegation.
  
  module Pos.DB.Lrc.Consumer.Delegation
         (
         -- * The 'RichmenComponent'
           dlgRichmenComponent
  
         -- * The consumer
         , dlgLrcConsumer
  
         -- * Functions for getting richmen
         , getDlgRichmen
         , tryGetDlgRichmen
         , getDlgRichmenObft
         ) where
  
  import           Universum
  
  import           Data.HashSet (fromList)
  
  import           Pos.Chain.Genesis (configGenesisWStakeholders)
  import           Pos.Chain.Genesis as Genesis (Config (..))
  import           Pos.Chain.Lrc (RichmenComponent (..), RichmenSet)
  import           Pos.Chain.Update (BlockVersionData (..))
  import           Pos.Core (EpochIndex)
  import           Pos.DB (MonadDB, MonadDBRead, MonadGState)
  import           Pos.DB.Lrc.Consumer (LrcConsumer,
                       lrcConsumerFromComponentSimple)
  import           Pos.DB.Lrc.Context (HasLrcContext, lrcActionOnEpochReason)
  import           Pos.DB.Lrc.RichmenBase
  import           Pos.Util.Util (getKeys)
  
  ----------------------------------------------------------------------------
  -- RichmenComponent
  ----------------------------------------------------------------------------
  
  dlgRichmenComponent :: BlockVersionData -> RichmenComponent RichmenSet
  dlgRichmenComponent genesisBvd = RichmenComponent
      { rcToData            = getKeys . snd
      , rcTag               = "dlg"
      , rcInitialThreshold  = bvdHeavyDelThd genesisBvd
      , rcConsiderDelegated = False
      }
  
  ----------------------------------------------------------------------------
  -- The consumer
  ----------------------------------------------------------------------------
  
  -- | Consumer will be called on every Richmen computation.
  dlgLrcConsumer :: (MonadGState m, MonadDB m) => BlockVersionData -> LrcConsumer m
  dlgLrcConsumer genesisBvd = lrcConsumerFromComponentSimple
      (dlgRichmenComponent genesisBvd)
      bvdHeavyDelThd
  
  ----------------------------------------------------------------------------
  -- Getting richmen
  ----------------------------------------------------------------------------
  
  -- | Wait for LRC results to become available and then get delegation ricmen
  -- data for the given epoch.
  getDlgRichmen
      :: (MonadIO m, MonadDBRead m, MonadReader ctx m, HasLrcContext ctx)
      => BlockVersionData
      -> Text               -- ^ Function name (to include into error message)
      -> EpochIndex         -- ^ Epoch for which you want to know the richmen
      -> m RichmenSet
  getDlgRichmen genesisBvd fname epoch = lrcActionOnEpochReason
      epoch
      (fname <> ": couldn't get delegation richmen")
      (tryGetDlgRichmen genesisBvd)
  
  -- | Like 'getDlgRichmen', but doesn't wait and doesn't fail.
  tryGetDlgRichmen
      :: MonadDBRead m => BlockVersionData -> EpochIndex -> m (Maybe RichmenSet)
  tryGetDlgRichmen = getRichmen . dlgRichmenComponent
  
  -- | For OBFT, we retrieve the genesis stakeholders and classify them as the
  -- "richmen". We don't perform any LRC operations here.
  getDlgRichmenObft
      :: Genesis.Config
      -> RichmenSet
  getDlgRichmenObft = fromList . configGenesisWStakeholders
  