From 6eb9ba26877f478c4353a858d3fee2f16606f4c5 Mon Sep 17 00:00:00 2001 From: Marcus Fernandes Date: Wed, 17 Jul 2024 09:35:24 -0300 Subject: [PATCH 1/3] Complete implementation of Blockfrost's `getTxAuxiliaryData` --- src/Internal/Contract/QueryHandle.purs | 13 +----- src/Internal/QueryM/Kupo.purs | 2 +- src/Internal/Service/Blockfrost.purs | 59 +++++++++++++++++++++++--- 3 files changed, 57 insertions(+), 17 deletions(-) diff --git a/src/Internal/Contract/QueryHandle.purs b/src/Internal/Contract/QueryHandle.purs index 360c6bf914..c678c78548 100644 --- a/src/Internal/Contract/QueryHandle.purs +++ b/src/Internal/Contract/QueryHandle.purs @@ -10,7 +10,6 @@ import Cardano.AsCbor (encodeCbor) import Cardano.Types.Transaction (hash) as Transaction import Contract.Log (logDebug') import Control.Monad.Error.Class (throwError) -import Control.Monad.Except (ExceptT(ExceptT), runExceptT) import Ctl.Internal.Contract.LogParams (LogParams) import Ctl.Internal.Contract.QueryBackend (BlockfrostBackend, CtlBackend) import Ctl.Internal.Contract.QueryHandle.Type (QueryHandle) @@ -41,7 +40,7 @@ import Ctl.Internal.Service.Blockfrost import Ctl.Internal.Service.Blockfrost as Blockfrost import Ctl.Internal.Service.Error (ClientError(ClientOtherError)) import Data.Either (Either(Left, Right)) -import Data.Maybe (Maybe(Just, Nothing), fromMaybe, isJust) +import Data.Maybe (fromMaybe, isJust) import Data.Newtype (wrap) import Effect.Aff (Aff) import Effect.Exception (error) @@ -101,15 +100,7 @@ queryHandleForBlockfrostBackend logParams backend = , getOutputAddressesByTxHash: runBlockfrostServiceM' <<< Blockfrost.getOutputAddressesByTxHash , doesTxExist: runBlockfrostServiceM' <<< Blockfrost.doesTxExist - , getTxAuxiliaryData: \txHash -> runExceptT do - -- FIXME: check if Blockfrost also returns full aux data - metadata <- ExceptT $ runBlockfrostServiceM' $ Blockfrost.getTxMetadata - txHash - pure $ wrap - { metadata: Just metadata - , nativeScripts: Nothing - , plutusScripts: Nothing - } + , getTxAuxiliaryData: runBlockfrostServiceM' <<< Blockfrost.getTxAuxiliaryData , utxosAt: runBlockfrostServiceM' <<< Blockfrost.utxosAt , getChainTip: runBlockfrostServiceM' Blockfrost.getChainTip , getCurrentEpoch: diff --git a/src/Internal/QueryM/Kupo.purs b/src/Internal/QueryM/Kupo.purs index 5ae6ef14b6..3a5eb589b0 100644 --- a/src/Internal/QueryM/Kupo.purs +++ b/src/Internal/QueryM/Kupo.purs @@ -457,7 +457,7 @@ unwrapKupoUtxoSlot :: KupoUtxoSlot -> Slot unwrapKupoUtxoSlot (KupoUtxoSlot slot) = slot -------------------------------------------------------------------------------- --- `getTxAuxiliaryData` reponse parsing +-- `getTxAuxiliaryData` response parsing -------------------------------------------------------------------------------- newtype KupoAuxiliaryData = KupoAuxiliaryData (Maybe AuxiliaryData) diff --git a/src/Internal/Service/Blockfrost.purs b/src/Internal/Service/Blockfrost.purs index 1e9708af21..3e31e298f2 100644 --- a/src/Internal/Service/Blockfrost.purs +++ b/src/Internal/Service/Blockfrost.purs @@ -49,6 +49,7 @@ module Ctl.Internal.Service.Blockfrost , getScriptByHash , getScriptInfo , getSystemStart + , getTxAuxiliaryData , getTxMetadata , getUtxoByOref , getValidatorHashDelegationsAndRewards @@ -85,9 +86,10 @@ import Cardano.AsCbor (decodeCbor, encodeCbor) import Cardano.Serialization.Lib (toBytes) import Cardano.Types ( AssetClass(AssetClass) + , AuxiliaryData , DataHash , GeneralTransactionMetadata(GeneralTransactionMetadata) - , Language(PlutusV1, PlutusV2, PlutusV3) + , Language(PlutusV3, PlutusV2, PlutusV1) , PlutusData , PoolPubKeyHash , RawBytes @@ -128,6 +130,7 @@ import Cardano.Types.NativeScript ) import Cardano.Types.NetworkId (NetworkId) import Cardano.Types.OutputDatum (OutputDatum(OutputDatum, OutputDatumHash)) +import Cardano.Types.PlutusScript (PlutusScript) import Cardano.Types.PlutusScript as PlutusScript import Cardano.Types.PoolPubKeyHash as PoolPubKeyHash import Cardano.Types.RedeemerTag (RedeemerTag(Spend, Mint, Cert, Reward)) as RedeemerTag @@ -201,6 +204,7 @@ import Ctl.Internal.Types.ProtocolParameters import Ctl.Internal.Types.Rational (Rational, reduce) import Ctl.Internal.Types.StakeValidatorHash (StakeValidatorHash) import Ctl.Internal.Types.SystemStart (SystemStart(SystemStart)) +import Data.Array (catMaybes) import Data.Array (find, length) as Array import Data.Bifunctor (lmap) import Data.BigNumber (BigNumber, toFraction) @@ -673,9 +677,38 @@ doesTxExist txHash = do Left e -> Left e -------------------------------------------------------------------------------- --- Get transaction metadata --------------------------------------------------------------------------------- +-- Get transaction auxiliary data +getTxAuxiliaryData + :: TransactionHash + -> BlockfrostServiceM (Either GetTxMetadataError AuxiliaryData) +getTxAuxiliaryData txHash = runExceptT do + metadata <- ExceptT $ getTxMetadata txHash + (scriptRefs :: Array ScriptRef) <- ExceptT $ getTxScripts txHash + pure $ wrap + { metadata: Just metadata + , nativeScripts: arrayToMaybe $ getNativeScripts scriptRefs + -- , nativeScripts: Nothing + , plutusScripts: arrayToMaybe $ getPlutusScripts scriptRefs + } + + where + arrayToMaybe :: forall a. Array a -> Maybe (Array a) + arrayToMaybe [] = Nothing + arrayToMaybe xs = Just xs + + getNativeScripts :: Array ScriptRef -> Array NativeScript + getNativeScripts = catMaybes <<< map isNativeScript + where + isNativeScript (NativeScriptRef script) = Just script + isNativeScript (PlutusScriptRef _) = Nothing + getPlutusScripts :: Array ScriptRef -> Array PlutusScript + getPlutusScripts = catMaybes <<< map isPlutusScript + where + isPlutusScript (PlutusScriptRef script) = Just script + isPlutusScript (NativeScriptRef _) = Nothing + +-- TODO: refactor to aux and remove metadat from tests. add aux tests. getTxMetadata :: TransactionHash -> BlockfrostServiceM (Either GetTxMetadataError GeneralTransactionMetadata) @@ -684,13 +717,29 @@ getTxMetadata txHash = do pure case unwrapBlockfrostMetadata <$> handleBlockfrostResponse response of Left (ClientHttpResponseError (Affjax.StatusCode 404) _) -> Left GetTxMetadataTxNotFoundError - Left e -> - Left (GetTxMetadataClientError e) + Left e -> Left (GetTxMetadataClientError e) Right metadata | Map.isEmpty (unwrap metadata) -> Left GetTxMetadataMetadataEmptyOrMissingError | otherwise -> Right metadata +getTxScripts + :: TransactionHash + -> BlockfrostServiceM (Either GetTxMetadataError (Array ScriptRef)) +getTxScripts txHash = runExceptT do + (blockfrostUtxoMap :: BlockfrostUtxosOfTransaction) <- ExceptT $ + blockfrostGetRequest (UtxosOfTransaction txHash) + <#> lmap GetTxMetadataClientError <<< handle404AsMempty <<< + handleBlockfrostResponse + let + (scriptHashes :: Array ScriptHash) = catMaybes + $ map (_.scriptHash <<< unwrap <<< snd) + $ unwrap blockfrostUtxoMap + catMaybes <$> traverse (ExceptT <<< scriptByHash) scriptHashes + + where + scriptByHash t = (lmap GetTxMetadataClientError) <$> getScriptByHash t + -------------------------------------------------------------------------------- -- Get current epoch information -------------------------------------------------------------------------------- From f72387c677351613b2c7ccbb57fd459c1e07bf0d Mon Sep 17 00:00:00 2001 From: Marcus Fernandes Date: Wed, 17 Jul 2024 19:55:10 -0300 Subject: [PATCH 2/3] Implement `getTxMetadata` via `getTxAuxiliaryData` and deprecate it --- src/Internal/Service/Blockfrost.purs | 47 ++++++++++++++++++---------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/Internal/Service/Blockfrost.purs b/src/Internal/Service/Blockfrost.purs index 3e31e298f2..717cb9f151 100644 --- a/src/Internal/Service/Blockfrost.purs +++ b/src/Internal/Service/Blockfrost.purs @@ -240,6 +240,7 @@ import Effect.Exception (error) import Foreign.Object (Object) import Foreign.Object as ForeignObject import JS.BigInt (fromString, toNumber) as BigInt +import Prim.TypeError (class Warn, Text) -------------------------------------------------------------------------------- -- BlockfrostServiceM @@ -682,19 +683,26 @@ getTxAuxiliaryData :: TransactionHash -> BlockfrostServiceM (Either GetTxMetadataError AuxiliaryData) getTxAuxiliaryData txHash = runExceptT do - metadata <- ExceptT $ getTxMetadata txHash - (scriptRefs :: Array ScriptRef) <- ExceptT $ getTxScripts txHash + metadata <- ExceptT $ getMetadata + scriptRefs <- ExceptT $ getTxScripts txHash pure $ wrap { metadata: Just metadata , nativeScripts: arrayToMaybe $ getNativeScripts scriptRefs - -- , nativeScripts: Nothing , plutusScripts: arrayToMaybe $ getPlutusScripts scriptRefs } where - arrayToMaybe :: forall a. Array a -> Maybe (Array a) - arrayToMaybe [] = Nothing - arrayToMaybe xs = Just xs + + getMetadata = do + response <- blockfrostGetRequest (TransactionMetadata txHash) + pure case unwrapBlockfrostMetadata <$> handleBlockfrostResponse response of + Left (ClientHttpResponseError (Affjax.StatusCode 404) _) -> + Left GetTxMetadataTxNotFoundError + Left e -> Left (GetTxMetadataClientError e) + Right metadata + | Map.isEmpty (unwrap metadata) -> + Left GetTxMetadataMetadataEmptyOrMissingError + | otherwise -> Right metadata getNativeScripts :: Array ScriptRef -> Array NativeScript getNativeScripts = catMaybes <<< map isNativeScript @@ -708,20 +716,25 @@ getTxAuxiliaryData txHash = runExceptT do isPlutusScript (PlutusScriptRef script) = Just script isPlutusScript (NativeScriptRef _) = Nothing --- TODO: refactor to aux and remove metadat from tests. add aux tests. + arrayToMaybe :: forall a. Array a -> Maybe (Array a) + arrayToMaybe [] = Nothing + arrayToMaybe xs = Just xs + + getTxMetadata - :: TransactionHash + :: Warn + ( Text + "deprecated: getTxMetadata. use Ctl.Internal.Service.Blockfrost.getTxAuxiliaryData" + ) + => TransactionHash -> BlockfrostServiceM (Either GetTxMetadataError GeneralTransactionMetadata) getTxMetadata txHash = do - response <- blockfrostGetRequest (TransactionMetadata txHash) - pure case unwrapBlockfrostMetadata <$> handleBlockfrostResponse response of - Left (ClientHttpResponseError (Affjax.StatusCode 404) _) -> - Left GetTxMetadataTxNotFoundError - Left e -> Left (GetTxMetadataClientError e) - Right metadata - | Map.isEmpty (unwrap metadata) -> - Left GetTxMetadataMetadataEmptyOrMissingError - | otherwise -> Right metadata + eAuxData <- getTxAuxiliaryData txHash + pure $ case eAuxData of + Left err -> Left err + Right auxiliaryData -> case (unwrap auxiliaryData).metadata of + Nothing -> Left GetTxMetadataMetadataEmptyOrMissingError + Just metadata -> Right metadata getTxScripts :: TransactionHash From 8faceb14333abcb2d7f84913a834e67a783ca6de Mon Sep 17 00:00:00 2001 From: Marcus Fernandes Date: Wed, 17 Jul 2024 20:00:37 -0300 Subject: [PATCH 3/3] Fix formatting --- src/Internal/Service/Blockfrost.purs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Internal/Service/Blockfrost.purs b/src/Internal/Service/Blockfrost.purs index 717cb9f151..e833f083a7 100644 --- a/src/Internal/Service/Blockfrost.purs +++ b/src/Internal/Service/Blockfrost.purs @@ -720,7 +720,6 @@ getTxAuxiliaryData txHash = runExceptT do arrayToMaybe [] = Nothing arrayToMaybe xs = Just xs - getTxMetadata :: Warn ( Text