Skip to content

Commit 0ff447b

Browse files
committed
Add posibility to provide actual datums for hashes in reference inputs
1 parent ed1b363 commit 0ff447b

File tree

8 files changed

+153
-68
lines changed

8 files changed

+153
-68
lines changed

cardano-api/gen/Test/Gen/Cardano/Api/Typed.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1036,7 +1036,7 @@ genValidTxBody sbe =
10361036
-- | Partial! This function will throw an error when the generated transaction is invalid.
10371037
genTxBody :: (HasCallStack, Typeable era) => ShelleyBasedEra era -> Gen (TxBody era)
10381038
genTxBody era = do
1039-
res <- Api.createTransactionBody era <$> genTxBodyContent era
1039+
res <- Api.createTransactionBody era mempty <$> genTxBodyContent era
10401040
case res of
10411041
Left err -> error (docToString (prettyError err))
10421042
Right txBody -> pure txBody

cardano-api/src/Cardano/Api/Internal/Experimental/Tx.hs

+5-2
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ import Cardano.Api.Internal.ReexposeLedger (StrictMaybe (..), maybeToStrictMaybe
134134
import Cardano.Api.Internal.ReexposeLedger qualified as L
135135
import Cardano.Api.Internal.Tx.Body
136136
import Cardano.Api.Internal.Tx.Sign
137+
import Cardano.Api.Internal.Tx.UTxO (UTxO)
137138

138139
import Cardano.Crypto.Hash qualified as Hash
139140
import Cardano.Ledger.Alonzo.TxBody qualified as L
@@ -162,14 +163,16 @@ newtype UnsignedTxError
162163

163164
makeUnsignedTx
164165
:: Era era
166+
-> UTxO era
167+
-- ^ UTXO for reference inputs
165168
-> TxBodyContent BuildTx era
166169
-> Either TxBodyError (UnsignedTx era)
167-
makeUnsignedTx era bc = obtainCommonConstraints era $ do
170+
makeUnsignedTx era utxo bc = obtainCommonConstraints era $ do
168171
let sbe = convert era
169172
aeon = convert era
170173
TxScriptWitnessRequirements languages scripts datums redeemers <-
171174
shelleyBasedEraConstraints sbe $
172-
collectTxBodyScriptWitnessRequirements (convert era) bc
175+
collectTxBodyScriptWitnessRequirements (convert era) utxo bc
173176

174177
-- cardano-api types
175178
let apiTxOuts = txOuts bc

cardano-api/src/Cardano/Api/Internal/Fees.hs

+8-3
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,7 @@ estimateBalancedTxBody
596596
first TxFeeEstimationxBodyError $ -- TODO: impossible to fail now
597597
createTransactionBody
598598
sbe
599+
mempty
599600
txbodycontent1
600601
{ txFee = TxFeeExplicit sbe maxLovelaceFee
601602
, txOuts =
@@ -638,6 +639,7 @@ estimateBalancedTxBody
638639
first TxFeeEstimationxBodyError $ -- TODO: impossible to fail now
639640
createTransactionBody
640641
sbe
642+
mempty
641643
txbodycontent1
642644
{ txFee = TxFeeExplicit sbe fee
643645
, txReturnCollateral = retColl
@@ -678,7 +680,7 @@ estimateBalancedTxBody
678680
first TxFeeEstimationFinalConstructionError $ -- TODO: impossible to fail now. We need to implement a function
679681
-- that simply creates a transaction body because we have already
680682
-- validated the transaction body earlier within makeTransactionBodyAutoBalance
681-
createTransactionBody sbe finalTxBodyContent
683+
createTransactionBody sbe mempty finalTxBodyContent
682684
return
683685
( BalancedTxBody
684686
finalTxBodyContent
@@ -1365,7 +1367,7 @@ makeTransactionBodyAutoBalance
13651367
-- 3. update tx with fees
13661368
-- 4. balance the transaction and update tx change output
13671369

1368-
txbodyForChange <- first TxBodyError $ createTransactionBody sbe txbodycontent
1370+
txbodyForChange <- first TxBodyError $ createTransactionBody sbe utxo txbodycontent
13691371
let initialChangeTxOutValue =
13701372
evaluateTransactionBalance sbe pp poolids stakeDelegDeposits drepDelegDeposits utxo txbodyForChange
13711373
initialChangeTxOut =
@@ -1387,6 +1389,7 @@ makeTransactionBodyAutoBalance
13871389
first TxBodyError
13881390
$ createTransactionBody
13891391
sbe
1392+
utxo
13901393
$ txbodycontent
13911394
& modTxOuts
13921395
(<> [initialChangeTxOut])
@@ -1425,6 +1428,7 @@ makeTransactionBodyAutoBalance
14251428
first TxBodyError $ -- TODO: impossible to fail now
14261429
createTransactionBody
14271430
sbe
1431+
utxo
14281432
txbodycontent1
14291433
{ txFee = TxFeeExplicit sbe maxLovelaceFee
14301434
, txOuts =
@@ -1472,6 +1476,7 @@ makeTransactionBodyAutoBalance
14721476
first TxBodyError $ -- TODO: impossible to fail now
14731477
createTransactionBody
14741478
sbe
1479+
utxo
14751480
txbodycontent1
14761481
{ txFee = TxFeeExplicit sbe fee
14771482
, txReturnCollateral = retColl
@@ -1504,7 +1509,7 @@ makeTransactionBodyAutoBalance
15041509
first TxBodyError $ -- TODO: impossible to fail now. We need to implement a function
15051510
-- that simply creates a transaction body because we have already
15061511
-- validated the transaction body earlier within makeTransactionBodyAutoBalance
1507-
createTransactionBody sbe finalTxBodyContent
1512+
createTransactionBody sbe utxo finalTxBodyContent
15081513
return
15091514
( BalancedTxBody
15101515
finalTxBodyContent

cardano-api/src/Cardano/Api/Internal/Tx/Body.hs

+95-38
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ module Cardano.Api.Internal.Tx.Body
301301
-- ** Other transaction body types
302302
, TxInsCollateral (..)
303303
, TxInsReference (..)
304+
, TxInsReferenceActualDatums
305+
, getReferenceInputDatumMap
304306
, TxReturnCollateral (..)
305307
, TxTotalCollateral (..)
306308
, TxFee (..)
@@ -432,6 +434,8 @@ import Cardano.Api.Internal.SerialiseJSON
432434
import Cardano.Api.Internal.Tx.BuildTxWith
433435
import Cardano.Api.Internal.Tx.Output
434436
import Cardano.Api.Internal.Tx.Sign
437+
import Cardano.Api.Internal.Tx.UTxO (UTxO)
438+
import Cardano.Api.Internal.Tx.UTxO qualified as UTxO
435439
import Cardano.Api.Internal.TxIn
436440
import Cardano.Api.Internal.TxMetadata
437441
import Cardano.Api.Internal.Utils
@@ -570,16 +574,32 @@ deriving instance Eq (TxTotalCollateral era)
570574

571575
deriving instance Show (TxTotalCollateral era)
572576

573-
data TxInsReference era where
574-
TxInsReferenceNone :: TxInsReference era
577+
data TxInsReference build era where
578+
TxInsReferenceNone :: TxInsReference build era
575579
TxInsReference
576580
:: BabbageEraOnwards era
577581
-> [TxIn]
578-
-> TxInsReference era
582+
-- ^ A list of reference inputs
583+
-> TxInsReferenceActualDatums build
584+
-- ^ A set of datums, which hashes are referenced in UTXO of reference inputs. Those datums will be inserted
585+
-- to the datum map available to the scripts.
586+
-> TxInsReference build era
579587

580-
deriving instance Eq (TxInsReference era)
588+
deriving instance Eq (TxInsReference build era)
581589

582-
deriving instance Show (TxInsReference era)
590+
deriving instance Show (TxInsReference build era)
591+
592+
-- | The actual datums, referenced by hash in the transaction reference inputs.
593+
--
594+
-- Only datums referenced by hashes in UTXOs of reference inputs, will be inserted into the transaction.
595+
type TxInsReferenceActualDatums build = BuildTxWith build (Set HashableScriptData)
596+
597+
getReferenceInputDatumMap
598+
:: TxInsReferenceActualDatums build
599+
-> Map (Hash ScriptData) HashableScriptData
600+
getReferenceInputDatumMap = \case
601+
ViewTx -> mempty
602+
BuildTxWith datumSet -> fromList $ map (\h -> (hashScriptDataBytes h, h)) $ toList datumSet
583603

584604
-- ----------------------------------------------------------------------------
585605
-- Transaction fees
@@ -984,7 +1004,7 @@ data TxBodyContent build era
9841004
= TxBodyContent
9851005
{ txIns :: TxIns build era
9861006
, txInsCollateral :: TxInsCollateral era
987-
, txInsReference :: TxInsReference era
1007+
, txInsReference :: TxInsReference build era
9881008
, txOuts :: [TxOut CtxTx era]
9891009
, txTotalCollateral :: TxTotalCollateral era
9901010
, txReturnCollateral :: TxReturnCollateral CtxTx era
@@ -1075,25 +1095,35 @@ addTxInCollateral
10751095
:: IsAlonzoBasedEra era => TxIn -> TxBodyContent build era -> TxBodyContent build era
10761096
addTxInCollateral txInCollateral = addTxInsCollateral [txInCollateral]
10771097

1078-
setTxInsReference :: TxInsReference era -> TxBodyContent build era -> TxBodyContent build era
1098+
setTxInsReference :: TxInsReference build era -> TxBodyContent build era -> TxBodyContent build era
10791099
setTxInsReference v txBodyContent = txBodyContent{txInsReference = v}
10801100

10811101
modTxInsReference
1082-
:: (TxInsReference era -> TxInsReference era) -> TxBodyContent build era -> TxBodyContent build era
1102+
:: (TxInsReference build era -> TxInsReference build era)
1103+
-> TxBodyContent build era
1104+
-> TxBodyContent build era
10831105
modTxInsReference f txBodyContent = txBodyContent{txInsReference = f (txInsReference txBodyContent)}
10841106

10851107
addTxInsReference
1086-
:: IsBabbageBasedEra era => [TxIn] -> TxBodyContent build era -> TxBodyContent build era
1087-
addTxInsReference txInsReference =
1088-
modTxInsReference
1089-
( \case
1090-
TxInsReferenceNone -> TxInsReference babbageBasedEra txInsReference
1091-
TxInsReference era xs -> TxInsReference era (xs <> txInsReference)
1092-
)
1108+
:: Applicative (BuildTxWith build)
1109+
=> IsBabbageBasedEra era
1110+
=> [TxIn]
1111+
-> Set HashableScriptData
1112+
-> TxBodyContent build era
1113+
-> TxBodyContent build era
1114+
addTxInsReference txInsReference scriptData =
1115+
modTxInsReference $
1116+
\case
1117+
TxInsReferenceNone -> TxInsReference babbageBasedEra txInsReference (pure scriptData)
1118+
TxInsReference era xs bScriptData' -> TxInsReference era (xs <> txInsReference) ((<> scriptData) <$> bScriptData')
10931119

10941120
addTxInReference
1095-
:: IsBabbageBasedEra era => TxIn -> TxBodyContent build era -> TxBodyContent build era
1096-
addTxInReference txInReference = addTxInsReference [txInReference]
1121+
:: Applicative (BuildTxWith build)
1122+
=> IsBabbageBasedEra era
1123+
=> TxIn
1124+
-> TxBodyContent build era
1125+
-> TxBodyContent build era
1126+
addTxInReference txInReference = addTxInsReference [txInReference] mempty
10971127

10981128
setTxOuts :: [TxOut CtxTx era] -> TxBodyContent build era -> TxBodyContent build era
10991129
setTxOuts v txBodyContent = txBodyContent{txOuts = v}
@@ -1370,9 +1400,11 @@ createTransactionBody
13701400
:: forall era
13711401
. HasCallStack
13721402
=> ShelleyBasedEra era
1403+
-> UTxO era
1404+
-- ^ UTXO for reference inputs
13731405
-> TxBodyContent BuildTx era
13741406
-> Either TxBodyError (TxBody era)
1375-
createTransactionBody sbe bc =
1407+
createTransactionBody sbe utxo bc =
13761408
shelleyBasedEraConstraints sbe $ do
13771409
(sData, mScriptIntegrityHash, scripts) <-
13781410
caseShelleyToMaryOrAlonzoEraOnwards
@@ -1387,7 +1419,7 @@ createTransactionBody sbe bc =
13871419
)
13881420
( \aeon -> do
13891421
TxScriptWitnessRequirements languages scripts dats redeemers <-
1390-
collectTxBodyScriptWitnessRequirements aeon bc
1422+
collectTxBodyScriptWitnessRequirements aeon utxo bc
13911423

13921424
let pparams = txProtocolParams bc
13931425
sData = TxBodyScriptData aeon dats redeemers
@@ -1742,11 +1774,11 @@ fromLedgerTxInsCollateral sbe body =
17421774
sbe
17431775

17441776
fromLedgerTxInsReference
1745-
:: ShelleyBasedEra era -> Ledger.TxBody (ShelleyLedgerEra era) -> TxInsReference era
1777+
:: ShelleyBasedEra era -> Ledger.TxBody (ShelleyLedgerEra era) -> TxInsReference ViewTx era
17461778
fromLedgerTxInsReference sbe txBody =
17471779
caseShelleyToAlonzoOrBabbageEraOnwards
17481780
(const TxInsReferenceNone)
1749-
(\w -> TxInsReference w $ map fromShelleyTxIn . toList $ txBody ^. L.referenceInputsTxBodyL)
1781+
(\w -> TxInsReference w (map fromShelleyTxIn . toList $ txBody ^. L.referenceInputsTxBodyL) ViewTx)
17501782
sbe
17511783

17521784
fromLedgerTxTotalCollateral
@@ -2108,11 +2140,11 @@ convPParamsToScriptIntegrityHash
21082140
-> Alonzo.TxDats (ShelleyLedgerEra era)
21092141
-> Set Plutus.Language
21102142
-> StrictMaybe L.ScriptIntegrityHash
2111-
convPParamsToScriptIntegrityHash w txProtocolParams redeemers datums languages =
2143+
convPParamsToScriptIntegrityHash w (BuildTxWith mTxProtocolParams) redeemers datums languages =
21122144
alonzoEraOnwardsConstraints w $
2113-
case txProtocolParams of
2114-
BuildTxWith Nothing -> SNothing
2115-
BuildTxWith (Just (LedgerProtocolParameters pp)) ->
2145+
case mTxProtocolParams of
2146+
Nothing -> SNothing
2147+
Just (LedgerProtocolParameters pp) ->
21162148
Alonzo.hashScriptIntegrity (Set.map (L.getLanguageView pp) languages) redeemers datums
21172149

21182150
convLanguages :: [(ScriptWitnessIndex, AnyScriptWitness era)] -> Set Plutus.Language
@@ -2122,11 +2154,11 @@ convLanguages witnesses =
21222154
| (_, AnyScriptWitness (PlutusScriptWitness _ v _ _ _ _)) <- witnesses
21232155
]
21242156

2125-
convReferenceInputs :: TxInsReference era -> Set Ledger.TxIn
2157+
convReferenceInputs :: TxInsReference build era -> Set Ledger.TxIn
21262158
convReferenceInputs txInsReference =
21272159
case txInsReference of
21282160
TxInsReferenceNone -> mempty
2129-
TxInsReference _ refTxins -> fromList $ map toShelleyTxIn refTxins
2161+
TxInsReference _ refTxins _ -> fromList $ map toShelleyTxIn refTxins
21302162

21312163
-- | Returns an OSet of proposals from 'TxProposalProcedures'.
21322164
convProposalProcedures
@@ -2986,18 +3018,27 @@ collectTxBodyScriptWitnessRequirements
29863018
:: forall era
29873019
. IsShelleyBasedEra era
29883020
=> AlonzoEraOnwards era
3021+
-> UTxO era
3022+
-- ^ UTXO for reference inputs
29893023
-> TxBodyContent BuildTx era
29903024
-> Either
29913025
TxBodyError
29923026
(TxScriptWitnessRequirements (ShelleyLedgerEra era))
29933027
collectTxBodyScriptWitnessRequirements
29943028
aEon
3029+
utxo
29953030
bc@TxBodyContent
2996-
{ txOuts
3031+
{ txInsReference
3032+
, txOuts
29973033
} =
29983034
obtainAlonzoScriptPurposeConstraints aEon $ do
29993035
let sbe = shelleyBasedEra @era
3000-
supplementaldatums = TxScriptWitnessRequirements mempty mempty (getSupplementalDatums aEon txOuts) mempty
3036+
supplementaldatums =
3037+
TxScriptWitnessRequirements
3038+
mempty
3039+
mempty
3040+
(getDatums aEon txInsReference utxo txOuts)
3041+
mempty
30013042
txInWits <-
30023043
first TxBodyPlutusScriptDecodeError $
30033044
legacyWitnessToScriptRequirements aEon $
@@ -3051,19 +3092,35 @@ collectTxBodyScriptWitnessRequirements
30513092
, txProposalWits
30523093
]
30533094

3054-
getSupplementalDatums
3095+
-- | Extract datum:
3096+
-- 1. supplemental datums from transaction outputs
3097+
-- 2. datums from reference inputs, whose hashes are present in UTXO (for those inputs)
3098+
getDatums
30553099
:: AlonzoEraOnwards era
3100+
-> TxInsReference BuildTx era
3101+
-- ^ reference inputs
3102+
-> UTxO era
3103+
-- ^ UTxO for reference inputs
30563104
-> [TxOut CtxTx era]
30573105
-> L.TxDats (ShelleyLedgerEra era)
3058-
getSupplementalDatums eon [] = alonzoEraOnwardsConstraints eon mempty
3059-
getSupplementalDatums eon txouts =
3060-
alonzoEraOnwardsConstraints eon $
3061-
L.TxDats $
3062-
fromList
3063-
[ (L.hashData ledgerData, ledgerData)
3064-
| TxOut _ _ (TxOutSupplementalDatum _ d) _ <- txouts
3065-
, let ledgerData = toAlonzoData d
3106+
getDatums eon txInsRef utxo txOutsFromTx = alonzoEraOnwardsConstraints eon $ do
3107+
let refTxInsDats =
3108+
[ d
3109+
| TxInsReference _ txIns datumSet <- [txInsRef]
3110+
, let datumMap = getReferenceInputDatumMap datumSet
3111+
, txIn <- txIns
3112+
, -- resolve only hashes
3113+
TxOut _ _ (TxOutDatumHash _ datumHash) _ <- maybeToList $ UTxO.lookup txIn utxo
3114+
, d <- maybeToList $ Map.lookup datumHash datumMap
30663115
]
3116+
-- use only supplemental datum
3117+
txOutsDats = [d | TxOut _ _ (TxOutSupplementalDatum _ d) _ <- txOutsFromTx]
3118+
L.TxDats $
3119+
fromList $
3120+
[ (L.hashData ledgerData, ledgerData)
3121+
| d <- refTxInsDats <> txOutsDats
3122+
, let ledgerData = toAlonzoData d
3123+
]
30673124

30683125
extractWitnessableTxIns
30693126
:: AlonzoEraOnwards era

cardano-api/src/Cardano/Api/Internal/Tx/BuildTxWith.hs

+7
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ instance Applicative (BuildTxWith BuildTx) where
4040
pure = BuildTxWith
4141
(BuildTxWith f) <*> (BuildTxWith a) = BuildTxWith (f a)
4242

43+
instance Semigroup a => Semigroup (BuildTxWith build a) where
44+
ViewTx <> ViewTx = ViewTx
45+
(BuildTxWith a) <> (BuildTxWith b) = BuildTxWith (a <> b)
46+
47+
instance (Applicative (BuildTxWith build), Monoid a) => Monoid (BuildTxWith build a) where
48+
mempty = pure mempty
49+
4350
buildTxWithToMaybe :: BuildTxWith build a -> Maybe a
4451
buildTxWithToMaybe ViewTx = Nothing
4552
buildTxWithToMaybe (BuildTxWith a) = Just a

0 commit comments

Comments
 (0)