{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
module Cardano.Ledger.Babbage.Scripts where
import Cardano.Ledger.Alonzo.Data (Data)
import Cardano.Ledger.Alonzo.PlutusScriptApi (getSpendingTxIn)
import Cardano.Ledger.Alonzo.Tx
( ScriptPurpose (..),
ValidatedTx (..),
isTwoPhaseScriptAddressFromMap,
txdats',
)
import Cardano.Ledger.Alonzo.TxWitness (TxWitness, unTxDats)
import Cardano.Ledger.Babbage.TxBody
( Datum (..),
TxOut (..),
txOutData,
txOutDataHash,
)
import qualified Cardano.Ledger.Core as Core
import Cardano.Ledger.Era (Crypto, Era, ValidateScript (hashScript))
import Cardano.Ledger.Hashes (DataHash)
import Cardano.Ledger.Shelley.Scripts (ScriptHash (..))
import Cardano.Ledger.Shelley.UTxO (UTxO (..))
import Cardano.Ledger.TxIn (TxIn)
import Control.Applicative ((<|>))
import Control.SetAlgebra (eval, (◁))
import qualified Data.Map.Strict as Map
import Data.Maybe.Strict (StrictMaybe (SJust, SNothing))
import Data.Set (Set)
import qualified Data.Set as Set
import GHC.Records (HasField (..))
getDatumBabbage ::
( Era era,
Core.TxOut era ~ TxOut era,
Core.Witnesses era ~ TxWitness era
) =>
Core.Tx era ->
UTxO era ->
ScriptPurpose (Crypto era) ->
Maybe (Data era)
getDatumBabbage :: Tx era
-> UTxO era -> ScriptPurpose (Crypto era) -> Maybe (Data era)
getDatumBabbage Tx era
tx (UTxO Map (TxIn (Crypto era)) (TxOut era)
m) ScriptPurpose (Crypto era)
sp = do
TxIn (Crypto era)
txIn <- ScriptPurpose (Crypto era) -> Maybe (TxIn (Crypto era))
forall crypto. ScriptPurpose crypto -> Maybe (TxIn crypto)
getSpendingTxIn ScriptPurpose (Crypto era)
sp
TxOut era
txOut <- TxIn (Crypto era)
-> Map (TxIn (Crypto era)) (TxOut era) -> Maybe (TxOut era)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup TxIn (Crypto era)
txIn Map (TxIn (Crypto era)) (TxOut era)
Map (TxIn (Crypto era)) (TxOut era)
m
let txOutDataFromWits :: Maybe (Data era)
txOutDataFromWits = do
DataHash (Crypto era)
hash <- TxOut era -> Maybe (DataHash (Crypto era))
forall era. Era era => TxOut era -> Maybe (DataHash (Crypto era))
txOutDataHash TxOut era
txOut
DataHash (Crypto era)
-> Map (DataHash (Crypto era)) (Data era) -> Maybe (Data era)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup DataHash (Crypto era)
hash (TxDats era -> Map (DataHash (Crypto era)) (Data era)
forall era. TxDats era -> Map (DataHash (Crypto era)) (Data era)
unTxDats (TxWitness era -> TxDats era
forall era. TxWitness era -> TxDats era
txdats' (Tx era -> TxWitness era
forall k (x :: k) r a. HasField x r a => r -> a
getField @"wits" Tx era
tx)))
TxOut era -> Maybe (Data era)
forall era. TxOut era -> Maybe (Data era)
txOutData TxOut era
txOut Maybe (Data era) -> Maybe (Data era) -> Maybe (Data era)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe (Data era)
txOutDataFromWits
babbageTxScripts ::
forall era.
( ValidateScript era,
HasField "referenceScript" (Core.TxOut era) (StrictMaybe (Core.Script era)),
HasField "inputs" (Core.TxBody era) (Set (TxIn (Crypto era))),
HasField "referenceInputs" (Core.TxBody era) (Set (TxIn (Crypto era)))
) =>
UTxO era ->
Core.Tx era ->
Map.Map (ScriptHash (Crypto era)) (Core.Script era)
babbageTxScripts :: UTxO era -> Tx era -> Map (ScriptHash (Crypto era)) (Script era)
babbageTxScripts UTxO era
utxo Tx era
tx = Map (ScriptHash (Crypto era)) (Script era)
ans
where
txbody :: TxBody era
txbody = Tx era -> TxBody era
forall k (x :: k) r a. HasField x r a => r -> a
getField @"body" Tx era
tx
ins :: Set (TxIn (Crypto era))
ins = TxBody era -> Set (TxIn (Crypto era))
forall k (x :: k) r a. HasField x r a => r -> a
getField @"referenceInputs" TxBody era
txbody Set (TxIn (Crypto era))
-> Set (TxIn (Crypto era)) -> Set (TxIn (Crypto era))
forall a. Ord a => Set a -> Set a -> Set a
`Set.union` TxBody era -> Set (TxIn (Crypto era))
forall k (x :: k) r a. HasField x r a => r -> a
getField @"inputs" TxBody era
txbody
ans :: Map (ScriptHash (Crypto era)) (Script era)
ans = Map (ScriptHash (Crypto era)) (Script era)
-> Map (ScriptHash (Crypto era)) (Script era)
-> Map (ScriptHash (Crypto era)) (Script era)
forall k a. Ord k => Map k a -> Map k a -> Map k a
Map.union (Set (TxIn (Crypto era))
-> UTxO era -> Map (ScriptHash (Crypto era)) (Script era)
forall era.
(ValidateScript era,
HasField
"referenceScript" (TxOut era) (StrictMaybe (Script era))) =>
Set (TxIn (Crypto era))
-> UTxO era -> Map (ScriptHash (Crypto era)) (Script era)
refScripts Set (TxIn (Crypto era))
ins UTxO era
utxo) (Tx era -> Map (ScriptHash (Crypto era)) (Script era)
forall k (x :: k) r a. HasField x r a => r -> a
getField @"scriptWits" Tx era
tx)
refScripts ::
forall era.
(ValidateScript era, HasField "referenceScript" (Core.TxOut era) (StrictMaybe (Core.Script era))) =>
Set (TxIn (Crypto era)) ->
UTxO era ->
Map.Map (ScriptHash (Crypto era)) (Core.Script era)
refScripts :: Set (TxIn (Crypto era))
-> UTxO era -> Map (ScriptHash (Crypto era)) (Script era)
refScripts Set (TxIn (Crypto era))
ins (UTxO Map (TxIn (Crypto era)) (TxOut era)
mp) = (Map (ScriptHash (Crypto era)) (Script era)
-> TxOut era -> Map (ScriptHash (Crypto era)) (Script era))
-> Map (ScriptHash (Crypto era)) (Script era)
-> Map (TxIn (Crypto era)) (TxOut era)
-> Map (ScriptHash (Crypto era)) (Script era)
forall a b k. (a -> b -> a) -> a -> Map k b -> a
Map.foldl' Map (ScriptHash (Crypto era)) (Script era)
-> TxOut era -> Map (ScriptHash (Crypto era)) (Script era)
accum Map (ScriptHash (Crypto era)) (Script era)
forall k a. Map k a
Map.empty (Exp (Map (TxIn (Crypto era)) (TxOut era))
-> Map (TxIn (Crypto era)) (TxOut era)
forall s t. Embed s t => Exp t -> s
eval (Set (TxIn (Crypto era))
ins Set (TxIn (Crypto era))
-> Map (TxIn (Crypto era)) (TxOut era)
-> Exp (Map (TxIn (Crypto era)) (TxOut era))
forall k s1 s2 (f :: * -> * -> *) v.
(Ord k, HasExp s1 (Sett k ()), HasExp s2 (f k v)) =>
s1 -> s2 -> Exp (f k v)
◁ Map (TxIn (Crypto era)) (TxOut era)
mp))
where
accum :: Map (ScriptHash (Crypto era)) (Script era)
-> TxOut era -> Map (ScriptHash (Crypto era)) (Script era)
accum Map (ScriptHash (Crypto era)) (Script era)
ans TxOut era
txout =
case TxOut era -> StrictMaybe (Script era)
forall k (x :: k) r a. HasField x r a => r -> a
getField @"referenceScript" TxOut era
txout of
StrictMaybe (Script era)
SNothing -> Map (ScriptHash (Crypto era)) (Script era)
ans
(SJust Script era
script) -> ScriptHash (Crypto era)
-> Script era
-> Map (ScriptHash (Crypto era)) (Script era)
-> Map (ScriptHash (Crypto era)) (Script era)
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert (Script era -> ScriptHash (Crypto era)
forall era.
ValidateScript era =>
Script era -> ScriptHash (Crypto era)
hashScript @era Script era
script) Script era
script Map (ScriptHash (Crypto era)) (Script era)
ans
babbageInputDataHashes ::
forall era.
( HasField "inputs" (Core.TxBody era) (Set (TxIn (Crypto era))),
ValidateScript era,
Core.TxOut era ~ TxOut era
) =>
Map.Map (ScriptHash (Crypto era)) (Core.Script era) ->
ValidatedTx era ->
UTxO era ->
(Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
babbageInputDataHashes :: Map (ScriptHash (Crypto era)) (Script era)
-> ValidatedTx era
-> UTxO era
-> (Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
babbageInputDataHashes Map (ScriptHash (Crypto era)) (Script era)
hashScriptMap ValidatedTx era
tx (UTxO Map (TxIn (Crypto era)) (TxOut era)
mp) =
((Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
-> TxIn (Crypto era)
-> TxOut era
-> (Set (DataHash (Crypto era)), Set (TxIn (Crypto era))))
-> (Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
-> Map (TxIn (Crypto era)) (TxOut era)
-> (Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
forall a k b. (a -> k -> b -> a) -> a -> Map k b -> a
Map.foldlWithKey' (Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
-> TxIn (Crypto era)
-> TxOut era
-> (Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
accum (Set (DataHash (Crypto era))
forall a. Set a
Set.empty, Set (TxIn (Crypto era))
forall a. Set a
Set.empty) Map (TxIn (Crypto era)) (TxOut era)
smallUtxo
where
txbody :: TxBody era
txbody = ValidatedTx era -> TxBody era
forall era. ValidatedTx era -> TxBody era
body ValidatedTx era
tx
spendinputs :: Set (TxIn (Crypto era))
spendinputs = TxBody era -> Set (TxIn (Crypto era))
forall k (x :: k) r a. HasField x r a => r -> a
getField @"inputs" TxBody era
txbody :: Set (TxIn (Crypto era))
smallUtxo :: Map (TxIn (Crypto era)) (TxOut era)
smallUtxo = Exp (Map (TxIn (Crypto era)) (TxOut era))
-> Map (TxIn (Crypto era)) (TxOut era)
forall s t. Embed s t => Exp t -> s
eval (Set (TxIn (Crypto era))
spendinputs Set (TxIn (Crypto era))
-> Map (TxIn (Crypto era)) (TxOut era)
-> Exp (Map (TxIn (Crypto era)) (TxOut era))
forall k s1 s2 (f :: * -> * -> *) v.
(Ord k, HasExp s1 (Sett k ()), HasExp s2 (f k v)) =>
s1 -> s2 -> Exp (f k v)
◁ Map (TxIn (Crypto era)) (TxOut era)
Map (TxIn (Crypto era)) (TxOut era)
mp)
accum :: (Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
-> TxIn (Crypto era)
-> TxOut era
-> (Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
accum ans :: (Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
ans@(!Set (DataHash (Crypto era))
hashSet, !Set (TxIn (Crypto era))
inputSet) TxIn (Crypto era)
txin TxOut era
txout =
case TxOut era
txout of
TxOut Addr (Crypto era)
addr Value era
_ Datum era
NoDatum StrictMaybe (Script era)
_ ->
if Map (ScriptHash (Crypto era)) (Script era)
-> Addr (Crypto era) -> Bool
forall era.
ValidateScript era =>
Map (ScriptHash (Crypto era)) (Script era)
-> Addr (Crypto era) -> Bool
isTwoPhaseScriptAddressFromMap @era Map (ScriptHash (Crypto era)) (Script era)
hashScriptMap Addr (Crypto era)
addr
then (Set (DataHash (Crypto era))
hashSet, TxIn (Crypto era)
-> Set (TxIn (Crypto era)) -> Set (TxIn (Crypto era))
forall a. Ord a => a -> Set a -> Set a
Set.insert TxIn (Crypto era)
txin Set (TxIn (Crypto era))
inputSet)
else (Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
ans
TxOut Addr (Crypto era)
addr Value era
_ (DatumHash DataHash (Crypto era)
dhash) StrictMaybe (Script era)
_ ->
if Map (ScriptHash (Crypto era)) (Script era)
-> Addr (Crypto era) -> Bool
forall era.
ValidateScript era =>
Map (ScriptHash (Crypto era)) (Script era)
-> Addr (Crypto era) -> Bool
isTwoPhaseScriptAddressFromMap @era Map (ScriptHash (Crypto era)) (Script era)
hashScriptMap Addr (Crypto era)
addr
then (DataHash (Crypto era)
-> Set (DataHash (Crypto era)) -> Set (DataHash (Crypto era))
forall a. Ord a => a -> Set a -> Set a
Set.insert DataHash (Crypto era)
dhash Set (DataHash (Crypto era))
hashSet, Set (TxIn (Crypto era))
inputSet)
else (Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
ans
TxOut Addr (Crypto era)
_ Value era
_ (Datum BinaryData era
_) StrictMaybe (Script era)
_ -> (Set (DataHash (Crypto era)), Set (TxIn (Crypto era)))
ans