{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE UndecidableInstances #-}

module Hydra.HeadLogic.StateEvent where

import Hydra.Chain.ChainState (IsChainState)
import Hydra.Events (EventId, HasEventId (..))
import Hydra.HeadLogic.Outcome (StateChanged (Checkpoint))
import Hydra.Node.State (NodeState)
import Hydra.Prelude

-- * State change events as used by Hydra.Node

-- | A state change event with an event id that is the common entity to be
-- loaded from an 'EventSource' and sent to 'EventSink's.
data StateEvent tx = StateEvent
  { forall tx. StateEvent tx -> EventId
eventId :: EventId
  , forall tx. StateEvent tx -> StateChanged tx
stateChanged :: StateChanged tx
  , forall tx. StateEvent tx -> UTCTime
time :: UTCTime
  }
  deriving stock ((forall x. StateEvent tx -> Rep (StateEvent tx) x)
-> (forall x. Rep (StateEvent tx) x -> StateEvent tx)
-> Generic (StateEvent tx)
forall x. Rep (StateEvent tx) x -> StateEvent tx
forall x. StateEvent tx -> Rep (StateEvent tx) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall tx x. Rep (StateEvent tx) x -> StateEvent tx
forall tx x. StateEvent tx -> Rep (StateEvent tx) x
$cfrom :: forall tx x. StateEvent tx -> Rep (StateEvent tx) x
from :: forall x. StateEvent tx -> Rep (StateEvent tx) x
$cto :: forall tx x. Rep (StateEvent tx) x -> StateEvent tx
to :: forall x. Rep (StateEvent tx) x -> StateEvent tx
Generic)

instance HasEventId (StateEvent tx) where
  getEventId :: StateEvent tx -> EventId
getEventId = StateEvent tx -> EventId
forall tx. StateEvent tx -> EventId
eventId

deriving stock instance IsChainState tx => Show (StateEvent tx)
deriving stock instance IsChainState tx => Eq (StateEvent tx)
deriving anyclass instance IsChainState tx => ToJSON (StateEvent tx)
deriving anyclass instance IsChainState tx => FromJSON (StateEvent tx)

-- NOTE: This codec defines the row format persisted in the hydra.db events
-- table (see "Hydra.Events.SQLiteBased"). Changing it breaks decoding of
-- existing databases and requires a schema migration.
instance IsChainState tx => ToCBOR (StateEvent tx) where
  toCBOR :: StateEvent tx -> Encoding
toCBOR = StateEvent tx -> Encoding
forall a. (Generic a, GToCBOR (Rep a)) => a -> Encoding
genericToCBOR

instance IsChainState tx => FromCBOR (StateEvent tx) where
  fromCBOR :: forall s. Decoder s (StateEvent tx)
fromCBOR = Decoder s (StateEvent tx)
forall a s. (Generic a, GFromCBOR (Rep a)) => Decoder s a
genericFromCBOR

mkCheckpoint :: NodeState tx -> EventId -> UTCTime -> StateEvent tx
mkCheckpoint :: forall tx. NodeState tx -> EventId -> UTCTime -> StateEvent tx
mkCheckpoint NodeState tx
nodeState EventId
eventId UTCTime
time =
  StateEvent
    { EventId
$sel:eventId:StateEvent :: EventId
eventId :: EventId
eventId
    , $sel:stateChanged:StateEvent :: StateChanged tx
stateChanged = NodeState tx -> StateChanged tx
forall tx. NodeState tx -> StateChanged tx
Checkpoint NodeState tx
nodeState
    , UTCTime
$sel:time:StateEvent :: UTCTime
time :: UTCTime
time
    }