Skip to content

Commit

Permalink
Address review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
j-mueller committed Oct 18, 2024
1 parent 55f90b0 commit 30f8b1b
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 61 deletions.
1 change: 1 addition & 0 deletions src/base/convex-base.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ library
Convex.Constants
Convex.MonadLog
Convex.NodeQueries
Convex.NodeQueries.Debug
Convex.NodeParams
Convex.PlutusLedger
Convex.PlutusTx
Expand Down
71 changes: 12 additions & 59 deletions src/base/lib/Convex/NodeQueries.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,7 @@ module Convex.NodeQueries(
queryProtocolParameters,
queryStakePools,
queryStakeAddresses,
queryUTxOFilter,

-- ** Debug queries
-- The queries in this section should only be used in testing or preview
-- environments. They may be unstable or inefficient.
queryUTxOByAddress,
queryUTxOWhole,
waitForTxIn,
waitForTx,
waitForTxInSpend
queryUTxOFilter
) where

import Cardano.Api (AnyCardanoEra,
Expand All @@ -60,11 +51,10 @@ import Cardano.Api (AnyCardanoE
Quantity,
SlotNo,
SystemStart,
Tx, TxIn,
envSecurityParam)
import qualified Cardano.Api as CAPI
import Cardano.Api.Experimental (Era)
import qualified Cardano.Api.Experimental as X
import qualified Cardano.Api.Experimental as C.Experimental
import Cardano.Api.Shelley (PoolId,
StakeAddress,
StakeCredential)
Expand All @@ -74,22 +64,17 @@ import Cardano.Crypto (RequiresNet
import Cardano.Ledger.Core (PParams)
import Cardano.Slotting.Slot (WithOrigin)
import Cardano.Slotting.Time (SlotLength)
import Control.Concurrent (threadDelay)
import Control.Exception (Exception,
throwIO)
import Control.Monad (unless,
when)
import Control.Monad.Except (MonadError,
throwError)
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Trans.Except (runExceptT)
import Convex.Utils (txnUtxos)
import Convex.Utxos (UtxoSet)
import qualified Convex.Utxos as Utxos
import Data.Bifunctor (Bifunctor (..))
import Data.Map (Map)
import Data.Set (Set)
import qualified Data.Set as Set
import Data.SOP.Strict (NP ((:*)))
import Data.Word (Word64)
import qualified Ouroboros.Consensus.Cardano.CanHardFork as Consensus
Expand Down Expand Up @@ -271,8 +256,8 @@ runEraQuery connectInfo EraQuery{eqQuery, eqResult} =
queryInSupportedEra :: LocalNodeConnectInfo -> (forall era. Era era -> EraQuery era result) -> IO result
queryInSupportedEra connectInfo qry = do
queryEra connectInfo >>= \case
CAPI.AnyCardanoEra CAPI.BabbageEra -> runEraQuery connectInfo (qry X.BabbageEra)
CAPI.AnyCardanoEra CAPI.ConwayEra -> runEraQuery connectInfo (qry X.ConwayEra)
CAPI.AnyCardanoEra CAPI.BabbageEra -> runEraQuery connectInfo (qry C.Experimental.BabbageEra)
CAPI.AnyCardanoEra CAPI.ConwayEra -> runEraQuery connectInfo (qry C.Experimental.ConwayEra)
era -> throwIO (QueryEraNotSupported era)

-- | Get the conway protocol parameters from the local cardano node
Expand All @@ -289,61 +274,29 @@ queryStakeAddresses :: LocalNodeConnectInfo -> Set StakeCredential -> IO (Map St
queryStakeAddresses info creds = do
let LocalNodeConnectInfo{localNodeNetworkId} = info
queryInSupportedEra info $ \case
X.BabbageEra -> EraQuery{eqQuery = CAPI.QueryStakeAddresses creds localNodeNetworkId, eqResult = first (fmap CAPI.lovelaceToQuantity)}
X.ConwayEra -> EraQuery{eqQuery = CAPI.QueryStakeAddresses creds localNodeNetworkId, eqResult = first (fmap CAPI.lovelaceToQuantity)}
C.Experimental.BabbageEra -> EraQuery{eqQuery = CAPI.QueryStakeAddresses creds localNodeNetworkId, eqResult = first (fmap CAPI.lovelaceToQuantity)}
C.Experimental.ConwayEra -> EraQuery{eqQuery = CAPI.QueryStakeAddresses creds localNodeNetworkId, eqResult = first (fmap CAPI.lovelaceToQuantity)}

-- | Get the set of registered stake pools
-- Throws 'QueryException' if the node's era is not supported or if the connection
-- to the node cannot be acquired
queryStakePools :: LocalNodeConnectInfo -> IO (Set PoolId)
queryStakePools connectInfo = queryInSupportedEra connectInfo $ \case
X.BabbageEra -> EraQuery{eqQuery = CAPI.QueryStakePools, eqResult = id}
X.ConwayEra -> EraQuery{eqQuery = CAPI.QueryStakePools, eqResult = id}
C.Experimental.BabbageEra -> EraQuery{eqQuery = CAPI.QueryStakePools, eqResult = id}
C.Experimental.ConwayEra -> EraQuery{eqQuery = CAPI.QueryStakePools, eqResult = id}

-- | Get the current epoch
-- Throws 'QueryException' if the node's era is not supported or if the connection
-- to the node cannot be acquired
queryEpoch :: LocalNodeConnectInfo -> IO CAPI.EpochNo
queryEpoch connectInfo = queryInSupportedEra connectInfo $ \case
X.BabbageEra -> EraQuery{eqQuery = CAPI.QueryEpoch, eqResult = id}
X.ConwayEra -> EraQuery{eqQuery = CAPI.QueryEpoch, eqResult = id}
C.Experimental.BabbageEra -> EraQuery{eqQuery = CAPI.QueryEpoch, eqResult = id}
C.Experimental.ConwayEra -> EraQuery{eqQuery = CAPI.QueryEpoch, eqResult = id}

-- | Query UTxO for all given addresses at given point.
-- Throws 'QueryException' if the node's era is not supported or if the connection
-- to the node cannot be acquired
queryUTxOFilter :: LocalNodeConnectInfo -> CAPI.QueryUTxOFilter -> IO (UtxoSet CAPI.CtxUTxO ())
queryUTxOFilter connectInfo flt = queryInSupportedEra connectInfo $ \case
X.BabbageEra -> EraQuery{eqQuery = CAPI.QueryUTxO flt, eqResult = Utxos.fromApiUtxo }
X.ConwayEra -> EraQuery{eqQuery = CAPI.QueryUTxO flt, eqResult = Utxos.fromApiUtxo }

queryUTxOByAddress :: LocalNodeConnectInfo -> [CAPI.AddressAny] -> IO (UtxoSet CAPI.CtxUTxO ())
queryUTxOByAddress connectInfo addresses =
queryUTxOFilter connectInfo $ CAPI.QueryUTxOByAddress $ Set.fromList addresses

queryUTxOWhole :: LocalNodeConnectInfo -> IO (UtxoSet CAPI.CtxUTxO ())
queryUTxOWhole connectInfo = queryUTxOFilter connectInfo CAPI.QueryUTxOWhole

{-| Wait until the output appears on the chain
-}
waitForTxIn :: LocalNodeConnectInfo -> TxIn -> IO ()
waitForTxIn connectInfo txIn = go where
go = do
utxo <- queryUTxOFilter connectInfo (CAPI.QueryUTxOByTxIn (Set.singleton txIn))
when (utxo == mempty) $ do
threadDelay 2_000_000
go

{-| Wait until the first output of the transaction appears on the chain
-}
waitForTx :: forall era. LocalNodeConnectInfo -> Tx era -> IO ()
waitForTx connectInfo tx = waitForTxIn connectInfo (fst $ head $ txnUtxos tx)

{-| Wait until the output disappears from the chain
-}
waitForTxInSpend :: LocalNodeConnectInfo -> TxIn -> IO ()
waitForTxInSpend connectInfo txIn = go where
go = do
utxo <- queryUTxOFilter connectInfo (CAPI.QueryUTxOByTxIn (Set.singleton txIn))
unless (utxo == mempty) $ do
threadDelay 2_000_000
go
C.Experimental.BabbageEra -> EraQuery{eqQuery = CAPI.QueryUTxO flt, eqResult = Utxos.fromApiUtxo }
C.Experimental.ConwayEra -> EraQuery{eqQuery = CAPI.QueryUTxO flt, eqResult = Utxos.fromApiUtxo }
56 changes: 56 additions & 0 deletions src/base/lib/Convex/NodeQueries/Debug.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{-| Node queries for use in testnet environments
-}
module Convex.NodeQueries.Debug(
-- The queries in this module are either inefficient (such as 'queryUTxOByAddress')
-- or brittle (such as 'waitForTxIn')
queryUTxOByAddress,
queryUTxOWhole,
waitForTxIn,
waitForTx,
waitForTxInSpend
) where

import Cardano.Api (LocalNodeConnectInfo, Tx, TxIn)
import qualified Cardano.Api as CAPI
import Control.Concurrent (threadDelay)
import Control.Monad (unless, when)
import Convex.NodeQueries (queryUTxOFilter)
import Convex.Utils (txnUtxos)
import Convex.Utxos (UtxoSet)
import qualified Data.Set as Set

{-| Get the set of UTxOs for a list of addresses
-}
queryUTxOByAddress :: LocalNodeConnectInfo -> [CAPI.AddressAny] -> IO (UtxoSet CAPI.CtxUTxO ())
queryUTxOByAddress connectInfo addresses =
queryUTxOFilter connectInfo $ CAPI.QueryUTxOByAddress $ Set.fromList addresses

{-| Get the entire UTxO set
-}
queryUTxOWhole :: LocalNodeConnectInfo -> IO (UtxoSet CAPI.CtxUTxO ())
queryUTxOWhole connectInfo = queryUTxOFilter connectInfo CAPI.QueryUTxOWhole

{-| Wait until the output appears on the chain
-}
waitForTxIn :: LocalNodeConnectInfo -> TxIn -> IO ()
waitForTxIn connectInfo txIn = go where
go = do
utxo <- queryUTxOFilter connectInfo (CAPI.QueryUTxOByTxIn (Set.singleton txIn))
when (utxo == mempty) $ do
threadDelay 2_000_000
go

{-| Wait until the first output of the transaction appears on the chain
-}
waitForTx :: forall era. LocalNodeConnectInfo -> Tx era -> IO ()
waitForTx connectInfo tx = waitForTxIn connectInfo (fst $ head $ txnUtxos tx)

{-| Wait until the output disappears from the chain
-}
waitForTxInSpend :: LocalNodeConnectInfo -> TxIn -> IO ()
waitForTxInSpend connectInfo txIn = go where
go = do
utxo <- queryUTxOFilter connectInfo (CAPI.QueryUTxOByTxIn (Set.singleton txIn))
unless (utxo == mempty) $ do
threadDelay 2_000_000
go
2 changes: 1 addition & 1 deletion src/devnet/lib/Convex/Devnet/Wallet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import qualified Convex.CoinSelection as CoinSelection
import Convex.Devnet.CardanoNode.Types (RunningNode (..))
import Convex.Devnet.Utils (keysFor)
import Convex.MonadLog (MonadLog (..))
import qualified Convex.NodeQueries as NodeQueries
import qualified Convex.NodeQueries.Debug as NodeQueries
import Convex.Utils (failOnError)
import Convex.Utxos (UtxoSet)
import Convex.Wallet (Wallet (..), address)
Expand Down
2 changes: 1 addition & 1 deletion src/devnet/lib/Convex/Devnet/WalletServer.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import Control.Tracer (Tracer, contramap, traceWith)
import Convex.Devnet.CardanoNode.Types (RunningNode (..))
import Convex.Devnet.Utils (failure, withLogFile)
import qualified Convex.Devnet.Wallet as Wallet
import qualified Convex.NodeQueries as NodeQueries
import qualified Convex.NodeQueries.Debug as NodeQueries
import Convex.Utxos (UtxoSet)
import qualified Convex.Wallet.API as API
import Convex.Wallet.Cli.Command (CliCommand (..))
Expand Down

0 comments on commit 30f8b1b

Please sign in to comment.