@@ -14,6 +14,7 @@ import Data.Time.Clock.POSIX
1414import Hydra.Cardano.Api hiding (LedgerState , fromNetworkMagic )
1515
1616import Cardano.Api.UTxO qualified as UTxO
17+ import Cardano.Crypto.Hash (hashToTextAsHex )
1718import Cardano.Ledger.Api.PParams
1819import Cardano.Ledger.BaseTypes (EpochInterval (.. ), EpochSize (.. ), NonNegativeInterval , UnitInterval , boundRational , unsafeNonZero )
1920import Cardano.Ledger.Binary.Version (mkVersion )
@@ -42,7 +43,7 @@ import Data.Text qualified as T
4243import Hydra.Cardano.Api.Prelude (StakePoolKey , fromNetworkMagic )
4344import Hydra.Chain.CardanoClient (QueryPoint (.. ))
4445import Hydra.Chain.ScriptRegistry (buildScriptPublishingTxs )
45- import Hydra.Tx (txId )
46+ import Hydra.Tx (ScriptRegistry , newScriptRegistry , txId )
4647import Money qualified
4748import Ouroboros.Consensus.Block (GenesisWindow (.. ))
4849import Ouroboros.Consensus.HardFork.History (Bound (.. ), EraEnd (.. ), EraParams (.. ), EraSummary (.. ), SafeZone (.. ), Summary (.. ), mkInterpreter )
@@ -63,6 +64,34 @@ runBlockfrostM prj action = do
6364 Left err -> throwIO (BlockfrostError $ show err)
6465 Right val -> pure val
6566
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+
6695publishHydraScripts ::
6796 -- | The path where the Blockfrost project token hash is stored.
6897 FilePath ->
@@ -361,6 +390,56 @@ mkEraHistory = do
361390-- Wallet API --
362391----------------
363392
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+
364443-- | Query the Blockfrost API for address UTxO and convert to cardano 'UTxO'.
365444queryUTxO :: SigningKey PaymentKey -> NetworkId -> BlockfrostClientT IO UTxO
366445queryUTxO sk networkId = do
0 commit comments