diff --git a/cardano-api/src/Cardano/Api.hs b/cardano-api/src/Cardano/Api.hs index 99a04d76fee..9d17fda9504 100644 --- a/cardano-api/src/Cardano/Api.hs +++ b/cardano-api/src/Cardano/Api.hs @@ -591,6 +591,8 @@ module Cardano.Api ( MempoolSizeAndCapacity(..), queryTxMonitoringLocal, + TxIdInMode(..), + EraHistory(..), getProgress, @@ -681,6 +683,7 @@ import Cardano.Api.Fees import Cardano.Api.GenesisParameters import Cardano.Api.Hash import Cardano.Api.HasTypeProxy +import Cardano.Api.InMode import Cardano.Api.IPC import Cardano.Api.IPC.Monad import Cardano.Api.Key diff --git a/cardano-api/src/Cardano/Api/IPC.hs b/cardano-api/src/Cardano/Api/IPC.hs index 92a3996e2c2..e3a76b61481 100644 --- a/cardano-api/src/Cardano/Api/IPC.hs +++ b/cardano-api/src/Cardano/Api/IPC.hs @@ -83,6 +83,7 @@ import Prelude import Data.Void (Void) +import Data.Aeson (ToJSON, (.=), object, toJSON) import qualified Data.ByteString.Lazy as LBS import qualified Data.Map.Strict as Map @@ -131,6 +132,7 @@ import Cardano.Api.Modes import Cardano.Api.NetworkId import Cardano.Api.Protocol.Types import Cardano.Api.Query +import Cardano.Api.Tx (getTxBody) import Cardano.Api.TxBody -- ---------------------------------------------------------------------------- @@ -650,6 +652,35 @@ data LocalTxMonitoringResult mode Consensus.MempoolSizeAndCapacity SlotNo -- ^ Slot number at which the mempool snapshot was taken +instance ToJSON (LocalTxMonitoringResult mode) where + toJSON result = + object $ case result of + LocalTxMonitoringTxExists tx slot -> + [ "exists" .= True + , "txId" .= tx + , "slot" .= slot + ] + LocalTxMonitoringTxDoesNotExist tx slot -> + [ "exists" .= False + , "txId" .= tx + , "slot" .= slot + ] + LocalTxMonitoringNextTx txInMode slot -> + [ "nextTx" .= txId + , "slot" .= slot + ] + where + txId = case txInMode of + Just (TxInMode tx _) -> Just $ getTxId $ getTxBody tx + -- TODO: support fetching the ID of a Byron Era transaction + _ -> Nothing + LocalTxMonitoringMempoolSizeAndCapacity mempool slot -> + [ "capacityInBytes" .= Consensus.capacityInBytes mempool + , "sizeInBytes" .= Consensus.sizeInBytes mempool + , "numberOfTxs" .= Consensus.numberOfTxs mempool + , "slot" .= slot + ] + data LocalTxMonitoringQuery mode -- | Query if a particular tx exists in the mempool. Note that, the absence -- of a transaction does not imply anything about how the transaction was diff --git a/cardano-cli/ChangeLog.md b/cardano-cli/ChangeLog.md index 4ae466d63f0..9982ca1bdad 100644 --- a/cardano-cli/ChangeLog.md +++ b/cardano-cli/ChangeLog.md @@ -2,6 +2,10 @@ ## vNext +### Features + +- Add `query tx-mempool` ([PR 4276](https://github.com/input-output-hk/cardano-node/pull/4276)) + ### Bugs - Allow reading signing keys from a pipe ([PR 4342](https://github.com/input-output-hk/cardano-node/pull/4342)) diff --git a/cardano-cli/src/Cardano/CLI/Shelley/Commands.hs b/cardano-cli/src/Cardano/CLI/Shelley/Commands.hs index cf6c5f2e350..e021d7b8bb4 100644 --- a/cardano-cli/src/Cardano/CLI/Shelley/Commands.hs +++ b/cardano-cli/src/Cardano/CLI/Shelley/Commands.hs @@ -373,6 +373,7 @@ data QueryCmd = -- ^ Node operational certificate (Maybe OutputFile) | QueryPoolState' AnyConsensusModeParams NetworkId [Hash StakePoolKey] + | QueryTxMempool AnyConsensusModeParams NetworkId TxMempoolQuery (Maybe OutputFile) deriving Show renderQueryCmd :: QueryCmd -> Text @@ -390,6 +391,14 @@ renderQueryCmd cmd = QueryStakeSnapshot' {} -> "query stake-snapshot" QueryKesPeriodInfo {} -> "query kes-period-info" QueryPoolState' {} -> "query pool-state" + QueryTxMempool _ _ query _ -> "query tx-mempool" <> renderTxMempoolQuery query + where + renderTxMempoolQuery query = + case query of + TxMempoolQueryTxExists tx -> "tx-exists " <> serialiseToRawBytesHexText tx + TxMempoolQueryNextTx -> "next-tx" + TxMempoolQueryInfo -> "info" + data GovernanceCmd = GovernanceMIRPayStakeAddressesCertificate diff --git a/cardano-cli/src/Cardano/CLI/Shelley/Parsers.hs b/cardano-cli/src/Cardano/CLI/Shelley/Parsers.hs index 88af07fffa2..0d77e54c2f5 100644 --- a/cardano-cli/src/Cardano/CLI/Shelley/Parsers.hs +++ b/cardano-cli/src/Cardano/CLI/Shelley/Parsers.hs @@ -941,6 +941,8 @@ pQueryCmd = (Opt.info pKesPeriodInfo $ Opt.progDesc "Get information about the current KES period and your node's operational certificate.") , subParser "pool-state" (Opt.info pQueryPoolState $ Opt.progDesc "Dump the pool state") + , subParser "tx-mempool" + (Opt.info pQueryTxMempool $ Opt.progDesc "Local Mempool info") ] where pQueryProtocolParameters :: Parser QueryCmd @@ -1010,6 +1012,25 @@ pQueryCmd = <*> pNetworkId <*> many pStakePoolVerificationKeyHash + pQueryTxMempool :: Parser QueryCmd + pQueryTxMempool = QueryTxMempool + <$> pConsensusModeParams + <*> pNetworkId + <*> pTxMempoolQuery + <*> pMaybeOutputFile + where + pTxMempoolQuery :: Parser TxMempoolQuery + pTxMempoolQuery = asum + [ subParser "info" + (Opt.info (pure TxMempoolQueryInfo) $ + Opt.progDesc "Ask the node about the current mempool's capacity and sizes") + , subParser "next-tx" + (Opt.info (pure TxMempoolQueryNextTx) $ + Opt.progDesc "Requests the next transaction from the mempool's current list") + , subParser "tx-exists" + (Opt.info (TxMempoolQueryTxExists <$> argument Opt.str (metavar "TX_ID")) $ + Opt.progDesc "Query if a particular transaction exists in the mempool") + ] pLeadershipSchedule :: Parser QueryCmd pLeadershipSchedule = QueryLeadershipSchedule <$> pConsensusModeParams diff --git a/cardano-cli/src/Cardano/CLI/Shelley/Run/Query.hs b/cardano-cli/src/Cardano/CLI/Shelley/Run/Query.hs index 3ff92eef2c3..28266142bad 100644 --- a/cardano-cli/src/Cardano/CLI/Shelley/Run/Query.hs +++ b/cardano-cli/src/Cardano/CLI/Shelley/Run/Query.hs @@ -199,6 +199,8 @@ runQueryCmd cmd = runQueryKesPeriodInfo consensusModeParams network nodeOpCert mOutFile QueryPoolState' consensusModeParams network poolid -> runQueryPoolState consensusModeParams network poolid + QueryTxMempool consensusModeParams network op mOutFile -> + runQueryTxMempool consensusModeParams network op mOutFile runQueryProtocolParameters :: AnyConsensusModeParams @@ -620,6 +622,34 @@ runQueryPoolState (AnyConsensusModeParams cModeParams) network poolIds = do result <- executeQuery era cModeParams localNodeConnInfo qInMode obtainLedgerEraClassConstraints sbe writePoolState result +-- | Query the local mempool state +runQueryTxMempool + :: AnyConsensusModeParams + -> NetworkId + -> TxMempoolQuery + -> Maybe OutputFile + -> ExceptT ShelleyQueryCmdError IO () +runQueryTxMempool (AnyConsensusModeParams cModeParams) network query mOutFile = do + SocketPath sockPath <- firstExceptT ShelleyQueryCmdEnvVarSocketErr readEnvSocketPath + let localNodeConnInfo = LocalNodeConnectInfo cModeParams network sockPath + + localQuery <- case query of + TxMempoolQueryTxExists tx -> do + anyE@(AnyCardanoEra era) <- determineEra cModeParams localNodeConnInfo + let cMode = consensusModeOnly cModeParams + eInMode <- toEraInMode era cMode + & hoistMaybe (ShelleyQueryCmdEraConsensusModeMismatch (AnyConsensusMode cMode) anyE) + pure $ LocalTxMonitoringQueryTx $ TxIdInMode tx eInMode + TxMempoolQueryNextTx -> pure LocalTxMonitoringSendNextTx + TxMempoolQueryInfo -> pure LocalTxMonitoringMempoolInformation + + result <- liftIO $ queryTxMonitoringLocal localNodeConnInfo localQuery + let renderedResult = encodePretty result + case mOutFile of + Nothing -> liftIO $ LBS.putStrLn renderedResult + Just (OutputFile oFp) -> handleIOExceptT (ShelleyQueryCmdWriteFileError . FileIOError oFp) + $ LBS.writeFile oFp renderedResult + -- | Obtain stake snapshot information for a pool, plus information about the total active stake. -- This information can be used for leader slot calculation, for example, and has been requested by SPOs. diff --git a/cardano-cli/src/Cardano/CLI/Types.hs b/cardano-cli/src/Cardano/CLI/Types.hs index 1ef07fea844..65724d4aab5 100644 --- a/cardano-cli/src/Cardano/CLI/Types.hs +++ b/cardano-cli/src/Cardano/CLI/Types.hs @@ -36,6 +36,7 @@ module Cardano.CLI.Types , TxOutChangeAddress (..) , TxOutDatumAnyEra (..) , TxFile (..) + , TxMempoolQuery (..) , UpdateProposalFile (..) , VerificationKeyFile (..) , Stakes (..) @@ -53,8 +54,8 @@ import Data.Word (Word64) import qualified Cardano.Chain.Slotting as Byron import Cardano.Api (AddressAny, AnyScriptLanguage, EpochNo, ExecutionUnits, Hash, - InAnyCardanoEra, PaymentKey, PolicyId, ScriptData, SlotNo (SlotNo), Tx, TxIn, - Value, WitCtxMint, WitCtxStake, WitCtxTxIn) + InAnyCardanoEra, PaymentKey, PolicyId, ScriptData, SlotNo (SlotNo), Tx, TxId, + TxIn, Value, WitCtxMint, WitCtxStake, WitCtxTxIn) import qualified Cardano.Ledger.Crypto as Crypto @@ -395,4 +396,8 @@ newtype TxFile = TxFile FilePath deriving Show - +data TxMempoolQuery = + TxMempoolQueryTxExists TxId + | TxMempoolQueryNextTx + | TxMempoolQueryInfo + deriving Show diff --git a/doc/reference/cardano-node-cli-reference.md b/doc/reference/cardano-node-cli-reference.md index 8f389d6a3c4..64c2d5adcbb 100644 --- a/doc/reference/cardano-node-cli-reference.md +++ b/doc/reference/cardano-node-cli-reference.md @@ -78,6 +78,9 @@ The `query` command contains the following subcommands: * `pool-params` (advanced): gets the current and future parameters for a stake pool * `leadership-schedule`: gets the slots in which the node is slot leader for the current or following epoch * `kes-period-info` (advanced): returns diagnostic information about your operational certificate +* `tx-mempool info`: returns details about a node's mempool's resource usage +* `tx-mempool next-tx`: returns the next transaction to be processed +* `tx-mempool tx-exists`: queries whether or not a transaction is in the node's mempool *cardano-cli governance* The `governance` command contains the following subcommands: diff --git a/scripts/babbage/example-babbage-script-usage.sh b/scripts/babbage/example-babbage-script-usage.sh index c012e70d093..067d9f9e6e5 100755 --- a/scripts/babbage/example-babbage-script-usage.sh +++ b/scripts/babbage/example-babbage-script-usage.sh @@ -22,7 +22,7 @@ ls -al "$CARDANO_NODE_SOCKET_PATH" plutusspendingscript="$BASE/scripts/plutus/scripts/v2/required-redeemer.plutus" plutusmintingscript="$BASE/scripts/plutus/scripts/v2/minting-script.plutus" plutusstakescript="scripts/plutus/scripts/v2/stake-script.plutus" -mintpolicyid=$(cardano-cli transaction policyid --script-file $plutusmintingscript) +mintpolicyid=$($CARDANO_CLI transaction policyid --script-file $plutusmintingscript) ## This datum hash is the hash of the untyped 42 scriptdatumhash="9e1199a988ba72ffd6e9c269cadb3b53b5f360ff99f112d9b2ee30c4d74ad88b" datumfilepath="$BASE/scripts/plutus/data/42.datum" diff --git a/scripts/babbage/mkfiles.sh b/scripts/babbage/mkfiles.sh index 2ac44459635..76239c75c1c 100755 --- a/scripts/babbage/mkfiles.sh +++ b/scripts/babbage/mkfiles.sh @@ -31,6 +31,7 @@ case $UNAME in DATE="date";; esac +CARDANO_CLI="${CARDANO_CLI:-cardano-cli}" NETWORK_MAGIC=42 SECURITY_PARAM=10 NUM_SPO_NODES=3 @@ -65,7 +66,7 @@ cat > "${ROOT}/byron.genesis.spec.json" <