-
module Marconi.Mamba.Api.UtxoIndexersQuery
+
module Marconi.Mamba.Api.Query.UtxoIndexer
-
, reportQueryCardanoAddresses
-
import Control.Concurrent.Async (forConcurrently)
import Control.Concurrent.STM (atomically)
import Control.Concurrent.STM.TMVar (TMVar, newEmptyTMVar, putTMVar, takeTMVar, tryTakeTMVar)
import Control.Exception (bracket)
import Control.Lens ((^.))
import Control.Monad.STM (STM)
import Data.Functor ((<&>))
import Data.List.NonEmpty qualified as NonEmpty
-
import Data.Text (Text, intercalate, pack, unpack)
+
import Data.Text (Text, unpack)
import Cardano.Api qualified as C
import Marconi.ChainIndex.Indexers.Utxo qualified as Utxo
import Marconi.ChainIndex.Types (TargetAddresses)
import Marconi.Core.Storable qualified as Storable
-
import Marconi.Mamba.Api.Types (HasUtxoIndexerEnv (uiIndexer, uiQaddresses),
-
QueryExceptions (AddressNotInListError, QueryError),
-
UtxoIndexerEnv (UtxoIndexerEnv, _uiIndexer, _uiQaddresses),
-
UtxoIndexerWrapper (UtxoIndexerWrapper, unWrap), UtxoReport (UtxoReport))
+
import Marconi.Mamba.Api.Types (HasIndexerEnv (uiIndexer, uiQaddresses),
+
IndexerEnv (IndexerEnv, _uiIndexer, _uiQaddresses),
+
IndexerWrapper (IndexerWrapper, unWrapUtxoIndexer),
+
QueryExceptions (AddressNotInListError, QueryError), UtxoQueryResult (UtxoQueryResult))
-- | Bootstraps the utxo query environment.
-- The module is responsible for accessing SQLite for quries.
-- The main issue we try to avoid here is mixing inserts and quries in SQLite to avoid locking the database
-
:: TargetAddresses -- ^ user provided target addresses
-
-> IO UtxoIndexerEnv -- ^ returns Query runtime environment
-
bootstrap targetAddresses = do
+
:: TargetAddresses -- ^ user provided target addresses
+
-> IO IndexerEnv -- ^ returns Query runtime environment
+
initializeEnv targetAddresses = do
ix <- atomically (newEmptyTMVar :: STM (TMVar Utxo.UtxoIndexer) )
-
{ _uiIndexer = UtxoIndexerWrapper ix
+
{ _uiIndexer = IndexerWrapper ix
, _uiQaddresses = targetAddresses
-
-- | finds reports for all user-provided addresses.
-
-- TODO consider sqlite streaming, https://hackage.haskell.org/package/sqlite-simple-0.4.18.2/docs/Database-SQLite-Simple.html#g:14
-
:: UtxoIndexerEnv -- ^ Query run time environment
-
-> IO [UtxoReport] -- ^ set of corresponding TxOutRefs
-
findAll env = forConcurrently addresses f
-
addresses = NonEmpty.toList (env ^. uiQaddresses)
-
f :: C.Address C.ShelleyAddr -> IO UtxoReport
-
f addr = (findByCardanoAddress env . C.toAddressAny $ addr) <&> UtxoReport (pack . show $ addr)
-
-- | Query utxos by Cardano Address
-
-- To Cardano error may occur
-
:: UtxoIndexerEnv -- ^ Query run time environment
+
-- | Query utxos by Address
+
-- Address conversion error from Bech32 may occur
+
:: IndexerEnv -- ^ Query run time environment
-> C.AddressAny -- ^ Cardano address to query
-
findByCardanoAddress = withQueryAction
+
findByAddress = withQueryAction
-
-- | Retrieve a Set of TxOutRefs associated with the given Cardano Era address
-
-- We return an empty Set if no address is found
-
:: UtxoIndexerEnv -- ^ Query run time environment
+
-- | Retrieve Utxos associated with the given address
+
-- We return an empty list if no address is found
+
:: IndexerEnv -- ^ Query run time environment
-> Text -- ^ Bech32 Address
-
-> IO (Either QueryExceptions UtxoReport) -- ^ To Plutus address conversion error may occure
-
findByAddress env addressText =
+
-> IO (Either QueryExceptions UtxoQueryResult) -- ^ To Plutus address conversion error may occure
+
findByBech32Address env addressText =
-
f :: Either C.Bech32DecodeError (C.Address C.ShelleyAddr) -> IO (Either QueryExceptions UtxoReport)
+
f :: Either C.Bech32DecodeError (C.Address C.ShelleyAddr) -> IO (Either QueryExceptions UtxoQueryResult)
| address `elem` (env ^. uiQaddresses) = -- allow for targetAddress search only
(pure . C.toAddressAny $ address)
-
>>= findByCardanoAddress env
-
<&> Right . UtxoReport addressText
+
<&> Right . UtxoQueryResult addressText
| otherwise = pure . Left . AddressNotInListError . QueryError $
unpack addressText <> " not in the provided target addresses"
f (Left e) = pure . Left $ QueryError (unpack addressText
-- | Execute the query function
-- We must stop the utxo inserts before doing the query
-
:: UtxoIndexerEnv -- ^ Query run time environment
-
-> C.AddressAny -- ^ Cardano address to query
+
:: IndexerEnv -- ^ Query run time environment
+
-> C.AddressAny -- ^ Cardano address to query
withQueryAction env address =
-
utxoIndexer = unWrap $ env ^. uiIndexer
+
utxoIndexer = unWrapUtxoIndexer $ env ^. uiIndexer
action :: Utxo.UtxoIndexer -> IO [Utxo.UtxoRow]
Utxo.UtxoResult rows <- Storable.query Storable.QEverything indexer (Utxo.UtxoAddress address)
-- | report target addresses
-> IO [C.Address C.ShelleyAddr]
-
reportQueryCardanoAddresses
-
reportQueryCardanoAddresses = intercalate ", " . reportBech32Addresses
reportBech32Addresses env
writeTMVar :: TMVar a -> a -> STM ()
writeTMVar t new = tryTakeTMVar t >> putTMVar t new
-
writeTMVar' :: UtxoIndexerWrapper-> Utxo.UtxoIndexer -> STM ()
-
writeTMVar' (UtxoIndexerWrapper t) = writeTMVar t
+
writeTMVar' :: IndexerWrapper-> Utxo.UtxoIndexer -> STM ()
+
writeTMVar' (IndexerWrapper t) = writeTMVar t