{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

-- | Definition of the shelley era, along with instances ot the @Core@ types
-- defined in @module Cardano.Ledger.Core@, and instances of the @API@ classes
-- exposed in @module Cardano.Ledger.Shelley.API@.
module Cardano.Ledger.Shelley
  ( ShelleyEra,
    Self,
    TxOut,
    TxBody,
    Value,
    Script,
    AuxiliaryData,
    PParams,
    Core.PParamsDelta,
    Tx,
    Witnesses,
    nativeMultiSigTag,
  )
where

import Cardano.Ledger.AuxiliaryData
  ( AuxiliaryDataHash (..),
    ValidateAuxiliaryData (..),
  )
import Cardano.Ledger.Coin (Coin)
import qualified Cardano.Ledger.Core as Core
import qualified Cardano.Ledger.Crypto as CryptoClass
import Cardano.Ledger.Era (SupportsSegWit (..), ValidateScript (..))
import qualified Cardano.Ledger.Era as E (Era (..), TranslationContext)
import Cardano.Ledger.Hashes (EraIndependentAuxiliaryData)
import Cardano.Ledger.SafeHash (makeHashWithExplicitProxys)
import Cardano.Ledger.Shelley.BlockChain (bbHash)
import qualified Cardano.Ledger.Shelley.BlockChain as Shelley
  ( TxSeq (..),
    txSeqTxns,
  )
import Cardano.Ledger.Shelley.Constraints
  ( UsesPParams (..),
    UsesTxBody,
    UsesTxOut (..),
    UsesValue,
  )
import Cardano.Ledger.Shelley.Metadata (Metadata (Metadata), validMetadatum)
import Cardano.Ledger.Shelley.PParams (PParams, PParamsUpdate, updatePParams)
import Cardano.Ledger.Shelley.Scripts (MultiSig)
import Cardano.Ledger.Shelley.Tx
  ( WitnessSet,
    validateNativeMultiSigScript,
  )
import qualified Cardano.Ledger.Shelley.Tx as STx (Tx, TxBody, TxOut (..))
import qualified Data.ByteString as BS
import Data.Proxy
import GHC.Records (HasField (..))

data ShelleyEra c

instance CryptoClass.Crypto c => E.Era (ShelleyEra c) where
  type Crypto (ShelleyEra c) = c

  getTxOutEitherAddr :: TxOut (ShelleyEra c)
-> Either
     (Addr (Crypto (ShelleyEra c)))
     (CompactAddr (Crypto (ShelleyEra c)))
getTxOutEitherAddr (STx.TxOutCompact a _) = CompactAddr c -> Either (Addr c) (CompactAddr c)
forall a b. b -> Either a b
Right CompactAddr c
CompactAddr (Crypto (ShelleyEra c))
a

  getAllTxInputs :: TxBody (ShelleyEra c) -> Set (TxIn (Crypto (ShelleyEra c)))
getAllTxInputs = forall k (x :: k) r a. HasField x r a => r -> a
forall r a. HasField "inputs" r a => r -> a
getField @"inputs"

instance CryptoClass.Crypto c => UsesValue (ShelleyEra c)

instance CryptoClass.Crypto c => UsesTxOut (ShelleyEra c) where
  makeTxOut :: Proxy (ShelleyEra c)
-> Addr (Crypto (ShelleyEra c))
-> Value (ShelleyEra c)
-> TxOut (ShelleyEra c)
makeTxOut Proxy (ShelleyEra c)
_ Addr (Crypto (ShelleyEra c))
a Value (ShelleyEra c)
v = Addr (Crypto (ShelleyEra c))
-> Value (ShelleyEra c) -> TxOut (ShelleyEra c)
forall era.
(Era era, Show (Value era), Compactible (Value era)) =>
Addr (Crypto era) -> Value era -> TxOut era
STx.TxOut Addr (Crypto (ShelleyEra c))
a Value (ShelleyEra c)
v

instance CryptoClass.Crypto c => UsesPParams (ShelleyEra c) where
  mergePPUpdates :: proxy (ShelleyEra c)
-> PParams (ShelleyEra c)
-> PParamsDelta (ShelleyEra c)
-> PParams (ShelleyEra c)
mergePPUpdates proxy (ShelleyEra c)
_ = PParams (ShelleyEra c)
-> PParamsDelta (ShelleyEra c) -> PParams (ShelleyEra c)
forall era. PParams era -> PParamsUpdate era -> PParams era
updatePParams

type instance E.TranslationContext (ShelleyEra c) = ()

--------------------------------------------------------------------------------
-- Core instances
--------------------------------------------------------------------------------

type instance Core.Tx (ShelleyEra c) = STx.Tx (ShelleyEra c)

type instance Core.Value (ShelleyEra _c) = Coin

type instance Core.TxBody (ShelleyEra c) = STx.TxBody (ShelleyEra c)

type instance Core.TxOut (ShelleyEra c) = STx.TxOut (ShelleyEra c)

type instance Core.Script (ShelleyEra c) = MultiSig c

type instance Core.AuxiliaryData (ShelleyEra c) = Metadata (ShelleyEra c)

type instance Core.PParams (ShelleyEra c) = PParams (ShelleyEra c)

type instance Core.Witnesses (ShelleyEra c) = WitnessSet (ShelleyEra c)

type instance Core.PParamsDelta (ShelleyEra c) = PParamsUpdate (ShelleyEra c)

--------------------------------------------------------------------------------
-- Ledger data instances
--------------------------------------------------------------------------------

-- | Magic number "memorialized" in the ValidateScript class under the method:
--   scriptPrefixTag:: Core.Script era -> Bs.ByteString, for the Shelley Era.
nativeMultiSigTag :: BS.ByteString
nativeMultiSigTag :: ByteString
nativeMultiSigTag = ByteString
"\00"

instance
  (CryptoClass.Crypto c, UsesTxBody (ShelleyEra c)) =>
  ValidateScript (ShelleyEra c)
  where
  scriptPrefixTag :: Script (ShelleyEra c) -> ByteString
scriptPrefixTag Script (ShelleyEra c)
_script = ByteString
nativeMultiSigTag

  -- In the ShelleyEra there is only one kind of Script and its tag is "\x00"
  validateScript :: Script (ShelleyEra c) -> Tx (ShelleyEra c) -> Bool
validateScript = Script (ShelleyEra c) -> Tx (ShelleyEra c) -> Bool
forall era.
(TransTx ToCBOR era, Witnesses era ~ WitnessSet era) =>
MultiSig (Crypto era) -> Tx era -> Bool
validateNativeMultiSigScript

instance CryptoClass.Crypto c => SupportsSegWit (ShelleyEra c) where
  type TxSeq (ShelleyEra c) = Shelley.TxSeq (ShelleyEra c)
  fromTxSeq :: TxSeq (ShelleyEra c) -> StrictSeq (Tx (ShelleyEra c))
fromTxSeq = TxSeq (ShelleyEra c) -> StrictSeq (Tx (ShelleyEra c))
forall era. TxSeq era -> StrictSeq (Tx era)
Shelley.txSeqTxns
  toTxSeq :: StrictSeq (Tx (ShelleyEra c)) -> TxSeq (ShelleyEra c)
toTxSeq = StrictSeq (Tx (ShelleyEra c)) -> TxSeq (ShelleyEra c)
forall era.
(Era era, SafeToHash (Witnesses era)) =>
StrictSeq (Tx era) -> TxSeq era
Shelley.TxSeq
  hashTxSeq :: TxSeq (ShelleyEra c)
-> Hash (HASH (Crypto (ShelleyEra c))) EraIndependentBlockBody
hashTxSeq = TxSeq (ShelleyEra c)
-> Hash (HASH (Crypto (ShelleyEra c))) EraIndependentBlockBody
forall era.
Era era =>
TxSeq era -> Hash (Crypto era) EraIndependentBlockBody
bbHash
  numSegComponents :: Word64
numSegComponents = Word64
3

instance CryptoClass.Crypto c => ValidateAuxiliaryData (ShelleyEra c) c where
  validateAuxiliaryData :: ProtVer -> AuxiliaryData (ShelleyEra c) -> Bool
validateAuxiliaryData ProtVer
_ (Metadata m) = (Metadatum -> Bool) -> Map Word64 Metadatum -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Metadatum -> Bool
validMetadatum Map Word64 Metadatum
m
  hashAuxiliaryData :: AuxiliaryData (ShelleyEra c) -> AuxiliaryDataHash c
hashAuxiliaryData AuxiliaryData (ShelleyEra c)
metadata = SafeHash c EraIndependentAuxiliaryData -> AuxiliaryDataHash c
forall crypto.
SafeHash crypto EraIndependentAuxiliaryData
-> AuxiliaryDataHash crypto
AuxiliaryDataHash (Proxy c
-> Proxy EraIndependentAuxiliaryData
-> Metadata (ShelleyEra c)
-> SafeHash c EraIndependentAuxiliaryData
forall t c index.
(SafeToHash t, HasAlgorithm c) =>
Proxy c -> Proxy index -> t -> SafeHash c index
makeHashWithExplicitProxys (Proxy c
forall k (t :: k). Proxy t
Proxy @c) Proxy EraIndependentAuxiliaryData
index AuxiliaryData (ShelleyEra c)
Metadata (ShelleyEra c)
metadata)
    where
      index :: Proxy EraIndependentAuxiliaryData
index = Proxy EraIndependentAuxiliaryData
forall k (t :: k). Proxy t
Proxy @EraIndependentAuxiliaryData

-- Self describing synonyms

type Value era = Coin

type Script era = MultiSig (E.Crypto era)

type AuxiliaryData era = Metadata era

type Self c = ShelleyEra c

type Tx era = STx.Tx era

type TxOut era = STx.TxOut era

type TxBody era = STx.TxBody era

type Witnesses era = WitnessSet (E.Crypto era)