@@ -14,6 +14,7 @@ import Data.Time.Clock.POSIX
14
14
import Hydra.Cardano.Api hiding (LedgerState , fromNetworkMagic )
15
15
16
16
import Cardano.Api.UTxO qualified as UTxO
17
+ import Cardano.Crypto.Hash (hashToTextAsHex )
17
18
import Cardano.Ledger.Api.PParams
18
19
import Cardano.Ledger.BaseTypes (EpochInterval (.. ), EpochSize (.. ), NonNegativeInterval , UnitInterval , boundRational , unsafeNonZero )
19
20
import Cardano.Ledger.Binary.Version (mkVersion )
@@ -42,7 +43,7 @@ import Data.Text qualified as T
42
43
import Hydra.Cardano.Api.Prelude (StakePoolKey , fromNetworkMagic )
43
44
import Hydra.Chain.CardanoClient (QueryPoint (.. ))
44
45
import Hydra.Chain.ScriptRegistry (buildScriptPublishingTxs )
45
- import Hydra.Tx (txId )
46
+ import Hydra.Tx (ScriptRegistry , newScriptRegistry , txId )
46
47
import Money qualified
47
48
import Ouroboros.Consensus.Block (GenesisWindow (.. ))
48
49
import Ouroboros.Consensus.HardFork.History (Bound (.. ), EraEnd (.. ), EraParams (.. ), EraSummary (.. ), SafeZone (.. ), Summary (.. ), mkInterpreter )
@@ -63,6 +64,34 @@ runBlockfrostM prj action = do
63
64
Left err -> throwIO (BlockfrostError $ show err)
64
65
Right val -> pure val
65
66
67
+ -- | Query for 'TxIn's in the search for outputs containing all the reference
68
+ -- scripts of the 'ScriptRegistry'.
69
+ --
70
+ -- This is implemented by repeated querying until we have all necessary
71
+ -- reference scripts as we do only know the transaction id, not the indices.
72
+ --
73
+ -- Can throw at least 'NewScriptRegistryException' on failure.
74
+ queryScriptRegistry ::
75
+ (MonadIO m , MonadThrow m ) =>
76
+ FilePath ->
77
+ [TxId ] ->
78
+ m (ScriptRegistry , NetworkId )
79
+ queryScriptRegistry projectPath txIds = do
80
+ prj <- liftIO $ Blockfrost. projectFromFile projectPath
81
+ runBlockfrostM prj $ do
82
+ Blockfrost. Genesis
83
+ { _genesisNetworkMagic
84
+ , _genesisSystemStart
85
+ } <-
86
+ queryGenesis
87
+ let networkId = toCardanoNetworkId _genesisNetworkMagic
88
+ utxoList <- forM candidates $ \ candidateTxIn -> queryUTxOByTxIn networkId candidateTxIn
89
+ case newScriptRegistry $ UTxO. squash utxoList of
90
+ Left e -> liftIO $ throwIO e
91
+ Right sr -> pure (sr, networkId)
92
+ where
93
+ candidates = map (\ txid -> TxIn txid (TxIx 0 )) txIds
94
+
66
95
publishHydraScripts ::
67
96
-- | The path where the Blockfrost project token hash is stored.
68
97
FilePath ->
@@ -114,13 +143,13 @@ toCardanoUTxO :: [Blockfrost.AddressUtxo] -> AddressInEra -> UTxO' (TxOut CtxUTx
114
143
toCardanoUTxO utxos addr = UTxO. fromPairs (toEntry <$> utxos)
115
144
where
116
145
toEntry :: Blockfrost. AddressUtxo -> (TxIn , TxOut CtxUTxO )
117
- toEntry utxo = (toCardanoTxIn utxo, toCardanoTxOut utxo addr)
146
+ toEntry utxo = (toCardanoTxIn ( Blockfrost. _addressUtxoTxHash utxo) ( Blockfrost. _addressUtxoOutputIndex utxo) , toCardanoTxOut utxo addr)
118
147
119
- toCardanoTxIn :: Blockfrost. AddressUtxo -> TxIn
120
- toCardanoTxIn Blockfrost. AddressUtxo {_addressUtxoTxHash = Blockfrost. TxHash {unTxHash}, _addressUtxoOutputIndex} =
148
+ toCardanoTxIn :: Blockfrost. TxHash -> Integer -> TxIn
149
+ toCardanoTxIn Blockfrost. TxHash {unTxHash} i =
121
150
case deserialiseFromRawBytesHex AsTxId (encodeUtf8 unTxHash) of
122
151
Left err -> error (show err)
123
- Right txid -> TxIn txid (TxIx (fromIntegral _addressUtxoOutputIndex ))
152
+ Right txid -> TxIn txid (TxIx (fromIntegral i ))
124
153
125
154
-- REVIEW! TxOutDatumNone and ReferenceScriptNone
126
155
toCardanoTxOut :: Blockfrost. AddressUtxo -> AddressInEra -> TxOut CtxUTxO
@@ -361,6 +390,56 @@ mkEraHistory = do
361
390
-- Wallet API --
362
391
----------------
363
392
393
+ -- | Query the Blockfrost API to get the 'UTxO' for 'TxIn' and convert to cardano 'UTxO'.
394
+ queryUTxOByTxIn :: NetworkId -> TxIn -> BlockfrostClientT IO UTxO
395
+ queryUTxOByTxIn networkId txIn = do
396
+ bfUTxO <- Blockfrost. getTxUtxos (Blockfrost. TxHash $ hashToTextAsHex txHash)
397
+ fromBFUtxo bfUTxO
398
+ where
399
+ fromBFUtxo Blockfrost. TransactionUtxos {_transactionUtxosOutputs} = do
400
+ utxoList <- mapM toCardanoUTxO' _transactionUtxosOutputs
401
+ pure $ UTxO. squash utxoList
402
+
403
+ toCardanoUTxO' output@ Blockfrost. UtxoOutput {_utxoOutputReferenceScriptHash} = do
404
+ case _utxoOutputReferenceScriptHash of
405
+ -- NOTE: We don't care about outputs without reference scripts
406
+ Nothing -> pure mempty
407
+ Just scriptHash -> do
408
+ Blockfrost. ScriptCBOR {_scriptCborCbor} <- Blockfrost. getScriptCBOR scriptHash
409
+ case _scriptCborCbor of
410
+ Nothing -> liftIO $ throwIO $ BlockfrostError " Failed to get script CBOR."
411
+ Just fullScriptCBOR -> do
412
+ case decodeBase16 fullScriptCBOR of
413
+ Left decodeErr -> liftIO $ throwIO . DecodeError $ " Bad Base16 PlutusScript CBOR: " <> decodeErr
414
+ Right bytes ->
415
+ case deserialiseFromCBOR (proxyToAsType (Proxy @ PlutusScript )) bytes of
416
+ Left err -> liftIO $ throwIO $ BlockfrostError $ " Failed to decode script: " <> T. pack (show err)
417
+ Right plutusScript -> do
418
+ let o = toCardanoTxOut' output plutusScript
419
+ pure $ UTxO. singleton (txIn, o)
420
+
421
+ toCardanoTxOut' Blockfrost. UtxoOutput {_utxoOutputAddress, _utxoOutputAmount, _utxoOutputDataHash, _utxoOutputInlineDatum, _utxoOutputReferenceScriptHash} plutusScript =
422
+ let datum =
423
+ case _utxoOutputInlineDatum of
424
+ Nothing ->
425
+ case _utxoOutputDataHash of
426
+ Nothing -> TxOutDatumNone
427
+ Just datumHash -> TxOutDatumHash (fromString $ T. unpack $ Blockfrost. unDatumHash datumHash)
428
+ Just (Blockfrost. InlineDatum (Blockfrost. ScriptDatumCBOR cborDatum)) ->
429
+ case deserialiseFromCBOR (proxyToAsType (Proxy @ HashableScriptData )) (encodeUtf8 cborDatum) of
430
+ Left _ -> TxOutDatumNone
431
+ Right hashableScriptData -> TxOutDatumInline hashableScriptData
432
+ in TxOut (scriptAddr plutusScript) (toCardanoValue _utxoOutputAmount) datum (mkScriptRef plutusScript)
433
+
434
+ scriptAddr script =
435
+ makeShelleyAddressInEra
436
+ shelleyBasedEra
437
+ networkId
438
+ (PaymentCredentialByScript $ hashScript $ PlutusScript script)
439
+ NoStakeAddress
440
+
441
+ TxIn (TxId txHash) _ = txIn
442
+
364
443
-- | Query the Blockfrost API for address UTxO and convert to cardano 'UTxO'.
365
444
queryUTxO :: SigningKey PaymentKey -> NetworkId -> BlockfrostClientT IO UTxO
366
445
queryUTxO sk networkId = do
0 commit comments